Move end clear bits clean up (#8354)

Co-authored-by: PhallenTree <168426989+PhallenTree@users.noreply.github.com>
This commit is contained in:
Alex 2025-11-27 17:42:16 +01:00 committed by GitHub
parent 9fde188033
commit 2d628aca0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 48 additions and 39 deletions

View File

@ -1099,7 +1099,7 @@
.byte 0xca .byte 0xca
.endm .endm
.macro setcharge battler:req .macro unused_0xcb battler:req
.byte 0xcb .byte 0xcb
.byte \battler .byte \battler
.endm .endm

View File

@ -2291,7 +2291,7 @@ BattleScript_TryTailwindAbilitiesLoop_WindRider:
BattleScript_TryTailwindAbilitiesLoop_WindPower: BattleScript_TryTailwindAbilitiesLoop_WindPower:
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
setcharge BS_TARGET setvolatile BS_TARGET, VOLATILE_CHARGE_TIMER, 2
printstring STRINGID_BEINGHITCHARGEDPKMNWITHPOWER printstring STRINGID_BEINGHITCHARGEDPKMNWITHPOWER
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
goto BattleScript_TryTailwindAbilitiesLoop_Increment goto BattleScript_TryTailwindAbilitiesLoop_Increment
@ -4022,7 +4022,7 @@ BattleScript_EffectFollowMe::
BattleScript_EffectCharge:: BattleScript_EffectCharge::
attackcanceler attackcanceler
setcharge BS_ATTACKER setvolatile BS_ATTACKER, VOLATILE_CHARGE_TIMER, 2
attackanimation attackanimation
waitanimation waitanimation
.if B_CHARGE_SPDEF_RAISE >= GEN_5 .if B_CHARGE_SPDEF_RAISE >= GEN_5
@ -5339,7 +5339,7 @@ BattleScript_AngerShellRet:
BattleScript_WindPowerActivates:: BattleScript_WindPowerActivates::
call BattleScript_AbilityPopUp call BattleScript_AbilityPopUp
setcharge BS_TARGET setvolatile BS_TARGET, VOLATILE_CHARGE_TIMER, 1
printstring STRINGID_BEINGHITCHARGEDPKMNWITHPOWER printstring STRINGID_BEINGHITCHARGEDPKMNWITHPOWER
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
return return

View File

@ -102,8 +102,7 @@ struct DisableStruct
u8 battlerWithSureHit; u8 battlerWithSureHit;
u8 isFirstTurn; u8 isFirstTurn;
u8 mimickedMoves:4; u8 mimickedMoves:4;
u8 chargeTimer:4; u8 rechargeTimer:4;
u8 rechargeTimer;
u8 autotomizeCount; u8 autotomizeCount;
u16 slowStartTimer; u16 slowStartTimer;
u16 embargoTimer; u16 embargoTimer;

View File

@ -407,7 +407,6 @@ bool32 IsPursuitTargetSet(void);
void ClearPursuitValuesIfSet(u32 battler); void ClearPursuitValuesIfSet(u32 battler);
void ClearPursuitValues(void); void ClearPursuitValues(void);
bool32 HasWeatherEffect(void); bool32 HasWeatherEffect(void);
bool32 IsAnyTargetAffected(u32 battlerAtk);
bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move); bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 HadMoreThanHalfHpNowDoesnt(u32 battler); bool32 HadMoreThanHalfHpNowDoesnt(u32 battler);
void ChooseStatBoostAnimation(u32 battler); void ChooseStatBoostAnimation(u32 battler);

View File

@ -199,7 +199,7 @@ enum VolatileFlags
F(VOLATILE_LOCK_ON, lockOn, (u32, 2), V_BATON_PASSABLE) \ F(VOLATILE_LOCK_ON, lockOn, (u32, 2), V_BATON_PASSABLE) \
F(VOLATILE_PERISH_SONG, perishSong, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_PERISH_SONG, perishSong, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_MINIMIZE, minimize, (u32, 1)) \ F(VOLATILE_MINIMIZE, minimize, (u32, 1)) \
F(VOLATILE_CHARGE, charge, (u32, 1)) \ F(VOLATILE_CHARGE_TIMER, chargeTimer, (u32, 2)) \
F(VOLATILE_ROOT, root, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_ROOT, root, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_YAWN, yawn, (u32, 2)) \ F(VOLATILE_YAWN, yawn, (u32, 2)) \
F(VOLATILE_IMPRISON, imprison, (u32, 1)) \ F(VOLATILE_IMPRISON, imprison, (u32, 1)) \

