Refactors Final Gambit + Tests (#7005)

This commit is contained in:
Alex 2025-05-31 15:52:53 +02:00 committed by GitHub
parent 7f4f391e9b
commit ede15918cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 112 additions and 58 deletions

View File

@ -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

View File

@ -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

View File

@ -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[];

View File

@ -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)

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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
},

View File

@ -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);
}
}