ワンクリックで
add-feature
Guide for adding new moves, items, or mechanics to the modular Pokemon Battle system.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Guide for adding new moves, items, or mechanics to the modular Pokemon Battle system.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Guide for maintaining and adding new battle animations, focusing on specific sequence timing (Entry, Hits, Faints) and the data-driven Animation Framework.
Learn how to use the DialogManager system to display text, ask questions, and manage user interactions in the game.
Guide for creating new screens and managing transitions using the ScreenManager framework.
Guidelines for maintaining visual consistency across the UI, based on the Summary Screen reference.
Guide for maintaining the modular structure, script order, and global module patterns.
| name | Add Feature |
| description | Guide for adding new moves, items, or mechanics to the modular Pokemon Battle system. |
A systematic guide to adding new content to the Pokemon Battle Modular system, ensuring all relevant files are updated and the modular structure is respected.
js/data: Definitions (Moves, Items, Constants)js/core: Logic (Battle flow, Mechanics, Effects)js/ui: Visuals (UI, Menus)js/anim: Animation engine, registry, and high-level APIjs/screens: Screen modules (Party, Summary, Selection)js/systems: Audio engine, Logger, StorageMOVE_DEXWhen a Pokémon is generated (Wild, Boss, or Starter), its moves are selected dynamically:
Location: js/data/moves.js
const MOVE_DEX = {
'MOVE NAME': {
isUnique: true,
onHit: async (battle, user, target, weatherMod) => {
// Your custom logic here
// IMPORTANT: Return values matter!
// - return true: Move succeeded
// - return false: Move failed (will show "But it failed!")
// - return 'FAIL': Move failed but already showed message
// - return 'IMMUNE': Target is immune (already showed message)
return true;
}
}
};
'BIND': {
isUnique: true,
onHit: async (battle, user, target, weatherMod) => {
// 1. Deal damage
const moveData = { name: 'BIND', type: 'normal', power: 15, category: 'physical' };
const result = await battle.handleDamageSequence(user, target, moveData, user === battle.p, weatherMod);
// 2. Apply volatile if hit
if (result.success && target.currentHp > 0) {
target.volatiles.trapped = {
turns: Math.floor(Math.random() * 4) + 2,
source: user.name,
moveName: 'BIND'
};
await UI.typeText(`${target.name} was trapped!`);
}
return result.success;
}
}
'LEECH SEED': {
isUnique: true,
onHit: async (battle, user, target) => {
// Check immunity
if (target.types.includes('grass')) {
await UI.typeText("It doesn't affect\n" + target.name + "...");
return 'IMMUNE'; // Prevents duplicate "But it failed!"
}
// Check if already applied
if (target.volatiles.seeded) {
await UI.typeText(`${target.name} is already\nseeded!`);
return 'FAIL'; // Already showed message
}
// Apply volatile
target.volatiles.seeded = { source: user === battle.p ? 'player' : 'enemy' };
await UI.typeText(`${target.name} was seeded!`);
return true;
}
}
'DISABLE': {
isUnique: true,
onHit: async (battle, user, target) => {
// Check if target has used a move (tracked automatically in turn_manager.js)
if (!target.lastMoveUsed || !target.lastMoveUsed.name) {
await UI.typeText("But it failed!");
return 'FAIL';
}
target.volatiles.disabled = {
moveName: target.lastMoveUsed.name,
turns: Math.floor(Math.random() * 4) + 4
};
await UI.typeText(`${target.name}'s ${target.lastMoveUsed.name}\nwas disabled!`);
return true;
}
}
Location: js/core/effects.js → processEndTurnStatus()
// Example: Trapped volatile
if (mon.volatiles.trapped) {
await wait(400);
const trap = mon.volatiles.trapped;
await UI.typeText(`${mon.name} is hurt by\n${trap.moveName}!`);
const dmg = Math.floor(mon.maxHp / 16);
await battle.applyDamage(mon, Math.max(1, dmg), 'normal');
trap.turns--;
if (trap.turns <= 0) {
delete mon.volatiles.trapped;
await UI.typeText(`${mon.name} was freed!`);
}
if (mon.currentHp <= 0) return;
}
Location: js/core/turn_manager.js → processAttack()
// Example: Prevent using disabled move
if (attacker.volatiles.disabled && attacker.volatiles.disabled.moveName === move.name) {
await UI.typeText(`${attacker.name}'s ${move.name}\nis disabled!`);
return;
}
Location: js/anim/anim_registry.js
Register a custom animation for the move using the data-driven AnimFramework. See the Battle Animations & Timing skill for the full reference.
AnimFramework.register('move-name', [
{ type: 'sfx', sound: 'fire' },
{ type: 'spriteMove', target: 'attacker', preset: 'lunge' }, // Attacker lunges
{ type: 'stream', from: 'attacker', to: 'defender', // SVG flame particles
count: 15, interval: 25, spread: 12, travelTime: 350,
size: 6, color: '#ff4500', outline: '#8b0000',
scaleStart: 0.6, scaleEnd: 2.0, svgShape: 'fire'
},
{ type: 'sfx', sound: 'fire' },
{ type: 'parallel', steps: [
{ type: 'screenFx', class: 'fx-fire', duration: 500 },
{ type: 'spriteShake', target: 'defender', duration: 400 },
{ type: 'formation', target: 'defender', pattern: 'fireBlast',
shape: 'fire', particleSize: 8, color: '#ff4500', duration: 500
}
]}
]);
20 step types available:
sfx, cry, wait, callback, parallelscreenFx, flash, tilt, bgColor, invert, wave, cssClassspriteShake, spriteMove (presets: lunge, dodge, jump, recoil, charge, slam, float, shake)stream (supports svgShape), beam, volley, particlesoverlay (SVG shapes: lightning, fire, water, leaf, star, claw, fist, skull, spiral), formation (patterns: fireBlast, cross, ring, xShape), spawnUse 'attacker' and 'defender' as position/element references — the framework resolves player/enemy side automatically.
To play: await AnimFramework.play('move-name', { attacker, defender, isPlayerAttacker });
Location: js/engine/ai.js → AIHeuristics
If you add a move with a unique mechanic (e.g., healing, charging, sleep-dependent, or hazards), you must update the AI heuristics so the enemy understands how and when to use it optimally.
evaluateStatusUtilityevaluateBuffUtilityevaluateAdvancedStrategies (e.g., checking if the player is asleep before using a move).README.md under appropriate sectionLocation: js/data/items.js
const ITEMS = {
'item-key': {
name: 'Item Name',
desc: 'Description',
type: 'heal', // heal, revive, ball, battle
heal: 50, // if type is heal
img: 'url-to-sprite'
}
};
js/screens/party.jsjs/core/capture.jsjs/core/battle.js → performItem()// BAD: Returns false, will show duplicate "But it failed!"
if (target.types.includes('grass')) {
await UI.typeText("It doesn't affect...");
return false; // ❌ Will show "But it failed!" again
}
// GOOD: Returns 'IMMUNE' to prevent duplicate message
if (target.types.includes('grass')) {
await UI.typeText("It doesn't affect...");
return 'IMMUNE'; // ✅ No duplicate message
}
If your volatile status needs to tick/expire, you MUST add logic to processEndTurnStatus() in effects.js.
target.volatiles.X for temporary effectstarget.lastMoveUsed for move history (tracked automatically)battle.weather, battle.terrain for field effects