Removes Resource Flags and moves fields to DisableStruct (#5945)

This commit is contained in:
Alex 2025-01-11 13:39:10 +01:00 committed by GitHub
parent bfa9d905e1
commit 8f34c76395
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 70 additions and 55 deletions

View File

@ -68,20 +68,6 @@
#define BATTLE_BUFFER_LINK_SIZE 0x1000
struct ResourceFlags
{
u32 flags[MAX_BATTLERS_COUNT];
};
#define RESOURCE_FLAG_FLASH_FIRE 0x1
#define RESOURCE_FLAG_ROOST 0x2
#define RESOURCE_FLAG_UNBURDEN 0x4
#define RESOURCE_FLAG_UNUSED 0x8
#define RESOURCE_FLAG_UNUSED_2 0x10
#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20
#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40
#define RESOURCE_FLAG_ICE_FACE 0x80
struct DisableStruct
{
u32 transformedMonPersonality;
@ -118,6 +104,7 @@ struct DisableStruct
u8 laserFocusTimer;
u8 throatChopTimer;
u8 wrapTurns;
u8 syrupBombTimer;
u8 tormentTimer:4; // used for G-Max Meltdown
u8 usedMoves:4;
u8 truantCounter:1;
@ -130,16 +117,23 @@ struct DisableStruct
u8 toxicSpikesDone:1;
u8 stickyWebDone:1;
u8 stealthRockDone:1;
u8 syrupBombTimer;
u8 syrupBombIsShiny:1;
u8 steelSurgeDone:1;
u8 weatherAbilityDone:1;
u8 terrainAbilityDone:1;
u8 syrupBombIsShiny:1;
u8 steelSurgeDone:1;
u8 usedProteanLibero:1;
u8 flashFireBoosted:1;
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
u8 boosterEnergyActivates:1;
u8 roostActive:1;
u8 unbrudenActive:1;
u8 startEmergencyExit:1;
u8 neutralizingGas:1;
u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case
u8 padding:2;
};
// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects
struct ProtectStruct
{
u32 protected:1;
@ -193,9 +187,9 @@ struct ProtectStruct
u32 specialDmg;
u8 physicalBattlerId;
u8 specialBattlerId;
};
// Cleared at the start of HandleAction_ActionFinished
struct SpecialStatus
{
s32 physicalDmg;
@ -416,7 +410,6 @@ struct StatsArray
struct BattleResources
{
struct SecretBase* secretBase;
struct ResourceFlags *flags;
struct BattleScriptsStack* battleScriptsStack;
struct BattleCallbacksStack* battleCallbackStack;
struct StatsArray* beforeLvlUp;

View File

@ -2826,7 +2826,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE
&& HasMoveWithType(battlerAtkPartner, TYPE_FIRE)
&& !(gBattleResources->flags->flags[battlerAtkPartner] & RESOURCE_FLAG_FLASH_FIRE))
&& !gDisableStructs[battlerAtkPartner].flashFireBoosted)
{
RETURN_SCORE_PLUS(WEAK_EFFECT);
}

View File

@ -3049,7 +3049,6 @@ static void BattleStartClearSetData(void)
gLastHitBy[i] = 0xFF;
gLockedMoves[i] = MOVE_NONE;
gLastPrintedMoves[i] = MOVE_NONE;
gBattleResources->flags->flags[i] = 0;
gPalaceSelectionBattleScripts[i] = 0;
gBattleStruct->lastTakenMove[i] = MOVE_NONE;
gBattleStruct->choicedMove[i] = MOVE_NONE;
@ -3263,7 +3262,6 @@ void SwitchInClearSetData(u32 battler)
}
gBattleStruct->choicedMove[battler] = MOVE_NONE;
gBattleResources->flags->flags[battler] = 0;
gCurrentMove = MOVE_NONE;
gBattleStruct->arenaTurnCounter = 0xFF;
@ -3404,8 +3402,6 @@ const u8* FaintClearSetData(u32 battler)
gBattleStruct->lastTakenMoveFrom[i][battler] = 0;
}
gBattleResources->flags->flags[battler] = 0;
gBattleMons[battler].types[0] = gSpeciesInfo[gBattleMons[battler].species].types[0];
gBattleMons[battler].types[1] = gSpeciesInfo[gBattleMons[battler].species].types[1];
gBattleMons[battler].types[2] = TYPE_MYSTERY;
@ -4818,7 +4814,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect)
// various effects
if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND)
speed *= 2;
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_UNBURDEN)
if (gDisableStructs[battler].unbrudenActive)
speed *= 2;
// paralysis drop
@ -5972,11 +5968,11 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost)
u32 teraType;
if (GetActiveGimmick(battler) == GIMMICK_TERA && ((teraType = GetMonData(mon, MON_DATA_TERA_TYPE)) != TYPE_STELLAR))
return teraType;
else if (type1 != TYPE_MYSTERY && !(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST && type1 == TYPE_FLYING))
else if (type1 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type1 == TYPE_FLYING))
return type1;
else if (type2 != TYPE_MYSTERY && !(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST && type2 == TYPE_FLYING))
else if (type2 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type2 == TYPE_FLYING))
return type2;
else if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST)
else if (gDisableStructs[battler].roostActive)
return (B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY);
else if (type3 != TYPE_MYSTERY)
return type3;