View File

@ -1447,7 +1447,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
} }
break; break;
case EFFECT_CHARGE: case EFFECT_CHARGE:
if (gBattleMons[battlerAtk].volatiles.charge) if (gBattleMons[battlerAtk].volatiles.chargeTimer > 0)
ADJUST_SCORE(-20); ADJUST_SCORE(-20);
else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC)) else if (!HasMoveWithType(battlerAtk, TYPE_ELECTRIC))
ADJUST_SCORE(-10); ADJUST_SCORE(-10);

View File

@ -378,7 +378,7 @@ static const struct ListMenuItem sVolatileStatusListItems[] =
{COMPOUND_STRING("Lock On"), VOLATILE_LOCK_ON}, {COMPOUND_STRING("Lock On"), VOLATILE_LOCK_ON},
{COMPOUND_STRING("Perish Song"), VOLATILE_PERISH_SONG}, {COMPOUND_STRING("Perish Song"), VOLATILE_PERISH_SONG},
{COMPOUND_STRING("Minimize"), VOLATILE_MINIMIZE}, {COMPOUND_STRING("Minimize"), VOLATILE_MINIMIZE},
{COMPOUND_STRING("Charge"), VOLATILE_CHARGE}, {COMPOUND_STRING("Charge"), VOLATILE_CHARGE_TIMER},
{COMPOUND_STRING("Root"), VOLATILE_ROOT}, {COMPOUND_STRING("Root"), VOLATILE_ROOT},
{COMPOUND_STRING("Yawn"), VOLATILE_YAWN}, {COMPOUND_STRING("Yawn"), VOLATILE_YAWN},
{COMPOUND_STRING("Imprison"), VOLATILE_IMPRISON}, {COMPOUND_STRING("Imprison"), VOLATILE_IMPRISON},

View File

@ -63,8 +63,8 @@ static bool32 HandleEndTurnVarious(u32 battler)
if (gBattleMons[i].volatiles.lockOn > 0) if (gBattleMons[i].volatiles.lockOn > 0)
gBattleMons[i].volatiles.lockOn--; gBattleMons[i].volatiles.lockOn--;
if (gDisableStructs[i].chargeTimer > 0 && --gDisableStructs[i].chargeTimer == 0) if (B_CHARGE < GEN_9 && gBattleMons[i].volatiles.chargeTimer > 0)
gBattleMons[i].volatiles.charge = FALSE; gBattleMons[i].volatiles.chargeTimer--;
if (gDisableStructs[i].laserFocusTimer > 0 && --gDisableStructs[i].laserFocusTimer == 0) if (gDisableStructs[i].laserFocusTimer > 0 && --gDisableStructs[i].laserFocusTimer == 0)
gBattleMons[i].volatiles.laserFocus = FALSE; gBattleMons[i].volatiles.laserFocus = FALSE;

View File

