From 0343f63edae790d87b513c23ec33b47e834de332 Mon Sep 17 00:00:00 2001 From: Nephrite Date: Wed, 13 Nov 2019 23:03:20 +0000 Subject: [PATCH] Dancer Implemented Dancer and all relevant code for interacting with abilities, certain moves, etc --- data/battle_scripts_1.s | 10 +++- include/battle.h | 4 +- include/battle_scripts.h | 1 + include/battle_util.h | 1 + include/constants/battle_script_commands.h | 7 +-- src/battle_script_commands.c | 58 ++++++++++++++++++---- src/battle_util.c | 34 ++++++++++++- 7 files changed, 98 insertions(+), 17 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index d0756a2d3..7591d81a0 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -5621,7 +5621,7 @@ BattleScript_MoveUsedIsTaunted:: BattleScript_SelectingNotAllowedMoveTauntInPalace:: printstring STRINGID_PKMNCANTUSEMOVETAUNT goto BattleScript_SelectingUnusableMoveInPalace - + BattleScript_SelectingNotAllowedMoveThroatChop:: printselectionstring STRINGID_PKMNCANTUSEMOVETHROATCHOP endselectionscript @@ -6757,6 +6757,14 @@ BattleScript_AbilityStatusEffect:: seteffectsecondary return +BattleScript_DancerActivates:: + call BattleScript_AbilityPopUp + waitmessage 0x20 + setbyte sB_ANIM_TURN, 0x0 + setbyte sB_ANIM_TARGETS_HIT, 0x0 + orword gHitMarker, HITMARKER_x800000 + jumptocalledmove TRUE + BattleScript_SynchronizeActivates:: waitstate call BattleScript_AbilityPopUp diff --git a/include/battle.h b/include/battle.h index ba29c43cb..69edbcf9a 100644 --- a/include/battle.h +++ b/include/battle.h @@ -174,6 +174,8 @@ struct SpecialStatus u8 gemBoost:1; u8 gemParam; u8 damagedMons:4; // Mons that have been damaged directly by using a move, includes substitute. + u8 dancerUsedMove:1; + u8 dancerOriginalTarget:3; s32 dmg; s32 physicalDmg; s32 specialDmg; @@ -594,7 +596,7 @@ struct BattleScripting u8 battleStyle; u8 drawlvlupboxState; u8 learnMoveState; - u8 field_20; + u8 savedBattler; u8 reshowMainState; u8 reshowHelperState; u8 field_23; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index ad219d701..721c49dab 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -326,5 +326,6 @@ extern const u8 BattleScript_FlameOrb[]; extern const u8 BattleScript_MoveEffectIncinerate[]; extern const u8 BattleScript_MoveEffectBugBite[]; extern const u8 BattleScript_IllusionOff[]; +extern const u8 BattleScript_DancerActivates[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index 005097ac3..5d4dff81e 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -21,6 +21,7 @@ #define ABILITYEFFECT_INTIMIDATE2 0xA #define ABILITYEFFECT_TRACE1 0xB #define ABILITYEFFECT_TRACE2 0xC +#define ABILITYEFFECT_MOVE_END_OTHER 0xD #define ABILITYEFFECT_SWITCH_IN_WEATHER 0xFF #define ITEMEFFECT_ON_SWITCH_IN 0x0 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 6f6d4faae..4b94c9033 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -22,7 +22,7 @@ #define sBATTLE_STYLE gBattleScripting + 0x1D #define sLVLBOX_STATE gBattleScripting + 0x1E #define sLEARNMOVE_STATE gBattleScripting + 0x1F -#define sFIELD_20 gBattleScripting + 0x20 +#define sSAVED_BATTLER gBattleScripting + 0x20 #define sRESHOW_MAIN_STATE gBattleScripting + 0x21 #define sRESHOW_HELPER_STATE gBattleScripting + 0x22 #define sFIELD_23 gBattleScripting + 0x23 @@ -188,8 +188,9 @@ #define MOVEEND_MIRROR_MOVE 17 #define MOVEEND_NEXT_TARGET 18 #define MOVEEND_LIFE_ORB 19 -#define MOVEEND_CLEAR_BITS 20 -#define MOVEEND_COUNT 21 +#define MOVEEND_DANCER 20 +#define MOVEEND_CLEAR_BITS 21 +#define MOVEEND_COUNT 22 // stat flags for Cmd_playstatchangeanimation #define BIT_HP 0x1 diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 74877bd93..c5b1479cb 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1032,7 +1032,6 @@ static void Cmd_attackcanceler(void) } gHitMarker |= HITMARKER_OBEYS; - if (NoTargetPresent(gCurrentMove)) { gBattlescriptCurrInstr = BattleScript_ButItFailedAtkStringPpReduce; @@ -4539,8 +4538,6 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_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 @@ -4553,10 +4550,15 @@ static void Cmd_moveend(void) gBattlerTarget = gActiveBattler; gHitMarker &= ~(HITMARKER_SWAP_ATTACKER_TARGET); } - if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) { - gLastPrintedMoves[gBattlerAttacker] = gChosenMove; - gLastUsedMove = gCurrentMove; + gDisableStructs[gBattlerAttacker].usedMoves |= gBitTable[gCurrMovePos]; + gBattleStruct->lastMoveTarget[gBattlerAttacker] = gBattlerTarget; + if (gHitMarker & HITMARKER_ATTACKSTRING_PRINTED) + { + gLastPrintedMoves[gBattlerAttacker] = gChosenMove; + gLastUsedMove = gCurrentMove; + } } if (!(gAbsentBattlerFlags & gBitTable[gBattlerAttacker]) && !(gBattleStruct->field_91 & gBitTable[gBattlerAttacker]) @@ -4564,9 +4566,11 @@ static void Cmd_moveend(void) && gBattleMoves[originallyUsedMove].effect != EFFECT_HEALING_WISH) { if (gHitMarker & HITMARKER_OBEYS) - { - gLastMoves[gBattlerAttacker] = gChosenMove; - gLastResultingMoves[gBattlerAttacker] = gCurrentMove; + { if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + { + gLastMoves[gBattlerAttacker] = gChosenMove; + gLastResultingMoves[gBattlerAttacker] = gCurrentMove; + } } else { @@ -4665,9 +4669,41 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + case MOVEEND_DANCER: // Special case because it's so annoying + if (gBattleMoves[gCurrentMove].flags & FLAG_DANCE) + { + u8 battler, nextDancer = 0; + + if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker] + || (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove + && gProtectStructs[gBattlerAttacker].usesBouncedMove))) + { // Dance move succeeds + // Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move + if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) + { + gBattleScripting.savedBattler = gBattlerTarget | 0x4; + gBattleScripting.savedBattler |= (gBattlerAttacker << 4); + gSpecialStatuses[gBattlerAttacker].dancerUsedMove = 1; + } + for (battler = 0; battler < MAX_BATTLERS_COUNT; battler++) + { + if (GetBattlerAbility(battler) == ABILITY_DANCER && !gSpecialStatuses[battler].dancerUsedMove) + { + if (!nextDancer || (gBattleMons[battler].speed < gBattleMons[nextDancer & 0x3].speed)) + nextDancer = battler | 0x4; + } + } + if (nextDancer && AbilityBattleEffects(ABILITYEFFECT_MOVE_END_OTHER, nextDancer & 0x3, 0, 0, 0)) + effect = TRUE; + } + } + gBattleScripting.atk49_state++; + break; case MOVEEND_CLEAR_BITS: // Clear bits active while using a move for all targets and all hits. if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget) *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3; + if (gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget) + *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].dancerOriginalTarget & 0x3; gProtectStructs[gBattlerAttacker].usesBouncedMove = 0; gBattleStruct->ateBoost[gBattlerAttacker] = 0; gStatuses3[gBattlerAttacker] &= ~(STATUS3_ME_FIRST); @@ -8384,7 +8420,7 @@ static void Cmd_setbide(void) static void Cmd_confuseifrepeatingattackends(void) { - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE)) + if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) && !gSpecialStatuses[gBattlerAttacker].dancerUsedMove) gBattleScripting.moveEffect = (MOVE_EFFECT_THRASH | MOVE_EFFECT_AFFECTS_USER); gBattlescriptCurrInstr++; @@ -11060,7 +11096,7 @@ static void Cmd_pursuitrelated(void) gCurrentMove = MOVE_PURSUIT; gBattlescriptCurrInstr += 5; gBattleScripting.animTurn = 1; - gBattleScripting.field_20 = gBattlerAttacker; + gBattleScripting.savedBattler = gBattlerAttacker; gBattlerAttacker = gActiveBattler; } else diff --git a/src/battle_util.c b/src/battle_util.c index 093288cb5..2999f44bd 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1351,6 +1351,7 @@ enum ENDTURN_WRAP, ENDTURN_UPROAR, ENDTURN_THRASH, + ENDTURN_FLINCH, ENDTURN_DISABLE, ENDTURN_ENCORE, ENDTURN_MAGNET_RISE, @@ -1660,6 +1661,9 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_FLINCH: // reset flinch + gBattleMons[gActiveBattler].status2 &= ~(STATUS2_FLINCHED); + gBattleStruct->turnEffectsTracker++; case ENDTURN_DISABLE: // disable if (gDisableStructs[gActiveBattler].disableTimer != 0) { @@ -2183,7 +2187,6 @@ u8 AtkCanceller_UnableToUseMove(void) case CANCELLER_FLINCH: // flinch if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED) { - gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_FLINCHED); gProtectStructs[gBattlerAttacker].flinchImmobility = 1; CancelMultiTurnMoves(gBattlerAttacker); gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched; @@ -3447,6 +3450,35 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA break; } break; + case ABILITYEFFECT_MOVE_END_OTHER: // Abilities that activate on *another* battler's moveend: Dancer, Soul-Heart, Receiver, Symbiosis + switch (GetBattlerAbility(battler)) + { + case ABILITY_DANCER: + if (IsBattlerAlive(battler) + && (gBattleMoves[gCurrentMove].flags & FLAG_DANCE) + && !gSpecialStatuses[battler].dancerUsedMove + && gBattlerAttacker != battler) + { + // Set bit and save Dancer mon's original target + gSpecialStatuses[battler].dancerUsedMove = 1; + gSpecialStatuses[battler].dancerOriginalTarget = *(gBattleStruct->moveTarget + battler) | 0x4; + gBattleStruct->atkCancellerTracker = 0; + gBattlerAttacker = gBattlerAbility = battler; + gCalledMove = gCurrentMove; + + // Set the target to the original target of the mon that first used a Dance move + gBattlerTarget = gBattleScripting.savedBattler & 0x3; + + // Make sure that the target isn't an ally - if it is, target the original user + if (GetBattlerSide(gBattlerTarget) == GetBattlerSide(gBattlerAttacker)) + gBattlerTarget = (gBattleScripting.savedBattler & 0xF0) >> 4; + gHitMarker &= ~(HITMARKER_ATTACKSTRING_PRINTED); + BattleScriptExecute(BattleScript_DancerActivates); + effect++; + } + break; + } + break; case ABILITYEFFECT_IMMUNITY: // 5 for (battler = 0; battler < gBattlersCount; battler++) {