View File

@ -2137,7 +2137,7 @@ static void Cmd_adjustdamage(void)
gBattleStruct->moveResultFlags[battlerDef] &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE);
gBattleStruct->moveDamage[battlerDef] = 0;
RecordAbilityBattle(gBattlerTarget, ABILITY_ICE_FACE);
gBattleResources->flags->flags[battlerDef] |= RESOURCE_FLAG_ICE_FACE;
gDisableStructs[battlerDef].iceFaceActivationPrevention = TRUE;
// Form change will be done after attack animation in Cmd_resultmessage.
continue;
}
@ -2807,9 +2807,9 @@ static void Cmd_resultmessage(void)
// TODO: Convert this to a proper FORM_CHANGE type.
// Do Ice Face form change which was set up in Cmd_adjustdamage.
if (gBattleResources->flags->flags[gBattlerTarget] & RESOURCE_FLAG_ICE_FACE)
if (gDisableStructs[gBattlerTarget].iceFaceActivationPrevention)
{
gBattleResources->flags->flags[gBattlerTarget] &= ~(RESOURCE_FLAG_ICE_FACE);
gDisableStructs[gBattlerTarget].iceFaceActivationPrevention = FALSE;
gBattleMons[gBattlerTarget].species = SPECIES_EISCUE_NOICE;
gBattleScripting.battler = gBattlerTarget; // For STRINGID_PKMNTRANSFORMED
BattleScriptPushCursor();
@ -3062,7 +3062,7 @@ static void CheckSetUnburden(u8 battler)
{
if (GetBattlerAbility(battler) == ABILITY_UNBURDEN)
{
gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_UNBURDEN;
gDisableStructs[battler].unbrudenActive = TRUE;
RecordAbilityBattle(battler, ABILITY_UNBURDEN);
}
}
@ -3084,7 +3084,8 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem)
{
RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem));
gBattleMons[battlerStealer].item = gLastUsedItem;
gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN;
gDisableStructs[battlerStealer].unbrudenActive = FALSE;
BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item
MarkBattlerForControllerExec(battlerStealer);
}
@ -5586,7 +5587,7 @@ static void Cmd_setroost(void)
{
CMD_ARGS();
gBattleResources->flags->flags[gBattlerAttacker] |= RESOURCE_FLAG_ROOST;
gDisableStructs[gBattlerAttacker].roostActive = TRUE;
gBattleStruct->roostTypes[gBattlerAttacker][0] = gBattleMons[gBattlerAttacker].types[0];
gBattleStruct->roostTypes[gBattlerAttacker][1] = gBattleMons[gBattlerAttacker].types[1];
@ -6714,7 +6715,7 @@ static void Cmd_moveend(void)
}
else // Eject Pack
{
if (!(gBattleResources->flags->flags[gBattlerTarget] & RESOURCE_FLAG_EMERGENCY_EXIT)
if (!gDisableStructs[gBattlerTarget].startEmergencyExit
&& !(gMovesInfo[gCurrentMove].effect == EFFECT_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker)))
{
effect = TRUE;
@ -6892,12 +6893,12 @@ static void Cmd_moveend(void)
{
if (gBattleStruct->redCardActivates)
{
gBattleResources->flags->flags[i] &= ~RESOURCE_FLAG_EMERGENCY_EXIT;
gDisableStructs[i].startEmergencyExit = FALSE;
continue;
}
if (gBattleResources->flags->flags[i] & RESOURCE_FLAG_EMERGENCY_EXIT)
if (gDisableStructs[i].startEmergencyExit)
{
gBattleResources->flags->flags[i] &= ~RESOURCE_FLAG_EMERGENCY_EXIT;
gDisableStructs[i].startEmergencyExit = FALSE;
gSpecialStatuses[i].emergencyExited = TRUE;
gBattlerTarget = gBattlerAbility = i;
BattleScriptPushCursor();
@ -8610,7 +8611,7 @@ static void BestowItem(u32 battlerAtk, u32 battlerDef)
gBattleMons[battlerDef].item = gLastUsedItem;
BtlController_EmitSetMonData(battlerDef, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[battlerDef].item), &gBattleMons[battlerDef].item);
MarkBattlerForControllerExec(battlerDef);
gBattleResources->flags->flags[battlerDef] &= ~RESOURCE_FLAG_UNBURDEN;
gDisableStructs[battlerDef].unbrudenActive = FALSE;
}
// Called by Cmd_removeitem. itemId represents the item that was removed, not being given.
@ -14665,8 +14666,8 @@ static void Cmd_tryswapitems(void)
}
else if (oldItemAtk == ITEM_NONE && *newItemAtk != ITEM_NONE)
{
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gBattleResources->flags->flags[gBattlerAttacker] & RESOURCE_FLAG_UNBURDEN)
gBattleResources->flags->flags[gBattlerAttacker] &= ~RESOURCE_FLAG_UNBURDEN;
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gDisableStructs[gBattlerAttacker].unbrudenActive)
gDisableStructs[gBattlerAttacker].unbrudenActive = FALSE;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_TAKEN; // nothing -> <- target's item
}