@ -336,6 +336,8 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
static void ResetValuesForCalledMove(void); static void ResetValuesForCalledMove(void);
static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd); static bool32 TrySymbiosis(u32 battler, u32 itemId, bool32 moveEnd);
static bool32 CanAbilityShieldActivateForBattler(u32 battler); static bool32 CanAbilityShieldActivateForBattler(u32 battler);
static void TryClearChargeVolatile(u32 moveType);
static bool32 IsAnyTargetAffected(void);
static void Cmd_attackcanceler(void); static void Cmd_attackcanceler(void);
static void Cmd_accuracycheck(void); static void Cmd_accuracycheck(void);
@ -540,7 +542,7 @@ static void Cmd_unused_0xC7(void);
static void Cmd_unused_c8(void); static void Cmd_unused_c8(void);
static void Cmd_trymemento(void); static void Cmd_trymemento(void);
static void Cmd_setforcedtarget(void); static void Cmd_setforcedtarget(void);
static void Cmd_setcharge(void); static void Cmd_unused_0xcb(void);
static void Cmd_unused_0xCC(void); static void Cmd_unused_0xCC(void);
static void Cmd_curestatuswithmove(void); static void Cmd_curestatuswithmove(void);
static void Cmd_settorment(void); static void Cmd_settorment(void);
@ -799,7 +801,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_unused_c8, //0xC8 Cmd_unused_c8, //0xC8
Cmd_trymemento, //0xC9 Cmd_trymemento, //0xC9
Cmd_setforcedtarget, //0xCA Cmd_setforcedtarget, //0xCA
Cmd_setcharge, //0xCB Cmd_unused_0xcb, //0xCB
Cmd_unused_0xCC, //0xCC Cmd_unused_0xCC, //0xCC
Cmd_curestatuswithmove, //0xCD Cmd_curestatuswithmove, //0xCD
Cmd_settorment, //0xCE Cmd_settorment, //0xCE
@ -1017,6 +1019,33 @@ bool32 IsMoveNotAllowedInSkyBattles(u32 move)
return (gBattleStruct->isSkyBattle && IsMoveSkyBattleBanned(gCurrentMove)); return (gBattleStruct->isSkyBattle && IsMoveSkyBattleBanned(gCurrentMove));
} }
static void TryClearChargeVolatile(u32 moveType)
{
if (B_CHARGE < GEN_9) // Prior to gen9, charge is cleared during the end turn
return;
if (gBattleMons[gBattlerAttacker].volatiles.chargeTimer == 2) // Has been set this turn by move
gBattleMons[gBattlerAttacker].volatiles.chargeTimer--;
else if (moveType == TYPE_ELECTRIC && gBattleMons[gBattlerAttacker].volatiles.chargeTimer == 1)
gBattleMons[gBattlerAttacker].volatiles.chargeTimer = 0;
}
static bool32 IsAnyTargetAffected(void)
{
if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
return FALSE;
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
if (battler == gBattlerAttacker)
continue;
if (!(gBattleStruct->moveResultFlags[battler] & MOVE_RESULT_NO_EFFECT))
return TRUE;
}
return FALSE;
}
u32 NumAffectedSpreadMoveTargets(void) u32 NumAffectedSpreadMoveTargets(void)
{ {
u32 targetCount = 0; u32 targetCount = 0;
@ -7025,9 +7054,7 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_SAME_MOVE_TURNS: case MOVEEND_SAME_MOVE_TURNS:
if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] if (gCurrentMove != gLastResultingMoves[gBattlerAttacker] || !IsAnyTargetAffected())
|| gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT
|| gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
gBattleStruct->metronomeItemCounter[gBattlerAttacker] = 0; gBattleStruct->metronomeItemCounter[gBattlerAttacker] = 0;
else if (gCurrentMove == gLastResultingMoves[gBattlerAttacker] && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT) else if (gCurrentMove == gLastResultingMoves[gBattlerAttacker] && gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT)
gBattleStruct->metronomeItemCounter[gBattlerAttacker]++; gBattleStruct->metronomeItemCounter[gBattlerAttacker]++;
@ -7049,12 +7076,10 @@ static void Cmd_moveend(void)
&& gBattleMons[gBattlerAttacker].volatiles.lockConfusionTurns != 1) // And won't end this turn && gBattleMons[gBattlerAttacker].volatiles.lockConfusionTurns != 1) // And won't end this turn
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it
TryClearChargeVolatile(moveType);
ValidateSavedBattlerCounts(); ValidateSavedBattlerCounts();
gProtectStructs[gBattlerAttacker].shellTrap = FALSE; gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE; gBattleStruct->battlerState[gBattlerAttacker].ateBoost = FALSE;
gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE;
gSpecialStatuses[gBattlerTarget].berryReduced = FALSE;
gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE;
gBattleScripting.moveEffect = MOVE_EFFECT_NONE; gBattleScripting.moveEffect = MOVE_EFFECT_NONE;
gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->swapDamageCategory = FALSE;
gBattleStruct->categoryOverride = FALSE; gBattleStruct->categoryOverride = FALSE;
@ -7070,8 +7095,6 @@ static void Cmd_moveend(void)
gBattleStruct->pledgeMove = FALSE; gBattleStruct->pledgeMove = FALSE;
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE)
SetActiveGimmick(gBattlerAttacker, GIMMICK_NONE); SetActiveGimmick(gBattlerAttacker, GIMMICK_NONE);
if (B_CHARGE >= GEN_9 && moveType == TYPE_ELECTRIC && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
gBattleMons[gBattlerAttacker].volatiles.charge = FALSE;
if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0) if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0)
gBattleMons[gBattlerAttacker].volatiles.destinyBond--; gBattleMons[gBattlerAttacker].volatiles.destinyBond--;
if (moveEffect == EFFECT_ECHOED_VOICE && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)) if (moveEffect == EFFECT_ECHOED_VOICE && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE))
@ -12591,17 +12614,8 @@ static void Cmd_setforcedtarget(void)
gBattlescriptCurrInstr = cmd->nextInstr; gBattlescriptCurrInstr = cmd->nextInstr;
} }
static void Cmd_setcharge(void) static void Cmd_unused_0xcb(void)
{ {
CMD_ARGS(u8 battler);
u8 battler = GetBattlerForBattleScript(cmd->battler);
gBattleMons[battler].volatiles.charge = TRUE;
if (B_CHARGE < GEN_9)
gDisableStructs[battler].chargeTimer = 2;
else
gDisableStructs[battler].chargeTimer = 0;
gBattlescriptCurrInstr = cmd->nextInstr;
} }
static void Cmd_unused_0xCC(void) static void Cmd_unused_0xCC(void)

