diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index f6811b9c02..b6d498982d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1644,6 +1644,11 @@ .4byte \ptr .endm + .macro tryinstruct ptr:req + various BS_ATTACKER, VARIOUS_TRY_INSTRUCT + .4byte \ptr + .endm + @ helpful macros .macro setstatchanger stat:req, stages:req, down:req setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 73e772148d..14e0c58f3f 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -348,6 +348,7 @@ gBattleScriptsForMoveEffects:: @ 82D86A8 .4byte BattleScript_EffectMatBlock .4byte BattleScript_EffectStompingTantrum .4byte BattleScript_EffectCoreEnforcer + .4byte BattleScript_EffectInstruct .4byte BattleScript_EffectThroatChop .4byte BattleScript_EffectLaserFocus @@ -787,6 +788,20 @@ BattleScript_EffectCopycat: BattleScript_CopycatFail: ppreduce goto BattleScript_ButItFailed + +BattleScript_EffectInstruct: + attackcanceler + attackstring + ppreduce + pause 0x5 + tryinstruct BattleScript_ButItFailed + attackanimation + waitanimation + printstring STRINGID_USEDINSTRUCTEDMOVE + waitmessage 0x40 + setbyte sB_ANIM_TURN, 0x0 + setbyte sB_ANIM_TARGETS_HIT, 0x0 + jumptocalledmove TRUE BattleScript_EffectAutonomize: setstatchanger STAT_SPEED, 2, FALSE diff --git a/include/battle.h b/include/battle.h index c6cf49fc25..594adb8884 100644 --- a/include/battle.h +++ b/include/battle.h @@ -165,6 +165,7 @@ struct SpecialStatus u8 sturdied:1; u8 stormDrainRedirected:1; u8 switchInAbilityDone:1; + u8 instructedChosenTarget:3; s32 dmg; s32 physicalDmg; s32 specialDmg; @@ -516,6 +517,7 @@ struct BattleStruct u8 ateBerry[2]; // array id determined by side, each party pokemon as bit u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum + u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct u8 debugHoldEffects[MAX_BATTLERS_COUNT]; // These override actual items' hold effects. }; diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 39f11694cb..1af103fc83 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -336,6 +336,7 @@ #define EFFECT_MAT_BLOCK 330 #define EFFECT_STOMPING_TANTRUM 331 #define EFFECT_CORE_ENFORCER 332 +#define EFFECT_INSTRUCT 333 #define EFFECT_THROAT_CHOP 334 #define EFFECT_LASER_FOCUS 335 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 334b4b349f..683f3ea372 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -139,6 +139,7 @@ #define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76 #define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77 #define VARIOUS_JUMP_IF_ROAR_FAILS 78 +#define VARIOUS_TRY_INSTRUCT 79 // atk80, dmg manipulation #define ATK80_DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 3326800c91..ad740bc6d2 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -528,6 +528,7 @@ #define STRINGID_SWEETVEILPROTECTED 524 #define STRINGID_AROMAVEILPROTECTED 525 #define STRINGID_CELEBRATEMESSAGE 526 +#define STRINGID_USEDINSTRUCTEDMOVE 527 #define STRINGID_THROATCHOPENDS 528 #define STRINGID_PKMNCANTUSEMOVETHROATCHOP 529 #define STRINGID_LASERFOCUS 530 diff --git a/src/battle_message.c b/src/battle_message.c index d96488ca96..e633b73317 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -655,6 +655,7 @@ static const u8 sText_FlowerVeilProtected[] = _("{B_DEF_NAME_WITH_PREFIX} surrou static const u8 sText_SweetVeilProtected[] = _("{B_DEF_NAME_WITH_PREFIX} surrounded itself\nwith a veil of sweetness!"); static const u8 sText_AromaVeilProtected[] = _("{B_DEF_NAME_WITH_PREFIX} is protected\nby an aromatic veil!"); static const u8 sText_CelebrateMessage[] = _("Congratulations, {B_PLAYER_NAME}!"); +static const u8 sText_UsedInstructedMove[] = _("{B_ATK_NAME_WITH_PREFIX} used the move\ninstructed by {B_BUFF1}!"); static const u8 sText_LaserFocusMessage[] = _("{B_ATK_NAME_WITH_PREFIX}\nconcentrated intensely!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = @@ -662,6 +663,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_LASERFOCUS - 12] = sText_LaserFocusMessage, [STRINGID_THROATCHOPENDS - 12] = sText_ThroatChopEnds, [STRINGID_PKMNCANTUSEMOVETHROATCHOP - 12] = sText_PkmnCantUseMoveThroatChop, + [STRINGID_USEDINSTRUCTEDMOVE - 12] = sText_UsedInstructedMove, [STRINGID_CELEBRATEMESSAGE - 12] = sText_CelebrateMessage, [STRINGID_AROMAVEILPROTECTED - 12] = sText_AromaVeilProtected, [STRINGID_SWEETVEILPROTECTED - 12] = sText_SweetVeilProtected, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ea3e899206..86ca273e6d 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -738,6 +738,7 @@ static const u16 sProtectSuccessRates[] = {USHRT_MAX, USHRT_MAX / 2, USHRT_MAX / #define METRONOME_FORBIDDEN_END 0xFFFF #define ASSIST_FORBIDDEN_END 0xFFFF #define COPYCAT_FORBIDDEN_END 0xFFFF +#define INSTRUCT_FORBIDDEN_END 0xFFFF static const u16 sMovesForbiddenToCopy[] = { @@ -773,6 +774,33 @@ static const u16 sMovesForbiddenToCopy[] = METRONOME_FORBIDDEN_END }; + +static const u16 sMoveEffectsForbiddenToInstruct[] = +{ + EFFECT_ASSIST, + //EFFECT_BEAK_BLAST, + EFFECT_BIDE, + EFFECT_FOCUS_PUNCH, + //EFFECT_GEOMANCY, + EFFECT_INSTRUCT, + EFFECT_ME_FIRST, + EFFECT_METRONOME, + EFFECT_MIRROR_MOVE, + EFFECT_NATURE_POWER, + EFFECT_PLACEHOLDER, + EFFECT_RECHARGE, + EFFECT_SEMI_INVULNERABLE, + //EFFECT_SHELL_TRAP, + EFFECT_SKETCH, + //EFFECT_SKY_DROP, + EFFECT_SKULL_BASH, + EFFECT_SLEEP_TALK, + EFFECT_SOLARBEAM, + EFFECT_TRANSFORM, + EFFECT_TWO_TURNS_ATTACK, + INSTRUCT_FORBIDDEN_END +}; + static const u16 sNaturePowerMoves[] = { MOVE_STUN_SPORE, @@ -4408,6 +4436,7 @@ static void atk49_moveend(void) break; case ATK49_UPDATE_LAST_MOVES: gDisableStructs[gBattlerAttacker].usedMoves |= gBitTable[gCurrMovePos]; + gBattleStruct->lastMoveTarget[gBattlerAttacker] = gBattlerTarget; if (gMoveResultFlags & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE)) gBattleStruct->lastMoveFailed |= gBitTable[gBattlerAttacker]; else @@ -4517,6 +4546,8 @@ static void atk49_moveend(void) gBattleScripting.atk49_state++; break; case ATK49_CLEAR_BITS: // Clear bits active just while using a move. + if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget) + *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3; gProtectStructs[gBattlerAttacker].usesBouncedMove = 0; gBattleStruct->ateBoost[gBattlerAttacker] = 0; gStatuses3[gBattlerAttacker] &= ~(STATUS3_ME_FIRST); @@ -7118,6 +7149,42 @@ static void atk76_various(void) gBattlescriptCurrInstr += 7; } return; + case VARIOUS_TRY_INSTRUCT: + for (i = 0; sMoveEffectsForbiddenToInstruct[i] != INSTRUCT_FORBIDDEN_END; i++) + { + if (sMoveEffectsForbiddenToInstruct[i] == gBattleMoves[gLastMoves[gBattlerTarget]].effect) + break; + } + if (gLastMoves[gBattlerTarget] == 0 || gLastMoves[gBattlerTarget] == 0xFFFF || sMoveEffectsForbiddenToInstruct[i] != INSTRUCT_FORBIDDEN_END + || gLastMoves[gBattlerTarget] == MOVE_STRUGGLE || gLastMoves[gBattlerTarget] == MOVE_KING_S_SHIELD) + { + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + } + else + { + gSpecialStatuses[gBattlerTarget].instructedChosenTarget = *(gBattleStruct->moveTarget + gBattlerTarget) | 0x4; + gBattlerAttacker = gBattlerTarget; + gCalledMove = gLastMoves[gBattlerAttacker]; + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gBattleMons[gBattlerAttacker].moves[i] == gCalledMove) + { + gCurrMovePos = i; + i = 4; + break; + } + } + if (i != 4 || gBattleMons[gBattlerAttacker].pp[gCurrMovePos] == 0) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); + else + { + gBattlerTarget = gBattleStruct->lastMoveTarget[gBattlerAttacker]; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler]); + gBattlescriptCurrInstr += 7; + } + } + return; case VARIOUS_ABILITY_POPUP: CreateAbilityPopUp(gActiveBattler, gBattleMons[gActiveBattler].ability, (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) != 0); break; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 6277a102ea..85e3cfd068 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -9152,7 +9152,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_INSTRUCT] = { - .effect = EFFECT_PLACEHOLDER, + .effect = EFFECT_INSTRUCT, .power = 0, .type = TYPE_PSYCHIC, .accuracy = 0,