View File

@ -2782,8 +2782,8 @@ u8 DoBattlerEndTurnEffects(void)
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_ROOST: // Return flying type.
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST)
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_ROOST;
if (gDisableStructs[battler].roostActive)
gDisableStructs[battler].roostActive = FALSE;
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_ELECTRIFY:
@ -5590,14 +5590,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
case MOVE_ABSORBED_BY_BOOST_FLASH_FIRE:
gBattleStruct->pledgeMove = FALSE;
if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE))
if (!gDisableStructs[battler].flashFireBoosted)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_BOOST;
if (gProtectStructs[gBattlerAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_FlashFireBoost;
else
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_FLASH_FIRE;
gDisableStructs[battler].flashFireBoosted = TRUE;
}
else
{
@ -5704,7 +5704,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
// Not currently held by Sky Drop
&& !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
{
gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_EMERGENCY_EXIT;
gDisableStructs[battler].startEmergencyExit = TRUE;
effect++;
}
break;
@ -6489,9 +6489,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
// Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gBattleResources->flags->flags[i] & RESOURCE_FLAG_NEUTRALIZING_GAS))
if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !gDisableStructs[i].neutralizingGas)
{
gBattleResources->flags->flags[i] |= RESOURCE_FLAG_NEUTRALIZING_GAS;
gDisableStructs[i].neutralizingGas = TRUE;
gBattlerAbility = i;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
@ -7223,9 +7223,8 @@ static u32 ItemHealHp(u32 battler, u32 itemId, enum ItemEffect caseID, bool32 pe
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ItemHealHP_RemoveItemRet;
}
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_EMERGENCY_EXIT
&& GetNonDynamaxHP(battler) >= GetNonDynamaxMaxHP(battler) / 2)
gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_EMERGENCY_EXIT;
if (gDisableStructs[battler].startEmergencyExit && GetNonDynamaxHP(battler) >= GetNonDynamaxMaxHP(battler) / 2)
gDisableStructs[battler].startEmergencyExit = FALSE;
return ITEM_HP_CHANGE;
}
@ -9768,7 +9767,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5));
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE && gBattleResources->flags->flags[battlerAtk] & RESOURCE_FLAG_FLASH_FIRE)
if (moveType == TYPE_FIRE && gDisableStructs[battlerAtk].flashFireBoosted)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
break;
case ABILITY_SWARM:
@ -12065,7 +12064,7 @@ void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3])
types[2] = gBattleMons[battler].types[2];
// Roost.
if (!isTera && (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST))
if (!isTera && gDisableStructs[battler].roostActive)
{
if (types[0] == TYPE_FLYING && types[1] == TYPE_FLYING)
types[0] = types[1] = B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY;

View File

@ -25,7 +25,6 @@ void AllocateBattleResources(void)
gBattleResources = AllocZeroed(sizeof(*gBattleResources));
gBattleResources->secretBase = AllocZeroed(sizeof(*gBattleResources->secretBase));
gBattleResources->flags = AllocZeroed(sizeof(*gBattleResources->flags));
gBattleResources->battleScriptsStack = AllocZeroed(sizeof(*gBattleResources->battleScriptsStack));
gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack));
gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp));
@ -58,7 +57,6 @@ void FreeBattleResources(void)
FREE_AND_SET_NULL(gBattleStruct);
FREE_AND_SET_NULL(gBattleResources->secretBase);
FREE_AND_SET_NULL(gBattleResources->flags);
FREE_AND_SET_NULL(gBattleResources->battleScriptsStack);
FREE_AND_SET_NULL(gBattleResources->battleCallbackStack);
FREE_AND_SET_NULL(gBattleResources->beforeLvlUp);

View File

@ -0,0 +1,28 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Flash Fire boosts fire type moves by 50% but no subsequent increase is applied")
{
s16 damage[3];
GIVEN {
PLAYER(SPECIES_HEATRAN) { Ability(ABILITY_FLASH_FIRE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_EMBER); MOVE(opponent, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER); MOVE(opponent, MOVE_EMBER); }
TURN { MOVE(player, MOVE_EMBER); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent, captureDamage: &damage[0]);
ABILITY_POPUP(player, ABILITY_FLASH_FIRE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent, captureDamage: &damage[1]);
ABILITY_POPUP(player, ABILITY_FLASH_FIRE);
ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player);
HP_BAR(opponent, captureDamage: &damage[2]);
} THEN {
EXPECT_MUL_EQ(damage[0], UQ_4_12(1.5), damage[1]);
EXPECT_EQ(damage[1], damage[2]);
}
}