diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index e671bc1649..9921af639c 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2449,10 +2449,6 @@ manipulatedamage DMG_FULL_ATTACKER_HP .endm - .macro dmgtocurrattackerhp - manipulatedamage DMG_CURR_ATTACKER_HP - .endm - .macro jumpifflowerveil jumpInstr:req jumpifnottype BS_TARGET, TYPE_GRASS, 1f jumpifability BS_TARGET_SIDE, ABILITY_FLOWER_VEIL, \jumpInstr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 4acd4a5ffe..c244a50d08 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1812,33 +1812,12 @@ BattleScript_AutotomizeWeightLoss:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectFinalGambit:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - typecalc - clearmoveresultflags MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE - dmgtocurrattackerhp - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - resultmessage - waitmessage B_WAIT_TIME_LONG - setadditionaleffects - tryfaintmon BS_TARGET - jumpifmovehadnoeffect BattleScript_MoveEnd +BattleScript_FinalGambit:: setatkhptozero healthbarupdate BS_ATTACKER datahpupdate BS_ATTACKER tryfaintmon BS_ATTACKER - goto BattleScript_MoveEnd + return BattleScript_TryHitSwitchTarget:: forcerandomswitch BattleScript_HitSwitchTargetForceRandomSwitchFailed diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 75d7495498..8c6d34b0f0 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -788,7 +788,7 @@ extern const u8 BattleScript_TryHitSwitchTarget[]; extern const u8 BattleScript_HitSwitchTargetDynamaxed[]; extern const u8 BattleScript_AbilityPreventsPhasingOutRet[]; extern const u8 BattleScript_PrintMonIsRootedRet[]; -extern const u8 BattleScript_EffectFinalGambit[]; +extern const u8 BattleScript_FinalGambit[]; extern const u8 BattleScript_EffectAutotomize[]; extern const u8 BattleScript_EffectCopycat[]; extern const u8 BattleScript_EffectDefog[]; diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index b892baedad..e09ff706ec 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -213,8 +213,7 @@ enum CmdVarious #define DMG_DOUBLED 2 #define DMG_1_8_TARGET_HP 3 #define DMG_FULL_ATTACKER_HP 4 -#define DMG_CURR_ATTACKER_HP 5 -#define DMG_BIG_ROOT 6 +#define DMG_BIG_ROOT 5 // Cmd_jumpifcantswitch #define SWITCH_IGNORE_ESCAPE_PREVENTION (1 << 7) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 4b24ea76c8..b537211c87 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -656,9 +656,6 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal // If target has less HP than user, Endeavor does no damage median = maximum = minimum = max(0, gBattleMons[damageCalcData->battlerDef].hp - gBattleMons[damageCalcData->battlerAtk].hp); break; - case EFFECT_FINAL_GAMBIT: - median = maximum = minimum = gBattleMons[damageCalcData->battlerAtk].hp; - break; case EFFECT_BEAT_UP: if (B_BEAT_UP >= GEN_5) { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 432eabfedb..b51abc82b2 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -6433,28 +6433,41 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_ABSORB: - if (moveEffect == EFFECT_ABSORB - && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) - && !(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK) - && IsBattlerAlive(gBattlerAttacker) - && IsBattlerTurnDamaged(gBattlerTarget)) + if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE + || !IsBattlerTurnDamaged(gBattlerTarget)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100)); - gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); - gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE; + gBattleScripting.moveendState++; + break; + } + switch (moveEffect) + { + case EFFECT_ABSORB: + if (!(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK) && IsBattlerAlive(gBattlerAttacker)) + { + gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100)); + gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); + gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE; + effect = TRUE; + if (GetBattlerAbility(gBattlerTarget) == ABILITY_LIQUID_OOZE) + { + gBattleStruct->moveDamage[gBattlerAttacker] *= -1; + gHitMarker |= HITMARKER_PASSIVE_DAMAGE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB_OOZE; + BattleScriptCall(BattleScript_EffectAbsorbLiquidOoze); + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB; + BattleScriptCall(BattleScript_EffectAbsorb); + } + } + break; + case EFFECT_FINAL_GAMBIT: + BattleScriptCall(BattleScript_FinalGambit); effect = TRUE; - if (GetBattlerAbility(gBattlerTarget) == ABILITY_LIQUID_OOZE) - { - gBattleStruct->moveDamage[gBattlerAttacker] *= -1; - gHitMarker |= HITMARKER_PASSIVE_DAMAGE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB_OOZE; - BattleScriptCall(BattleScript_EffectAbsorbLiquidOoze); - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB; - BattleScriptCall(BattleScript_EffectAbsorb); - } + break; + default: + break; } gBattleScripting.moveendState++; break; @@ -11845,9 +11858,6 @@ static void Cmd_manipulatedamage(void) case DMG_BIG_ROOT: gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); break; - case DMG_CURR_ATTACKER_HP: - gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerAttacker); - break; } gBattlescriptCurrInstr = cmd->nextInstr; diff --git a/src/battle_util.c b/src/battle_util.c index e2b0eb41e9..d0f5544645 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -9333,6 +9333,9 @@ static inline s32 DoFixedDamageMoveCalc(struct DamageCalculationData *damageCalc case EFFECT_SUPER_FANG: dmg = GetNonDynamaxHP(damageCalcData->battlerDef) / 2; break; + case EFFECT_FINAL_GAMBIT: + dmg = GetNonDynamaxHP(damageCalcData->battlerAtk); + break; default: return INT32_MAX; } diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 06b1fb3fd6..a79eb441c1 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1564,7 +1564,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_FINAL_GAMBIT] = { - .battleScript = BattleScript_EffectFinalGambit, + .battleScript = BattleScript_EffectHit, .battleTvScore = 0, // TODO: Assign points }, diff --git a/test/battle/move_effect/final_gambit.c b/test/battle/move_effect/final_gambit.c index be815abf5a..5eba955b28 100644 --- a/test/battle/move_effect/final_gambit.c +++ b/test/battle/move_effect/final_gambit.c @@ -1,4 +1,74 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Final Gambit (Move Effect) test titles") +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_FINAL_GAMBIT) == EFFECT_FINAL_GAMBIT); +} + +SINGLE_BATTLE_TEST("Final Gambit faints user and target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_FINAL_GAMBIT); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FINAL_GAMBIT, player); + HP_BAR(opponent); + HP_BAR(player); + } THEN { + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_HP), 0); + EXPECT_EQ(GetMonData(&gEnemyParty[0], MON_DATA_HP), 0); + } +} + +SINGLE_BATTLE_TEST("Final Gambit does not faint user if target protects") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PROTECT); MOVE(player, MOVE_FINAL_GAMBIT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FINAL_GAMBIT, player); + } THEN { + EXPECT_NE(GetMonData(&gPlayerParty[0], MON_DATA_HP), 0); + EXPECT_NE(GetMonData(&gEnemyParty[0], MON_DATA_HP), 0); + } +} + +SINGLE_BATTLE_TEST("Final Gambit does not faint user if attacker fails to attack") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_CONFUSE_RAY); MOVE(player, MOVE_FINAL_GAMBIT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FINAL_GAMBIT, player); + } THEN { + EXPECT_NE(GetMonData(&gPlayerParty[0], MON_DATA_HP), 0); + EXPECT_NE(GetMonData(&gEnemyParty[0], MON_DATA_HP), 0); + } +} + +SINGLE_BATTLE_TEST("Final Gambit does not faint user if target is immune") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GASTLY); + } WHEN { + TURN { MOVE(player, MOVE_FINAL_GAMBIT); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FINAL_GAMBIT, player); + } THEN { + EXPECT_NE(GetMonData(&gPlayerParty[0], MON_DATA_HP), 0); + EXPECT_NE(GetMonData(&gEnemyParty[0], MON_DATA_HP), 0); + } +}