View File

@ -603,7 +603,7 @@ void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags, struct DisableStruc
tvPtr->side[atkSide].usedMoveSlot = moveSlot; tvPtr->side[atkSide].usedMoveSlot = moveSlot;
AddMovePoints(PTS_MOVE_EFFECT, moveSlot, move, 0); AddMovePoints(PTS_MOVE_EFFECT, moveSlot, move, 0);
AddPointsBasedOnWeather(weatherFlags, move, moveSlot); AddPointsBasedOnWeather(weatherFlags, move, moveSlot);
if (gBattleMons[gBattlerAttacker].volatiles.charge) if (gBattleMons[gBattlerAttacker].volatiles.chargeTimer > 0)
AddMovePoints(PTS_ELECTRIC, move, moveSlot, 0); AddMovePoints(PTS_ELECTRIC, move, moveSlot, 0);
if (move == MOVE_WISH) if (move == MOVE_WISH)

View File

@ -7137,7 +7137,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
if (gSpecialStatuses[battlerAtk].gemBoost) if (gSpecialStatuses[battlerAtk].gemBoost)
modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(gSpecialStatuses[battlerAtk].gemParam))); modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12(gSpecialStatuses[battlerAtk].gemParam)));
if (gBattleMons[battlerAtk].volatiles.charge && moveType == TYPE_ELECTRIC) if (moveType == TYPE_ELECTRIC && gBattleMons[battlerAtk].volatiles.chargeTimer > 0)
modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); modifier = uq4_12_multiply(modifier, UQ_4_12(2.0));
if (GetMoveEffect(ctx->chosenMove) == EFFECT_ME_FIRST) if (GetMoveEffect(ctx->chosenMove) == EFFECT_ME_FIRST)
modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); modifier = uq4_12_multiply(modifier, UQ_4_12(1.5));

View File

@ -131,7 +131,7 @@ SINGLE_BATTLE_TEST("Charge's effect is removed regardless if the next move is El
} }
} }
SINGLE_BATTLE_TEST("Charge will not expire if it flinches twice in a row") SINGLE_BATTLE_TEST("Charge will expire if user flinches while using an electric move")
{ {
s16 damage[2]; s16 damage[2];
GIVEN { GIVEN {
@ -151,9 +151,6 @@ SINGLE_BATTLE_TEST("Charge will not expire if it flinches twice in a row")
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDERBOLT, player);
HP_BAR(opponent, captureDamage: &damage[1]); HP_BAR(opponent, captureDamage: &damage[1]);
} THEN { } THEN {
if (B_CHARGE < GEN_9) EXPECT_EQ(damage[0], damage[1]);
EXPECT_EQ(damage[0], damage[1]);
else
EXPECT_MUL_EQ(damage[0], Q_4_12(2.0), damage[1]);
} }
} }