Move disable struct members to battle mon volatiles (#8540)

This commit is contained in:
Alex 2025-12-16 15:53:35 +01:00 committed by GitHub
parent 3ad72f1263
commit 4ae2f03e02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 594 additions and 570 deletions

View File

@ -656,7 +656,7 @@ BattleScript_SkyDropFlyingType:
waitmessage B_WAIT_TIME_LONG
makevisible BS_ATTACKER
jumpifvolatile BS_TARGET, VOLATILE_CONFUSION, BattleScript_SkyDropFlyingAlreadyConfused
jumpifvolatile BS_TARGET, VOLATILE_LOCK_CONFUSE, BattleScript_SkyDropFlyingConfuseLock
jumpifvolatile BS_TARGET, VOLATILE_RAMPAGE_TURNS, BattleScript_SkyDropFlyingConfuseLock
goto BattleScript_MoveEnd
BattleScript_SkyDropChangedTarget:
pause B_WAIT_TIME_SHORT
@ -669,7 +669,7 @@ BattleScript_SkyDropChangedTarget:
BattleScript_SkyDropFlyingConfuseLock:
seteffectprimary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_CONFUSION
BattleScript_SkyDropFlyingAlreadyConfused:
clearvolatile BS_TARGET, VOLATILE_LOCK_CONFUSE
clearvolatile BS_TARGET, VOLATILE_RAMPAGE_TURNS
jumpifvolatile BS_TARGET, VOLATILE_CONFUSION, BattleScript_MoveEnd
setbyte BS_ATTACKER, BS_TARGET
goto BattleScript_ThrashConfuses

View File

@ -50,7 +50,7 @@
// Used to exclude moves learned temporarily by Transform or Mimic
#define MOVE_IS_PERMANENT(battler, moveSlot) \
(!(gBattleMons[battler].volatiles.transformed) \
&& !(gDisableStructs[battler].mimickedMoves & (1u << moveSlot)))
&& !(gBattleMons[battler].volatiles.mimickedMoves & (1u << moveSlot)))
// Battle Actions
// These determine what each battler will do in a turn
@ -76,71 +76,6 @@
#define BATTLE_BUFFER_LINK_SIZE 0x1000
// Cleared each time a mon leaves the field, either by switching out or fainting
struct DisableStruct
{
u32 transformedMonPersonality;
bool8 transformedMonShininess;
u16 disabledMove;
u16 encoredMove;
u8 protectUses:4;
u8 stockpileCounter:4;
s8 stockpileDef;
s8 stockpileSpDef;
s8 stockpileBeforeDef;
s8 stockpileBeforeSpDef;
u8 substituteHP;
u8 encoredMovePos;
u16 disableTimer;
u16 encoreTimer;
u16 perishSongTimer;
u8 rolloutTimer;
u16 tauntTimer;
u8 furyCutterCounter;
u8 metronomeItemCounter;
u8 battlerPreventingEscape;
u8 battlerWithSureHit;
u8 isFirstTurn;
u8 mimickedMoves:4;
u8 rechargeTimer:4;
u8 autotomizeCount;
u16 slowStartTimer;
u16 embargoTimer;
u16 magnetRiseTimer;
u16 telekinesisTimer;
u16 healBlockTimer;
u16 laserFocusTimer;
u16 throatChopTimer;
u8 wrapTurns;
u16 syrupBombTimer;
u16 tormentTimer; // used for G-Max Meltdown
u8 usedMoves:4;
u8 truantCounter:1;
u8 truantSwitchInHack:1;
u8 tarShot:1;
u8 octolock:1;
u8 cudChew:1;
u8 weatherAbilityDone:1;
u8 terrainAbilityDone:1;
u8 syrupBombIsShiny:1;
u8 usedProteanLibero:1;
u8 flashFireBoosted:1;
u8 boosterEnergyActivated:1;
u8 padding1:1;
u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching)
u8 roostActive:1;
u8 unburdenActive:1;
u8 neutralizingGas:1;
u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case
u8 unnerveActivated:1; // Unnerve and As One (Unnerve part) activate only once per switch in
u8 endured:1;
u8 tryEjectPack:1;
u8 octolockedBy:3;
u8 paradoxBoostedStat:4;
u8 unableToUseMove:1; // for end of turn checks only, for individual actions use the BattleStruct member
u8 padding:1;
};
// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects
struct ProtectStruct
{
@ -591,7 +526,8 @@ struct BattlerState
// End of Word
u16 hpOnSwitchout;
u16 switchIn:1;
u16 padding:15;
u16 isFirstTurn:2;
u16 padding:13;
};
struct PartyState
@ -1080,7 +1016,6 @@ extern u32 gHitMarker;
extern u8 gBideTarget[MAX_BATTLERS_COUNT];
extern u32 gSideStatuses[NUM_BATTLE_SIDES];
extern struct SideTimer gSideTimers[NUM_BATTLE_SIDES];
extern struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT];
extern u16 gPauseCounterBattle;
extern u16 gPaydayMoney;
extern u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT];

View File

@ -42,13 +42,25 @@ struct BattleAnimBackground
const u32 *tilemap;
};
// Helper struct for link battles to show correct animations and transformations that can change their look
// Used by EmitBattleAnimation and EmitMoveAnimation
struct LinkBattleAnim
{
u32 transformedMonPID;
u8 rolloutTimer;
u8 furyCutterCounter;
u8 syrupBombIsShiny:1;
u8 isTransformedMonShiny:1;
u8 padding:4;
};
#define ANIM_ARGS_COUNT 8
extern void (*gAnimScriptCallback)(void);
extern bool8 gAnimScriptActive;
extern u8 gAnimVisualTaskCount;
extern u8 gAnimSoundTaskCount;
extern struct DisableStruct *gAnimDisableStructPtr;
extern struct LinkBattleAnim *gAnimDisableStructPtr;
extern s32 gAnimMoveDmg;
extern u16 gAnimMovePower;
extern u8 gAnimFriendship;

View File

@ -316,7 +316,7 @@ void BtlController_EmitTrainerSlide(u32 battler, u32 bufferId);
void BtlController_EmitTrainerSlideBack(u32 battler, u32 bufferId);
void BtlController_EmitFaintAnimation(u32 battler, u32 bufferId);
void BtlController_EmitBallThrowAnim(u32 battler, u32 bufferId, u8 caseId);
void BtlController_EmitMoveAnimation(u32 battler, u32 bufferId, u16 move, u8 turnOfMove, u16 movePower, s32 dmg, u8 friendship, struct DisableStruct *disableStructPtr, u8 multihit);
void BtlController_EmitMoveAnimation(u32 battler, u32 bufferId, u16 move, u8 turnOfMove, u16 movePower, s32 dmg, u8 friendship, u8 multihit);
void BtlController_EmitPrintString(u32 battler, u32 bufferId, enum StringID stringId);
void BtlController_EmitPrintSelectionString(u32 battler, u32 bufferId, enum StringID stringId);
void BtlController_EmitChooseAction(u32 battler, u32 bufferId, u8 action, u16 itemId);
@ -344,7 +344,7 @@ void BtlController_EmitDrawPartyStatusSummary(u32 battler, u32 bufferId, struct
void BtlController_EmitHidePartyStatusSummary(u32 battler, u32 bufferId);
void BtlController_EmitEndBounceEffect(u32 battler, u32 bufferId);
void BtlController_EmitSpriteInvisibility(u32 battler, u32 bufferId, bool8 isInvisible);
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, struct DisableStruct *disableStructPtr, u16 argument);
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, u16 argument);
void BtlController_EmitLinkStandbyMsg(u32 battler, u32 bufferId, u8 mode, bool32 record);
void BtlController_EmitResetActionMoveSelection(u32 battler, u32 bufferId, u8 caseId);
void BtlController_EmitEndLinkBattle(u32 battler, u32 bufferId, u8 battleOutcome);

View File

@ -2,7 +2,7 @@
#define GUARD_BATTLE_TV_H
void BattleTv_SetDataBasedOnString(enum StringID stringId);
void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags, struct DisableStruct *disableStructPtr);
void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags);
void BattleTv_SetDataBasedOnAnimation(u8 animationId);
void TryPutLinkBattleTvShowOnAir(void);
void BattleTv_ClearExplosionFaintCause(void);

View File

@ -433,7 +433,7 @@ void UpdateStallMons(void);
bool32 TrySwitchInEjectPack(enum EjectPackTiming timing);
bool32 TryEmergencyExit(void);
bool32 EmergencyExitCanBeTriggered(u32 battler);
u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile);
ARM_FUNC u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile);
void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue);
bool32 ItemHealMonVolatile(u32 battler, u16 itemId);
void PushHazardTypeToQueue(u32 side, enum Hazards hazardType);
@ -458,5 +458,6 @@ bool32 IsMimikyuDisguised(u32 battler);
void SetStartingStatus(enum StartingStatus status);
void ResetStartingStatuses(void);
bool32 IsUsableWhileAsleepEffect(enum BattleMoveEffects effect);
void SetWrapTurns(u32 battler, enum HoldEffect holdEffect);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -173,6 +173,25 @@
#define B_DEFIANT_STICKY_WEB GEN_LATEST // In Gen9+, Defiant activates on Sticky Web regardless of who set it up. In Gen8, Defiant does not activate on Sticky Web set up by an ally after Court Change swaps its side.
#define B_POWDER_OVERCOAT GEN_LATEST // In Gen6+, Overcoat blocks powder and spore moves from affecting the user.
// Various volatile timers
#define B_CONFUSION_TURNS 5
#define B_UPROAR_TURN_COUNT 5
#define B_RAMPAGE_TURNS 3
#define B_DISABLE_TIMER 4
#define B_ENCORE_TIMER 4
#define B_PERISH_SONG_TIMER 3
#define B_TAUNT_TIMER 5
#define B_SLOW_START_TIMER 5
#define B_EMBARGO_TIMER 5
#define B_MAGNET_RISE_TIMER 5
#define B_TELEKINESIS_TIMER 3
#define B_HEAL_BLOCK_TIMER 5
#define B_LASER_FOCUS_TIMER 2
#define B_THROAT_CHOP_TIMER 2
#define B_WRAP_TURNS 7 // Max number of turns with Grip Claw
#define B_SYRUP_BOMB_TIMER 3
#define B_TORMENT_TIMER 3
// Item settings
#define B_CONFUSE_BERRIES_HEAL GEN_LATEST // Before Gen7, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP.
#define B_X_ITEMS_BUFF GEN_LATEST // In Gen7+, the X Items raise a stat by 2 stages instead of 1.

View File

@ -162,47 +162,47 @@ enum VolatileFlags
* These are removed after exiting the battle or switching
* Enum, Type Type, max value, flags */
#define VOLATILE_DEFINITIONS(F) \
F(VOLATILE_CONFUSION, confusionTurns, (u32, 6), V_BATON_PASSABLE) \
F(VOLATILE_CONFUSION, confusionTurns, (u32, B_CONFUSION_TURNS + 1), V_BATON_PASSABLE) \
F(VOLATILE_FLINCHED, flinched, (u32, 1)) \
F(VOLATILE_UPROAR, uproarTurns, (u32, 5)) \
F(VOLATILE_TORMENT, torment, (u32, 1)) \
F(VOLATILE_BIDE, bideTurns, (u32, 3)) \
F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 3)) \
F(VOLATILE_RAMPAGE_TURNS, rampageTurns, (u32, B_RAMPAGE_TURNS + 1)) \
F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \
F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \
F(VOLATILE_WRAPPED_BY, wrappedBy, (enum BattlerId, MAX_BITS(4))) \
F(VOLATILE_WRAPPED_MOVE, wrappedMove, (u32, MOVES_COUNT_ALL - 1)) \
F(VOLATILE_WRAPPED_BY, wrappedBy, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
F(VOLATILE_WRAPPED_MOVE, wrappedMove, (u32, MOVES_COUNT_ALL)) \
F(VOLATILE_POWDER, powder, (u32, 1)) \
F(VOLATILE_UNUSED, padding, (u32, 1)) \
F(VOLATILE_INFATUATION, infatuation, (enum BattlerId, MAX_BITS(4))) \
F(VOLATILE_INFATUATION, infatuation, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
F(VOLATILE_DEFENSE_CURL, defenseCurl, (u32, 1)) \
F(VOLATILE_TRANSFORMED, transformed, (u32, 1)) \
F(VOLATILE_RAGE, rage, (u32, 1)) \
F(VOLATILE_SUBSTITUTE, substitute, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 2)) \
F(VOLATILE_DESTINY_BOND, destinyBond, (u32, 3)) \
F(VOLATILE_ESCAPE_PREVENTION, escapePrevention, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_NIGHTMARE, nightmare, (u32, 1)) \
F(VOLATILE_CURSED, cursed, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \
F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_BONUS_CRIT_STAGES, bonusCritStages, (u32, 3)) \
F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, SEMI_INVULNERABLE_COUNT - 1)) \
F(VOLATILE_BONUS_CRIT_STAGES, bonusCritStages, (u32, 4)) \
F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, SEMI_INVULNERABLE_COUNT)) \
F(VOLATILE_ELECTRIFIED, electrified, (u32, 1)) \
F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_INFINITE_CONFUSION, infiniteConfusion, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_SALT_CURE, saltCure, (u32, 1)) \
F(VOLATILE_SYRUP_BOMB, syrupBomb, (u32, 1)) \
F(VOLATILE_STICKY_SYRUPED_BY, stickySyrupedBy, (enum BattlerId, MAX_BITS(4))) \
F(VOLATILE_STICKY_SYRUPED_BY, stickySyrupedBy, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
F(VOLATILE_GLAIVE_RUSH, glaiveRush, (u32, 1)) \
F(VOLATILE_LEECH_SEED, leechSeed, (enum BattlerId, MAX_BITS(4)), V_BATON_PASSABLE) \
F(VOLATILE_LEECH_SEED, leechSeed, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT)), 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_MINIMIZE, minimize, (u32, 1)) \
F(VOLATILE_CHARGE_TIMER, chargeTimer, (u32, 2)) \
F(VOLATILE_CHARGE_TIMER, chargeTimer, (u32, 3)) \
F(VOLATILE_ROOT, root, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_YAWN, yawn, (u32, 2)) \
F(VOLATILE_YAWN, yawn, (u32, 3)) \
F(VOLATILE_IMPRISON, imprison, (u32, 1)) \
F(VOLATILE_GRUDGE, grudge, (u32, 1)) \
F(VOLATILE_GASTRO_ACID, gastroAcid, (u32, 1), V_BATON_PASSABLE) \
@ -219,7 +219,64 @@ enum VolatileFlags
F(VOLATILE_VESSEL_OF_RUIN, vesselOfRuin, (u32, 1)) \
F(VOLATILE_SWORD_OF_RUIN, swordOfRuin, (u32, 1)) \
F(VOLATILE_TABLETS_OF_RUIN, tabletsOfRuin, (u32, 1)) \
F(VOLATILE_BEADS_OF_RUIN, beadsOfRuin, (u32, 1))
F(VOLATILE_BEADS_OF_RUIN, beadsOfRuin, (u32, 1)) \
F(VOLATILE_IS_TRANSFORMED_MON_SHINY, isTransformedMonShiny, (u32, 1)) \
F(VOLATILE_TRANSFORMED_MON_PID, transformedMonPID, (u32, UINT32_MAX)) \
F(VOLATILE_DISABLED_MOVE, disabledMove, (u32, MOVES_COUNT_ALL)) \
F(VOLATILE_ENCORED_MOVE, encoredMove, (u32, MOVES_COUNT_ALL)) \
F(VOLATILE_PROTECT_USES, protectUses, (u32, UINT8_MAX)) \
F(VOLATILE_STOCKPILE_COUNTER, stockpileCounter, (u32, MAX_STAT_STAGE)) \
F(VOLATILE_STOCKPILE_DEF, stockpileDef, (u32, MAX_STAT_STAGE)) \
F(VOLATILE_STOCKPILE_SP_DEF, stockpileSpDef, (u32, MAX_STAT_STAGE)) \
F(VOLATILE_STOCKPILE_BEFORE_DEF, stockpileBeforeDef, (u32, MAX_STAT_STAGE)) \
F(VOLATILE_STOCKPILE_BEFORE_SP_DEF, stockpileBeforeSpDef, (u32, MAX_STAT_STAGE)) \
F(VOLATILE_SUBSTITUTE_HP, substituteHP, (u32, UINT8_MAX)) \
F(VOLATILE_ENCORED_MOVE_POS, encoredMovePos, (u32, MAX_BITS(MAX_MON_MOVES))) \
F(VOLATILE_DISABLE_TIMER, disableTimer, (u32, B_DISABLE_TIMER + 1)) \
F(VOLATILE_ENCORE_TIMER, encoreTimer, (u32, B_ENCORE_TIMER + 1)) \
F(VOLATILE_PERISH_SONG_TIMER, perishSongTimer, (u32, B_PERISH_SONG_TIMER + 1)) \
F(VOLATILE_ROLLOUT_TIMER, rolloutTimer, (u32, UINT8_MAX)) \
F(VOLATILE_FURY_CUTTER_COUNTER, furyCutterCounter, (u32, UINT8_MAX)) \
F(VOLATILE_METRONOME_ITEM_COUNTER, metronomeItemCounter, (u32, UINT8_MAX)) \
F(VOLATILE_BATTLER_PREVENTING_ESCAPE, battlerPreventingEscape, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
F(VOLATILE_BATTLER_WITH_SURE_HIT, battlerWithSureHit, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
F(VOLATILE_MIMICKED_MOVES, mimickedMoves, (u32, MAX_BITS(MAX_MON_MOVES))) \
F(VOLATILE_RECHARGE_TIMER, rechargeTimer, (u32, 3)) \
F(VOLATILE_AUTOTOMIZE_COUNT, autotomizeCount, (u32, UINT8_MAX)) \
F(VOLATILE_SLOW_START_TIMER, slowStartTimer, (u32, B_SLOW_START_TIMER + 1)) \
F(VOLATILE_EMBARGO_TIMER, embargoTimer, (u32, B_EMBARGO_TIMER + 1)) \
F(VOLATILE_MAGNET_RISE_TIMER, magnetRiseTimer, (u32, B_MAGNET_RISE_TIMER + 1)) \
F(VOLATILE_TELEKINESIS_TIMER, telekinesisTimer, (u32, B_TELEKINESIS_TIMER + 1)) \
F(VOLATILE_HEAL_BLOCK_TIMER, healBlockTimer, (u32, B_HEAL_BLOCK_TIMER + 1)) \
F(VOLATILE_TAUNT_TIMER, tauntTimer, (u32, B_TAUNT_TIMER + 1)) \
F(VOLATILE_TORMENT_TIMER, tormentTimer, (u32, B_TORMENT_TIMER + 1)) \
F(VOLATILE_LASER_FOCUS_TIMER, laserFocusTimer, (u32, B_LASER_FOCUS_TIMER + 1)) \
F(VOLATILE_THROAT_CHOP_TIMER, throatChopTimer, (u32, B_THROAT_CHOP_TIMER + 1)) \
F(VOLATILE_WRAP_TURNS, wrapTurns, (u32, B_WRAP_TURNS + 1)) \
F(VOLATILE_SYRUP_BOMB_TIMER, syrupBombTimer, (u32, B_SYRUP_BOMB_TIMER + 1)) \
F(VOLATILE_USED_MOVES, usedMoves, (u32, MAX_BITS(MAX_MON_MOVES))) \
F(VOLATILE_TRUANT_COUNTER, truantCounter, (u32, 1)) \
F(VOLATILE_TRUANT_SWITCH_IN_HACK, truantSwitchInHack, (u32, 1)) \
F(VOLATILE_TAR_SHOT, tarShot, (u32, 1)) \
F(VOLATILE_OCTOLOCK, octolock, (u32, 1)) \
F(VOLATILE_CUD_CHEW, cudChew, (u32, 1)) \
F(VOLATILE_WEATHER_ABILITY_DONE, weatherAbilityDone, (u32, 1)) \
F(VOLATILE_TERRAIN_ABILITY_DONE, terrainAbilityDone, (u32, 1)) \
F(VOLATILE_SYRUP_BOMB_IS_SHINY, syrupBombIsShiny, (u32, 1)) \
F(VOLATILE_USED_PROTEAN_LIBERO, usedProteanLibero, (u32, 1)) \
F(VOLATILE_FLASH_FIRE_BOOSTED, flashFireBoosted, (u32, 1)) \
F(VOLATILE_BOOSTER_ENERGY_ACTIVATED, boosterEnergyActivated, (u32, 1)) \
F(VOLATILE_OVERWRITTEN_ABILITY, overwrittenAbility, (u32, ABILITIES_COUNT)) \
F(VOLATILE_ROOST_ACTIVE, roostActive, (u32, 1)) \
F(VOLATILE_UNBURDEN_ACTIVE, unburdenActive, (u32, 1)) \
F(VOLATILE_NEUTRALIZING_GAS, neutralizingGas, (u32, 1)) \
F(VOLATILE_TRIGGER_ICE_FACE, triggerIceFace, (u32, 1)) \
F(VOLATILE_UNNERVE_ACTIVATED, unnerveActivated, (u32, 1)) \
F(VOLATILE_ENDURED, endured, (u32, 1)) \
F(VOLATILE_TRY_EJECT_PACK, tryEjectPack, (u32, 1)) \
F(VOLATILE_OCTOLOCKED_BY, octolockedBy, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
F(VOLATILE_PARADOX_BOOSTED_STAT, paradoxBoostedStat, (u32, NUM_STATS)) \
F(VOLATILE_UNABLE_TO_USE_MOVE, unableToUseMove, (u32, 1))
/* Use within a macro to get the maximum allowed value for a volatile. Requires _typeMaxValue as input. */

View File

@ -328,27 +328,7 @@ struct Volatiles
// u32 confusionTurns:3;
// u32 flinched:1;
// u32 uproarTurns:3;
// u32 torment:1;
// u32 bideTurns:2;
// u32 lockConfusionTurns:2;
// u32 multipleTurns:1;
// u32 wrapped:1;
// u32 powder:1;
// u32 padding:1;
// u32 infatuation:4; // one bit for each battler
// u32 defenseCurl:1;
// u32 transformed:1;
// u32 recharge:1;
// u32 rage:1;
// u32 substitute:1;
// u32 destinyBond:1;
// u32 escapePrevention:1;
// u32 nightmare:1;
// u32 cursed:1;
// u32 foresight:1;
// u32 dragonCheer:1;
// u32 focusEnergy:1;
// u32 bonusCritStages:3;
// etc.
};
struct BattlePokemon

View File

@ -233,6 +233,7 @@ enum RandomTag
RNG_MAGNITUDE,
RNG_FISHING_BITE,
RNG_FISHING_GEN3_STICKY,
RNG_TAUNT,
};
#define RandomWeighted(tag, ...) \

View File

@ -90,7 +90,7 @@ bool32 ShouldUseItem(u32 battler)
shouldUse = ShouldCureStatusWithItem(battler, battler, gAiLogicData);
break;
case EFFECT_ITEM_INCREASE_STAT:
if (gDisableStructs[battler].isFirstTurn || !AI_OpponentCanFaintAiWithMod(battler, 0))
if (gBattleStruct->battlerState[battler].isFirstTurn || !AI_OpponentCanFaintAiWithMod(battler, 0))
{
if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_FORCE_SETUP_FIRST_TURN)
{
@ -117,7 +117,7 @@ bool32 ShouldUseItem(u32 battler)
case EFFECT_ITEM_INCREASE_ALL_STATS:
if (gAiLogicData->abilities[battler] == ABILITY_CONTRARY)
break;
if (gDisableStructs[battler].isFirstTurn || !AI_OpponentCanFaintAiWithMod(battler, 0))
if (gBattleStruct->battlerState[battler].isFirstTurn || !AI_OpponentCanFaintAiWithMod(battler, 0))
{
if (gAiThinkingStruct->aiFlags[battler] & AI_FLAG_FORCE_SETUP_FIRST_TURN)
{
@ -143,7 +143,7 @@ bool32 ShouldUseItem(u32 battler)
}
break;
case EFFECT_ITEM_SET_FOCUS_ENERGY:
if (!gDisableStructs[battler].isFirstTurn
if (!gBattleStruct->battlerState[battler].isFirstTurn
|| gBattleMons[battler].volatiles.dragonCheer
|| gBattleMons[battler].volatiles.focusEnergy
|| AI_OpponentCanFaintAiWithMod(battler, 0))
@ -167,7 +167,7 @@ bool32 ShouldUseItem(u32 battler)
break;
case EFFECT_ITEM_SET_MIST:
battlerSide = GetBattlerSide(battler);
if (gDisableStructs[battler].isFirstTurn && !(gSideStatuses[battlerSide] & SIDE_STATUS_MIST))
if (gBattleStruct->battlerState[battler].isFirstTurn && !(gSideStatuses[battlerSide] & SIDE_STATUS_MIST))
shouldUse = TRUE;
break;
case EFFECT_ITEM_REVIVE:

View File

@ -1393,7 +1393,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
// the following checks apply to any target (including user)
// throat chop check
if (gDisableStructs[battlerAtk].throatChopTimer > 0 && IsSoundMove(move))
if (gBattleMons[battlerAtk].volatiles.throatChopTimer > 0 && IsSoundMove(move))
return 0; // Can't even select move at all
// heal block check
if (gBattleMons[battlerAtk].volatiles.healBlock && IsHealBlockPreventingMove(battlerAtk, move))
@ -1902,7 +1902,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_DISABLE:
if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX)
ADJUST_SCORE(-10);
else if (gDisableStructs[battlerDef].disableTimer == 0
else if (gBattleMons[battlerDef].volatiles.disableTimer == 0
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
{
@ -1924,7 +1924,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_ENCORE:
if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX)
ADJUST_SCORE(-10);
else if (gDisableStructs[battlerDef].encoreTimer == 0
else if (gBattleMons[battlerDef].volatiles.encoreTimer == 0
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& !DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
{
@ -2123,17 +2123,17 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_FIRST_TURN_ONLY:
if (!gDisableStructs[battlerAtk].isFirstTurn)
if (!gBattleStruct->battlerState[battlerAtk].isFirstTurn)
ADJUST_SCORE(-10);
if (HasChoiceEffect(battlerAtk))
ADJUST_SCORE(-5);
break;
case EFFECT_STOCKPILE:
if (gDisableStructs[battlerAtk].stockpileCounter >= 3)
if (gBattleMons[battlerAtk].volatiles.stockpileCounter >= 3)
ADJUST_SCORE(-10);
break;
case EFFECT_SWALLOW:
if (gDisableStructs[battlerAtk].stockpileCounter == 0)
if (gBattleMons[battlerAtk].volatiles.stockpileCounter == 0)
{
ADJUST_SCORE(-10);
}
@ -2407,7 +2407,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
break;
case PROTECT_MAT_BLOCK:
if (!gDisableStructs[battlerAtk].isFirstTurn)
if (!gBattleStruct->battlerState[battlerAtk].isFirstTurn)
{
ADJUST_SCORE(-10);
decreased = TRUE;
@ -2434,14 +2434,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
{
ADJUST_SCORE(-10); //Don't protect if you're going to faint after protecting
}
else if (gDisableStructs[battlerAtk].protectUses == 1 && Random() % 100 < 50)
else if (gBattleMons[battlerAtk].volatiles.protectUses == 1 && Random() % 100 < 50)
{
if (isBattle1v1)
ADJUST_SCORE(-6);
else
ADJUST_SCORE(-10); //Don't try double protecting in doubles
}
else if (gDisableStructs[battlerAtk].protectUses >= 2)
else if (gBattleMons[battlerAtk].volatiles.protectUses >= 2)
{
ADJUST_SCORE(-10);
}
@ -2552,7 +2552,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
return AI_CheckBadMove(battlerAtk, battlerDef, GetNaturePowerMove(battlerAtk), score);
break;
case EFFECT_TAUNT:
if (gDisableStructs[battlerDef].tauntTimer > 0
if (gBattleMons[battlerDef].volatiles.tauntTimer > 0
|| DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove))
ADJUST_SCORE(-10);
break;
@ -2952,7 +2952,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case EFFECT_MAGNET_RISE:
if (gFieldStatuses & STATUS_FIELD_GRAVITY
|| gDisableStructs[battlerAtk].magnetRiseTimer > 0
|| gBattleMons[battlerAtk].volatiles.magnetRiseTimer > 0
|| aiData->holdEffects[battlerAtk] == HOLD_EFFECT_IRON_BALL
|| gBattleMons[battlerAtk].volatiles.smackDown
|| gBattleMons[battlerAtk].volatiles.root
@ -4536,14 +4536,14 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
}
break;
case EFFECT_SWALLOW:
if (gDisableStructs[battlerAtk].stockpileCounter == 0)
if (gBattleMons[battlerAtk].volatiles.stockpileCounter == 0)
{
break;
}
else
{
u32 healPercent = 0;
switch (gDisableStructs[battlerAtk].stockpileCounter)
switch (gBattleMons[battlerAtk].volatiles.stockpileCounter)
{
case 1:
healPercent = 25;
@ -4689,7 +4689,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
case EFFECT_DISABLE:
if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX)
break;
else if (gDisableStructs[battlerDef].disableTimer == 0
else if (gBattleMons[battlerDef].volatiles.disableTimer == 0
&& (aiData->lastUsedMove[battlerDef] != MOVE_NONE)
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& (AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)))
@ -4712,7 +4712,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
encourage = TRUE;
break;
}
if (gDisableStructs[battlerDef].encoreTimer == 0
if (gBattleMons[battlerDef].volatiles.encoreTimer == 0
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
&& (encourage))
ADJUST_SCORE(BEST_EFFECT);
@ -4795,7 +4795,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
break;
case PROTECT_MAT_BLOCK:
if (gDisableStructs[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE
if (gBattleStruct->battlerState[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE
&& !IsBattleMoveStatus(predictedMove) && !(AI_GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER))
ADJUST_SCORE(ProtectChecks(battlerAtk, battlerDef, move, predictedMove));
break;
@ -4832,7 +4832,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
case EFFECT_TOXIC_SPIKES:
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, move, aiData))
{
if (gDisableStructs[battlerAtk].isFirstTurn)
if (gBattleStruct->battlerState[battlerAtk].isFirstTurn)
ADJUST_SCORE(BEST_EFFECT);
else
ADJUST_SCORE(DECENT_EFFECT);
@ -4978,7 +4978,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF));
break;
case EFFECT_FIRST_TURN_ONLY:
if (gDisableStructs[battlerAtk].isFirstTurn && IsBestDmgMove(battlerAtk, battlerDef, AI_ATTACKING, move))
if (gBattleStruct->battlerState[battlerAtk].isFirstTurn && IsBestDmgMove(battlerAtk, battlerDef, AI_ATTACKING, move))
ADJUST_SCORE(BEST_EFFECT);
break;
case EFFECT_STOCKPILE:
@ -5250,7 +5250,7 @@ static s32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move, stru
case EFFECT_IMPRISON:
if (predictedMove != MOVE_NONE && HasMove(battlerAtk, predictedMove))
ADJUST_SCORE(DECENT_EFFECT);
else if (gDisableStructs[battlerAtk].isFirstTurn == 0)
else if (gBattleStruct->battlerState[battlerAtk].isFirstTurn == 0)
ADJUST_SCORE(WEAK_EFFECT);
break;
case EFFECT_REFRESH:
@ -6029,7 +6029,7 @@ static s32 AI_CalcAdditionalEffectScore(u32 battlerAtk, u32 battlerDef, u32 move
case MOVE_EFFECT_STEALTH_ROCK:
if (AI_ShouldSetUpHazards(battlerAtk, battlerDef, move, aiData))
{
if (gDisableStructs[battlerAtk].isFirstTurn)
if (gBattleStruct->battlerState[battlerAtk].isFirstTurn)
ADJUST_SCORE(BEST_EFFECT);
else
ADJUST_SCORE(DECENT_EFFECT);

View File

@ -385,7 +385,7 @@ static bool32 ShouldSwitchIfTruant(u32 battler)
// Switch if mon with truant is bodied by Protect or invulnerability spam
if (gAiLogicData->abilities[battler] == ABILITY_TRUANT
&& IsTruantMonVulnerable(battler, gBattlerTarget)
&& gDisableStructs[battler].truantCounter
&& gBattleMons[battler].volatiles.truantCounter
&& gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 2
&& gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE)
{
@ -708,7 +708,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler)
//Perish Song
if (gBattleMons[battler].volatiles.perishSong
&& gDisableStructs[battler].perishSongTimer == 0
&& gBattleMons[battler].volatiles.perishSongTimer == 0
&& monAbility != ABILITY_SOUNDPROOF
&& RandomPercentage(RNG_AI_SWITCH_PERISH_SONG, GetSwitchChance(SHOULD_SWITCH_PERISH_SONG)))
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
@ -1032,7 +1032,7 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
static bool32 ShouldSwitchIfEncored(u32 battler)
{
u32 encoredMove = gDisableStructs[battler].encoredMove;
u32 encoredMove = gBattleMons[battler].volatiles.encoredMove;
u32 opposingBattler = GetOppositeBattler(battler);
// Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer

View File

@ -716,7 +716,7 @@ bool32 IsDamageMoveUnusable(struct BattleContext *ctx)
return TRUE;
break;
case EFFECT_FIRST_TURN_ONLY:
if (!gDisableStructs[ctx->battlerAtk].isFirstTurn)
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn)
return TRUE;
break;
default:
@ -1820,8 +1820,8 @@ enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId)
enum Ability abilityAiRatings[NUM_ABILITY_SLOTS] = {0};
// We've had ability overwritten by e.g. Worry Seed. It is not part of gAiPartyData in case of switching
if (gDisableStructs[battlerId].overwrittenAbility)
return gDisableStructs[battlerId].overwrittenAbility;
if (gBattleMons[battlerId].volatiles.overwrittenAbility)
return gBattleMons[battlerId].volatiles.overwrittenAbility;
// The AI knows its own ability, and omniscience handling
if (IsAiBattlerAware(battlerId) || (IsAiBattlerAssumingStab(battlerId) && ASSUME_STAB_SEES_ABILITY))
@ -2167,7 +2167,7 @@ bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, enum Ability atkAbility, en
return FALSE;
if (((gBattleMons[battlerDef].volatiles.lockOn
&& gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
&& gBattleMons[battlerDef].volatiles.battlerWithSureHit == battlerAtk)
|| atkAbility == ABILITY_NO_GUARD || defAbility == ABILITY_NO_GUARD)
&& gBattleMons[battlerAtk].level >= gBattleMons[battlerDef].level)
{
@ -2270,7 +2270,7 @@ s32 ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove)
s32 score = 0;
// TODO more sophisticated logic
u32 uses = gDisableStructs[battlerAtk].protectUses;
u32 uses = gBattleMons[battlerAtk].volatiles.protectUses;
/*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED))
{
@ -3569,7 +3569,7 @@ bool32 IsBattlerIncapacitated(u32 battler, enum Ability ability)
if (gBattleMons[battler].status1 & STATUS1_SLEEP && !HasMoveWithEffect(battler, EFFECT_SLEEP_TALK))
return TRUE;
if (gDisableStructs[battler].rechargeTimer > 0 || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0))
if (gBattleMons[battler].volatiles.rechargeTimer > 0 || (ability == ABILITY_TRUANT && gBattleMons[battler].volatiles.truantCounter != 0))
return TRUE;
return FALSE;
@ -5940,7 +5940,7 @@ bool32 ShouldTriggerAbility(u32 battlerAtk, u32 battlerDef, enum Ability ability
return BattlerStatCanRise(battlerDef, ability, STAT_SPEED);
case ABILITY_FLASH_FIRE:
return (HasMoveWithType(battlerDef, TYPE_FIRE) && !gDisableStructs[battlerDef].flashFireBoosted);
return (HasMoveWithType(battlerDef, TYPE_FIRE) && !gBattleMons[battlerDef].volatiles.flashFireBoosted);
case ABILITY_WATER_COMPACTION:
case ABILITY_WELL_BAKED_BODY:

View File

@ -103,7 +103,7 @@ EWRAM_DATA static s8 sAnimFramesToWait = 0;
EWRAM_DATA bool8 gAnimScriptActive = FALSE;
EWRAM_DATA u8 gAnimVisualTaskCount = 0;
EWRAM_DATA u8 gAnimSoundTaskCount = 0;
EWRAM_DATA struct DisableStruct *gAnimDisableStructPtr = NULL;
EWRAM_DATA struct LinkBattleAnim *gAnimDisableStructPtr = NULL;
EWRAM_DATA s32 gAnimMoveDmg = 0;
EWRAM_DATA u16 gAnimMovePower = 0;
EWRAM_DATA static u16 sAnimSpriteIndexArray[ANIM_SPRITE_INDEX_COUNT] = {0};

View File

@ -6691,11 +6691,11 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
}
SwapStructData(&gBattleMons[battlerAtk], &gBattleMons[battlerPartner], data, sizeof(struct BattlePokemon));
SwapStructData(&gDisableStructs[battlerAtk], &gDisableStructs[battlerPartner], data, sizeof(struct DisableStruct));
SwapStructData(&gSpecialStatuses[battlerAtk], &gSpecialStatuses[battlerPartner], data, sizeof(struct SpecialStatus));
SwapStructData(&gProtectStructs[battlerAtk], &gProtectStructs[battlerPartner], data, sizeof(struct ProtectStruct));
SwapStructData(&gBattleSpritesDataPtr->battlerData[battlerAtk], &gBattleSpritesDataPtr->battlerData[battlerPartner], data, sizeof(struct BattleSpriteInfo));
SwapStructData(&gBattleStruct->illusion[battlerAtk], &gBattleStruct->illusion[battlerPartner], data, sizeof(struct Illusion));
SwapStructData(&gBattleStruct->battlerState[battlerAtk], &gBattleStruct->battlerState[battlerPartner], data, sizeof(struct BattlerState));
SWAP(gBattleSpritesDataPtr->battlerData[battlerAtk].invisible, gBattleSpritesDataPtr->battlerData[battlerPartner].invisible, temp);
SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp);

View File

@ -998,10 +998,10 @@ void HandleMoveSwitching(u32 battler)
moveInfo->maxPp[gMoveSelectionCursor[battler]] = moveInfo->maxPp[gMultiUsePlayerCursor];
moveInfo->maxPp[gMultiUsePlayerCursor] = i;
if (gDisableStructs[battler].mimickedMoves & (1u << gMoveSelectionCursor[battler]))
if (gBattleMons[battler].volatiles.mimickedMoves & (1u << gMoveSelectionCursor[battler]))
{
gDisableStructs[battler].mimickedMoves &= ~(1u << gMoveSelectionCursor[battler]);
gDisableStructs[battler].mimickedMoves |= 1u << gMultiUsePlayerCursor;
gBattleMons[battler].volatiles.mimickedMoves &= ~(1u << gMoveSelectionCursor[battler]);
gBattleMons[battler].volatiles.mimickedMoves |= 1u << gMultiUsePlayerCursor;
}
MoveSelectionDisplayMoveNames(battler);

View File

@ -953,7 +953,7 @@ static void UNUSED BtlController_EmitPause(u32 battler, u32 bufferId, u8 toWait,
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, toWait * 3 + 2);
}
void BtlController_EmitMoveAnimation(u32 battler, u32 bufferId, u16 move, u8 turnOfMove, u16 movePower, s32 dmg, u8 friendship, struct DisableStruct *disableStructPtr, u8 multihit)
void BtlController_EmitMoveAnimation(u32 battler, u32 bufferId, u16 move, u8 turnOfMove, u16 movePower, s32 dmg, u8 friendship, u8 multihit)
{
gBattleResources->transferBuffer[0] = CONTROLLER_MOVEANIMATION;
gBattleResources->transferBuffer[1] = move;
@ -979,8 +979,17 @@ void BtlController_EmitMoveAnimation(u32 battler, u32 bufferId, u16 move, u8 tur
}
gBattleResources->transferBuffer[14] = 0;
gBattleResources->transferBuffer[15] = 0;
memcpy(&gBattleResources->transferBuffer[16], disableStructPtr, sizeof(struct DisableStruct));
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 16 + sizeof(struct DisableStruct));
struct LinkBattleAnim anim = {0};
anim.isTransformedMonShiny = gBattleMons[battler].volatiles.isTransformedMonShiny;
anim.transformedMonPID = gBattleMons[battler].volatiles.transformedMonPID;
anim.rolloutTimer = gBattleMons[battler].volatiles.rolloutTimer;
anim.furyCutterCounter = gBattleMons[battler].volatiles.furyCutterCounter;
anim.syrupBombIsShiny = gBattleMons[battler].volatiles.syrupBombIsShiny;
anim.isTransformedMonShiny = gBattleMons[battler].volatiles.isTransformedMonShiny;
memcpy(&gBattleResources->transferBuffer[16], &anim, sizeof(struct LinkBattleAnim));
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 16 + sizeof(struct LinkBattleAnim));
}
void BtlController_EmitPrintString(u32 battler, u32 bufferId, enum StringID stringID)
@ -1361,14 +1370,23 @@ void BtlController_EmitSpriteInvisibility(u32 battler, u32 bufferId, bool8 isInv
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4);
}
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, struct DisableStruct *disableStructPtr, u16 argument)
void BtlController_EmitBattleAnimation(u32 battler, u32 bufferId, u8 animationId, u16 argument)
{
gBattleResources->transferBuffer[0] = CONTROLLER_BATTLEANIMATION;
gBattleResources->transferBuffer[1] = animationId;
gBattleResources->transferBuffer[2] = argument;
gBattleResources->transferBuffer[3] = (argument & 0xFF00) >> 8;
memcpy(&gBattleResources->transferBuffer[4], disableStructPtr, sizeof(struct DisableStruct));
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4 + sizeof(struct DisableStruct));
struct LinkBattleAnim anim = {0};
anim.isTransformedMonShiny = gBattleMons[battler].volatiles.isTransformedMonShiny;
anim.transformedMonPID = gBattleMons[battler].volatiles.transformedMonPID;
anim.rolloutTimer = gBattleMons[battler].volatiles.rolloutTimer;
anim.furyCutterCounter = gBattleMons[battler].volatiles.furyCutterCounter;
anim.syrupBombIsShiny = gBattleMons[battler].volatiles.syrupBombIsShiny;
anim.isTransformedMonShiny = gBattleMons[battler].volatiles.isTransformedMonShiny;
memcpy(&gBattleResources->transferBuffer[4], &anim, sizeof(struct LinkBattleAnim));
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4 + sizeof(struct LinkBattleAnim));
}
// mode is a LINK_STANDBY_* constant
@ -2572,13 +2590,13 @@ void BtlController_HandleMoveAnimation(u32 battler)
gAnimMoveDmg = gBattleResources->bufferA[battler][6] | (gBattleResources->bufferA[battler][7] << 8) | (gBattleResources->bufferA[battler][8] << 16) | (gBattleResources->bufferA[battler][9] << 24);
gAnimFriendship = gBattleResources->bufferA[battler][10];
gWeatherMoveAnim = gBattleResources->bufferA[battler][12] | (gBattleResources->bufferA[battler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[battler][16];
gTransformedPersonalities[battler] = gAnimDisableStructPtr->transformedMonPersonality;
gTransformedShininess[battler] = gAnimDisableStructPtr->transformedMonShininess;
gAnimDisableStructPtr = (struct LinkBattleAnim *)&gBattleResources->bufferA[battler][16];
gTransformedPersonalities[battler] = gAnimDisableStructPtr->transformedMonPID;
gTransformedShininess[battler] = gAnimDisableStructPtr->isTransformedMonShiny;
gBattleSpritesDataPtr->healthBoxesData[battler].animationState = 0;
gBattlerControllerFuncs[battler] = Controller_DoMoveAnimation;
if (ShouldUpdateTvData(battler))
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim);
}
}
@ -2954,7 +2972,7 @@ void BtlController_HandleBattleAnimation(u32 battler)
u8 animationId = gBattleResources->bufferA[battler][1];
u16 argument = gBattleResources->bufferA[battler][2] | (gBattleResources->bufferA[battler][3] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[battler][4];
gAnimDisableStructPtr = (struct LinkBattleAnim *)&gBattleResources->bufferA[battler][4];
if (TryHandleLaunchBattleTableAnimation(battler, battler, battler, animationId, argument))
BtlController_Complete(battler);

View File

@ -1981,12 +1981,14 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data)
}
else if (data->currentSecondaryListItemId == VARIOUS_SUBSTITUTE_HP)
{
u32 subHp = gBattleMons[data->battlerId].volatiles.substituteHP;
data->modifyArrows.minValue = 0;
data->modifyArrows.maxValue = 255;
data->modifyArrows.maxDigits = 3;
data->modifyArrows.modifiedValPtr = &gDisableStructs[data->battlerId].substituteHP;
data->modifyArrows.modifiedValPtr = &subHp;
gBattleMons[data->battlerId].volatiles.substituteHP = subHp;
data->modifyArrows.typeOfVal = VAR_SUBSTITUTE;
data->modifyArrows.currValue = gDisableStructs[data->battlerId].substituteHP;
data->modifyArrows.currValue = gBattleMons[data->battlerId].volatiles.substituteHP;
}
else if (data->currentSecondaryListItemId == VARIOUS_IN_LOVE)
{

View File

@ -57,8 +57,8 @@ static bool32 HandleEndTurnVarious(u32 battler)
for (i = 0; i < gBattlersCount; i++)
{
if (gDisableStructs[i].throatChopTimer > 0)
gDisableStructs[i].throatChopTimer--;
if (gBattleMons[i].volatiles.throatChopTimer > 0)
gBattleMons[i].volatiles.throatChopTimer--;
if (gBattleMons[i].volatiles.lockOn > 0)
gBattleMons[i].volatiles.lockOn--;
@ -66,7 +66,7 @@ static bool32 HandleEndTurnVarious(u32 battler)
if (B_CHARGE < GEN_9 && gBattleMons[i].volatiles.chargeTimer > 0)
gBattleMons[i].volatiles.chargeTimer--;
if (gDisableStructs[i].laserFocusTimer > 0 && --gDisableStructs[i].laserFocusTimer == 0)
if (gBattleMons[i].volatiles.laserFocusTimer > 0 && --gBattleMons[i].volatiles.laserFocusTimer == 0)
gBattleMons[i].volatiles.laserFocus = FALSE;
gBattleStruct->battlerState[i].wasAboveHalfHp = gBattleMons[i].hp > gBattleMons[i].maxHP / 2;
@ -327,14 +327,14 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleStruct->eventState.endTurnBlock++;
break;
case FIRST_EVENT_BLOCK_THRASH:
if (gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
if (gBattleMons[battler].volatiles.rampageTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
{
gBattleMons[battler].volatiles.lockConfusionTurns--;
if (gDisableStructs[battler].unableToUseMove)
gBattleMons[battler].volatiles.rampageTurns--;
if (gBattleMons[battler].volatiles.unableToUseMove)
{
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
}
else if (!gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.multipleTurns)
else if (!gBattleMons[battler].volatiles.rampageTurns && gBattleMons[battler].volatiles.multipleTurns)
{
gBattleMons[battler].volatiles.multipleTurns = FALSE;
if (!gBattleMons[battler].volatiles.confusionTurns)
@ -604,9 +604,9 @@ static bool32 HandleEndTurnWrap(u32 battler)
if (gBattleMons[battler].volatiles.wrapped && IsBattlerAlive(battler))
{
if (gDisableStructs[battler].wrapTurns != 0)
if (gBattleMons[battler].volatiles.wrapTurns != 0)
{
gDisableStructs[battler].wrapTurns--;
gBattleMons[battler].volatiles.wrapTurns--;
if (IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
return effect;
@ -663,10 +663,10 @@ static bool32 HandleEndTurnOctolock(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].octolock)
if (gBattleMons[battler].volatiles.octolock)
{
gBattlerTarget = battler;
gBattlerAttacker = gDisableStructs[battler].battlerPreventingEscape;
gBattlerAttacker = gBattleMons[battler].volatiles.battlerPreventingEscape;
BattleScriptExecute(BattleScript_OctolockEndTurn);
effect = TRUE;
}
@ -682,7 +682,7 @@ static bool32 HandleEndTurnSyrupBomb(u32 battler)
if (gBattleMons[battler].volatiles.syrupBomb && (IsBattlerAlive(battler)))
{
if (gDisableStructs[battler].syrupBombTimer > 0 && --gDisableStructs[battler].syrupBombTimer == 0)
if (gBattleMons[battler].volatiles.syrupBombTimer > 0 && --gBattleMons[battler].volatiles.syrupBombTimer == 0)
gBattleMons[battler].volatiles.syrupBomb = FALSE;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SYRUP_BOMB);
gBattlescriptCurrInstr = BattleScript_SyrupBombEndTurn;
@ -699,7 +699,7 @@ static bool32 HandleEndTurnTaunt(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].tauntTimer && --gDisableStructs[battler].tauntTimer == 0)
if (gBattleMons[battler].volatiles.tauntTimer && --gBattleMons[battler].volatiles.tauntTimer == 0)
{
gBattleScripting.battler = battler;
BattleScriptExecute(BattleScript_BufferEndTurn);
@ -716,7 +716,7 @@ static bool32 HandleEndTurnTorment(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].tormentTimer > 0 && --gDisableStructs[battler].tormentTimer == 0)
if (gBattleMons[battler].volatiles.tormentTimer > 0 && --gBattleMons[battler].volatiles.tormentTimer == 0)
{
gBattleMons[battler].volatiles.torment = FALSE;
gBattleScripting.battler = battler;
@ -733,18 +733,18 @@ static bool32 HandleEndTurnEncore(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].encoreTimer != 0)
if (gBattleMons[battler].volatiles.encoreTimer != 0)
{
if (gBattleMons[battler].moves[gDisableStructs[battler].encoredMovePos] != gDisableStructs[battler].encoredMove) // Pokémon does not have the encored move anymore
if (gBattleMons[battler].moves[gBattleMons[battler].volatiles.encoredMovePos] != gBattleMons[battler].volatiles.encoredMove) // Pokémon does not have the encored move anymore
{
gDisableStructs[battler].encoredMove = 0;
gDisableStructs[battler].encoreTimer = 0;
gBattleMons[battler].volatiles.encoredMove = 0;
gBattleMons[battler].volatiles.encoreTimer = 0;
}
else if (--gDisableStructs[battler].encoreTimer == 0
|| gBattleMons[battler].pp[gDisableStructs[battler].encoredMovePos] == 0)
else if (--gBattleMons[battler].volatiles.encoreTimer == 0
|| gBattleMons[battler].pp[gBattleMons[battler].volatiles.encoredMovePos] == 0)
{
gDisableStructs[battler].encoredMove = 0;
gDisableStructs[battler].encoreTimer = 0;
gBattleMons[battler].volatiles.encoredMove = 0;
gBattleMons[battler].volatiles.encoreTimer = 0;
gBattleScripting.battler = battler;
BattleScriptExecute(BattleScript_EncoredNoMore);
effect = TRUE;
@ -761,21 +761,21 @@ static bool32 HandleEndTurnDisable(u32 battler)
u32 moveIndex = 0;
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].disableTimer != 0)
if (gBattleMons[battler].volatiles.disableTimer != 0)
{
for (moveIndex = 0; moveIndex < MAX_MON_MOVES; moveIndex++)
{
if (gDisableStructs[battler].disabledMove == gBattleMons[battler].moves[moveIndex])
if (gBattleMons[battler].volatiles.disabledMove == gBattleMons[battler].moves[moveIndex])
break;
}
if (moveIndex == MAX_MON_MOVES) // Pokémon does not have the disabled move anymore
{
gDisableStructs[battler].disabledMove = 0;
gDisableStructs[battler].disableTimer = 0;
gBattleMons[battler].volatiles.disabledMove = 0;
gBattleMons[battler].volatiles.disableTimer = 0;
}
else if (--gDisableStructs[battler].disableTimer == 0) // disable ends
else if (--gBattleMons[battler].volatiles.disableTimer == 0) // disable ends
{
gDisableStructs[battler].disabledMove = 0;
gBattleMons[battler].volatiles.disabledMove = 0;
gBattleScripting.battler = battler;
BattleScriptExecute(BattleScript_DisabledNoMore);
effect = TRUE;
@ -791,7 +791,7 @@ static bool32 HandleEndTurnMagnetRise(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].magnetRiseTimer > 0 && --gDisableStructs[battler].magnetRiseTimer == 0)
if (gBattleMons[battler].volatiles.magnetRiseTimer > 0 && --gBattleMons[battler].volatiles.magnetRiseTimer == 0)
{
gBattleMons[battler].volatiles.magnetRise = FALSE;
BattleScriptExecute(BattleScript_BufferEndTurn);
@ -808,7 +808,7 @@ static bool32 HandleEndTurnTelekinesis(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].telekinesisTimer > 0 && --gDisableStructs[battler].telekinesisTimer == 0)
if (gBattleMons[battler].volatiles.telekinesisTimer > 0 && --gBattleMons[battler].volatiles.telekinesisTimer == 0)
{
gBattleMons[battler].volatiles.telekinesis = FALSE;
BattleScriptExecute(BattleScript_TelekinesisEndTurn);
@ -824,7 +824,7 @@ static bool32 HandleEndTurnHealBlock(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].healBlockTimer > 0 && --gDisableStructs[battler].healBlockTimer == 0)
if (gBattleMons[battler].volatiles.healBlockTimer > 0 && --gBattleMons[battler].volatiles.healBlockTimer == 0)
{
gBattleMons[battler].volatiles.healBlock = FALSE;
gBattleScripting.battler = battler;
@ -842,7 +842,7 @@ static bool32 HandleEndTurnEmbargo(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].embargoTimer > 0 && --gDisableStructs[battler].embargoTimer == 0)
if (gBattleMons[battler].volatiles.embargoTimer > 0 && --gBattleMons[battler].volatiles.embargoTimer == 0)
{
gBattleMons[battler].volatiles.embargo = FALSE;
BattleScriptExecute(BattleScript_EmbargoEndTurn);
@ -922,8 +922,8 @@ static bool32 HandleEndTurnPerishSong(u32 battler)
if (IsBattlerAlive(battler) && gBattleMons[battler].volatiles.perishSong)
{
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[battler].perishSongTimer);
if (gDisableStructs[battler].perishSongTimer == 0)
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gBattleMons[battler].volatiles.perishSongTimer);
if (gBattleMons[battler].volatiles.perishSongTimer == 0)
{
gBattleMons[battler].volatiles.perishSong = FALSE;
SetPassiveDamageAmount(battler, gBattleMons[battler].hp);
@ -931,7 +931,7 @@ static bool32 HandleEndTurnPerishSong(u32 battler)
}
else
{
gDisableStructs[battler].perishSongTimer--;
gBattleMons[battler].volatiles.perishSongTimer--;
BattleScriptExecute(BattleScript_PerishSongCountGoesDown);
}
effect = TRUE;
@ -946,8 +946,8 @@ static bool32 HandleEndTurnRoost(u32 battler)
gBattleStruct->eventState.endTurnBattler++;
if (gDisableStructs[battler].roostActive)
gDisableStructs[battler].roostActive = FALSE;
if (gBattleMons[battler].volatiles.roostActive)
gBattleMons[battler].volatiles.roostActive = FALSE;
return effect;
}
@ -1235,7 +1235,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
{
gBattlerAttacker = battler;
gBattleMons[battler].volatiles.uproarTurns--; // uproar timer goes down
if (gDisableStructs[battler].unableToUseMove)
if (gBattleMons[battler].volatiles.unableToUseMove)
{
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS;

View File

@ -950,8 +950,8 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, u8 changeType)
if (changeType == SPECIES_GFX_CHANGE_TRANSFORM)
{
personalityValue = gDisableStructs[battlerAtk].transformedMonPersonality;
isShiny = gDisableStructs[battlerAtk].transformedMonShininess;
personalityValue = gBattleMons[battlerAtk].volatiles.transformedMonPID;
isShiny = gBattleMons[battlerAtk].volatiles.isTransformedMonShiny;
}
else
{

View File

@ -53,16 +53,16 @@ enum ItemEffect TryBoosterEnergy(u32 battler, enum Ability ability)
{
enum ItemEffect effect = ITEM_NO_EFFECT;
if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].volatiles.transformed)
if (gBattleMons[battler].volatiles.boosterEnergyActivated || gBattleMons[battler].volatiles.transformed)
return ITEM_NO_EFFECT;
if (((ability == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect()))
|| ((ability == ABILITY_QUARK_DRIVE) && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)))
{
gDisableStructs[battler].paradoxBoostedStat = GetParadoxHighestStatId(battler);
PREPARE_STAT_BUFFER(gBattleTextBuff1, gDisableStructs[battler].paradoxBoostedStat);
gBattleMons[battler].volatiles.paradoxBoostedStat = GetParadoxHighestStatId(battler);
PREPARE_STAT_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.paradoxBoostedStat);
gBattlerAbility = gBattleScripting.battler = battler;
gDisableStructs[battler].boosterEnergyActivated = TRUE;
gBattleMons[battler].volatiles.boosterEnergyActivated = TRUE;
RecordAbilityBattle(battler, ability);
BattleScriptCall(BattleScript_BoosterEnergyRet);
effect = ITEM_EFFECT_OTHER;
@ -427,18 +427,18 @@ static enum ItemEffect TryMentalHerb(u32 battler)
if (B_MENTAL_HERB >= GEN_5)
{
// Check taunt
if (gDisableStructs[battler].tauntTimer != 0)
if (gBattleMons[battler].volatiles.tauntTimer != 0)
{
gDisableStructs[battler].tauntTimer = 0;
gBattleMons[battler].volatiles.tauntTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT);
effect = ITEM_EFFECT_OTHER;
}
// Check encore
if (gDisableStructs[battler].encoreTimer != 0)
if (gBattleMons[battler].volatiles.encoreTimer != 0)
{
gDisableStructs[battler].encoredMove = 0;
gDisableStructs[battler].encoreTimer = 0;
gBattleMons[battler].volatiles.encoredMove = 0;
gBattleMons[battler].volatiles.encoreTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE;
effect = ITEM_EFFECT_OTHER;
}
@ -457,10 +457,10 @@ static enum ItemEffect TryMentalHerb(u32 battler)
effect = ITEM_EFFECT_OTHER;
}
// Check disable
if (gDisableStructs[battler].disableTimer != 0)
if (gBattleMons[battler].volatiles.disableTimer != 0)
{
gDisableStructs[battler].disableTimer = 0;
gDisableStructs[battler].disabledMove = 0;
gBattleMons[battler].volatiles.disableTimer = 0;
gBattleMons[battler].volatiles.disabledMove = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE;
effect = ITEM_EFFECT_OTHER;
}

View File

@ -195,7 +195,6 @@ EWRAM_DATA u32 gHitMarker = 0;
EWRAM_DATA u8 gBideTarget[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u32 gSideStatuses[NUM_BATTLE_SIDES] = {0};
EWRAM_DATA struct SideTimer gSideTimers[NUM_BATTLE_SIDES] = {0};
EWRAM_DATA struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gPauseCounterBattle = 0;
EWRAM_DATA u16 gPaydayMoney = 0;
EWRAM_DATA u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT] = {0};
@ -3020,7 +3019,6 @@ static void BattleStartClearSetData(void)
TurnValuesCleanUp(FALSE);
memset(&gSpecialStatuses, 0, sizeof(gSpecialStatuses));
memset(&gDisableStructs, 0, sizeof(gDisableStructs));
memset(&gFieldTimers, 0, sizeof(gFieldTimers));
memset(&gSideStatuses, 0, sizeof(gSideStatuses));
memset(&gSideTimers, 0, sizeof(gSideTimers));
@ -3030,7 +3028,7 @@ static void BattleStartClearSetData(void)
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
gDisableStructs[i].isFirstTurn = 2;
gBattleStruct->battlerState[i].isFirstTurn = 2;
gLastMoves[i] = MOVE_NONE;
gLastLandedMoves[i] = MOVE_NONE;
gLastHitByType[i] = 0;
@ -3140,7 +3138,6 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
{
s32 i;
enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove);
struct DisableStruct disableStructCopy = gDisableStructs[battler];
ClearIllusionMon(battler);
if (effect != EFFECT_BATON_PASS)
@ -3149,12 +3146,12 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].volatiles.escapePrevention && gDisableStructs[i].battlerPreventingEscape == battler)
if (gBattleMons[i].volatiles.escapePrevention && gBattleMons[i].volatiles.battlerPreventingEscape == battler)
gBattleMons[i].volatiles.escapePrevention = FALSE;
if (gBattleMons[i].volatiles.lockOn && gDisableStructs[i].battlerWithSureHit == battler)
if (gBattleMons[i].volatiles.lockOn && gBattleMons[i].volatiles.battlerWithSureHit == battler)
{
gBattleMons[i].volatiles.lockOn = 0;
gDisableStructs[i].battlerWithSureHit = 0;
gBattleMons[i].volatiles.battlerWithSureHit = 0;
}
}
}
@ -3176,7 +3173,7 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
{
if (!IsBattlerAlly(battler, i)
&& gBattleMons[i].volatiles.lockOn != 0
&& (gDisableStructs[i].battlerWithSureHit == battler))
&& (gBattleMons[i].volatiles.battlerWithSureHit == battler))
{
gBattleMons[i].volatiles.lockOn = 0;
}
@ -3193,36 +3190,34 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
gBattleMons[i].volatiles.wrapped = FALSE;
if (gBattleMons[i].volatiles.syrupBomb && gBattleMons[i].volatiles.stickySyrupedBy == battler)
gBattleMons[i].volatiles.syrupBomb = FALSE;
if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler)
gDisableStructs[i].octolock = FALSE;
if (gBattleMons[i].volatiles.octolock && gBattleMons[i].volatiles.octolockedBy == battler)
gBattleMons[i].volatiles.octolock = FALSE;
}
gActionSelectionCursor[battler] = 0;
gMoveSelectionCursor[battler] = 0;
memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct));
if (GetProtectType(gProtectStructs[battler].protected) == PROTECT_TYPE_SINGLE) // Side type protects expire at the end of the turn
gProtectStructs[battler].protected = PROTECT_NONE;
if (effect == EFFECT_BATON_PASS)
{
gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP;
gDisableStructs[battler].battlerWithSureHit = disableStructCopy.battlerWithSureHit;
gDisableStructs[battler].perishSongTimer = disableStructCopy.perishSongTimer;
gDisableStructs[battler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape;
gDisableStructs[battler].embargoTimer = disableStructCopy.embargoTimer;
gDisableStructs[battler].healBlockTimer = disableStructCopy.healBlockTimer;
gBattleMons[battler].volatiles.substituteHP = volatilesCopy->substituteHP;
gBattleMons[battler].volatiles.battlerWithSureHit = volatilesCopy->battlerWithSureHit;
gBattleMons[battler].volatiles.perishSongTimer = volatilesCopy->perishSongTimer;
gBattleMons[battler].volatiles.battlerPreventingEscape = volatilesCopy->battlerPreventingEscape;
gBattleMons[battler].volatiles.embargoTimer = volatilesCopy->embargoTimer;
gBattleMons[battler].volatiles.healBlockTimer = volatilesCopy->healBlockTimer;
}
else if (effect == EFFECT_SHED_TAIL)
{
gBattleMons[battler].volatiles.substitute = TRUE;
gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP;
gBattleMons[battler].volatiles.substituteHP = volatilesCopy->substituteHP;
}
gBattleStruct->moveResultFlags[battler] = 0;
gDisableStructs[battler].isFirstTurn = 2;
gDisableStructs[battler].truantSwitchInHack = disableStructCopy.truantSwitchInHack;
gBattleStruct->battlerState[battler].isFirstTurn = 2;
gBattleMons[battler].volatiles.truantSwitchInHack = volatilesCopy->truantSwitchInHack;
gLastMoves[battler] = MOVE_NONE;
gLastLandedMoves[battler] = MOVE_NONE;
gLastHitByType[battler] = 0;
@ -3302,7 +3297,7 @@ const u8* FaintClearSetData(u32 battler)
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].volatiles.escapePrevention && gDisableStructs[i].battlerPreventingEscape == battler)
if (gBattleMons[i].volatiles.escapePrevention && gBattleMons[i].volatiles.battlerPreventingEscape == battler)
gBattleMons[i].volatiles.escapePrevention = FALSE;
if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler))
gBattleMons[i].volatiles.infatuation = 0;
@ -3310,15 +3305,13 @@ const u8* FaintClearSetData(u32 battler)
gBattleMons[i].volatiles.wrapped = FALSE;
if (gBattleMons[i].volatiles.syrupBomb && gBattleMons[i].volatiles.stickySyrupedBy == battler)
gBattleMons[i].volatiles.syrupBomb = FALSE;
if (gDisableStructs[i].octolock && gDisableStructs[i].octolockedBy == battler)
gDisableStructs[i].octolock = FALSE;
if (gBattleMons[i].volatiles.octolock && gBattleMons[i].volatiles.octolockedBy == battler)
gBattleMons[i].volatiles.octolock = FALSE;
}
gActionSelectionCursor[battler] = 0;
gMoveSelectionCursor[battler] = 0;
memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct));
if (GetProtectType(gProtectStructs[battler].protected) == PROTECT_TYPE_SINGLE) // Side type protects expire at the end of the turn
gProtectStructs[battler].protected = PROTECT_NONE;
@ -3332,7 +3325,7 @@ const u8* FaintClearSetData(u32 battler)
gProtectStructs[battler].statRaised = FALSE;
gProtectStructs[battler].pranksterElevated = FALSE;
gDisableStructs[battler].isFirstTurn = 2;
gBattleStruct->battlerState[battler].isFirstTurn = 2;
gLastMoves[battler] = MOVE_NONE;
gLastLandedMoves[battler] = MOVE_NONE;
@ -3405,9 +3398,9 @@ const u8* FaintClearSetData(u32 battler)
// If the target was sky dropped in the middle of using Outrage/Petal Dance/Thrash,
// confuse them upon release and print "confused via fatigue" message and animation.
if (gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns)
if (gBattleMons[otherSkyDropper].volatiles.rampageTurns)
{
gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns = 0;
gBattleMons[otherSkyDropper].volatiles.rampageTurns = 0;
// If the released mon can be confused, do so.
// Don't use CanBeConfused here, since it can cause issues in edge cases.
@ -4133,7 +4126,7 @@ static void HandleTurnActionSelectionState(void)
else
{
if (gBattleMons[battler].volatiles.multipleTurns
|| gDisableStructs[battler].rechargeTimer > 0)
|| gBattleMons[battler].volatiles.rechargeTimer > 0)
{
gChosenActionByBattler[battler] = B_ACTION_USE_MOVE;
gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
@ -4183,17 +4176,17 @@ static void HandleTurnActionSelectionState(void)
gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3];
return;
}
else if (GetConfig(CONFIG_ENCORE_TARGET) < GEN_5 && gDisableStructs[battler].encoredMove != MOVE_NONE)
else if (GetConfig(CONFIG_ENCORE_TARGET) < GEN_5 && gBattleMons[battler].volatiles.encoredMove != MOVE_NONE)
{
gChosenMoveByBattler[battler] = gDisableStructs[battler].encoredMove;
gBattleStruct->chosenMovePositions[battler] = gDisableStructs[battler].encoredMovePos;
gChosenMoveByBattler[battler] = gBattleMons[battler].volatiles.encoredMove;
gBattleStruct->chosenMovePositions[battler] = gBattleMons[battler].volatiles.encoredMovePos;
gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
if (gTestRunnerEnabled)
{
UNUSED enum Gimmick gimmick = GIMMICK_NONE;
if (gBattleResources->bufferB[battler][2] & RET_GIMMICK)
gimmick = gBattleStruct->gimmick.usableGimmick[battler];
TestRunner_Battle_CheckChosenMove(battler, gDisableStructs[battler].encoredMove, gDisableStructs[battler].encoredMovePos, gimmick);
TestRunner_Battle_CheckChosenMove(battler, gBattleMons[battler].volatiles.encoredMove, gBattleMons[battler].volatiles.encoredMovePos, gimmick);
}
return;
}
@ -4295,7 +4288,7 @@ static void HandleTurnActionSelectionState(void)
gBattleCommunication[GetPartnerBattler(battler)] = STATE_BEFORE_ACTION_CHOSEN;
RecordedBattle_ClearBattlerAction(battler, 1);
if (gBattleMons[GetPartnerBattler(battler)].volatiles.multipleTurns
|| gDisableStructs[GetPartnerBattler(battler)].rechargeTimer > 0)
|| gBattleMons[GetPartnerBattler(battler)].volatiles.rechargeTimer > 0)
{
BtlController_EmitEndBounceEffect(battler, B_COMM_TO_CONTROLLER);
MarkBattlerForControllerExec(battler);
@ -4311,7 +4304,7 @@ static void HandleTurnActionSelectionState(void)
}
else if (gChosenActionByBattler[GetPartnerBattler(battler)] == B_ACTION_USE_MOVE
&& (gProtectStructs[GetPartnerBattler(battler)].noValidMoves
|| gDisableStructs[GetPartnerBattler(battler)].encoredMove))
|| gBattleMons[GetPartnerBattler(battler)].volatiles.encoredMove))
{
RecordedBattle_ClearBattlerAction(GetPartnerBattler(battler), 1);
}
@ -4692,13 +4685,13 @@ u32 GetBattlerTotalSpeedStat(u32 battler, enum Ability ability, enum HoldEffect
speed = (speed * 150) / 100;
else if (ability == ABILITY_SURGE_SURFER && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
speed *= 2;
else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0)
else if (ability == ABILITY_SLOW_START && gBattleMons[battler].volatiles.slowStartTimer != 0)
speed /= 2;
else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].volatiles.transformed) && ((gBattleWeather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battler].boosterEnergyActivated))
else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].volatiles.transformed) && ((gBattleWeather & B_WEATHER_SUN && HasWeatherEffect()) || gBattleMons[battler].volatiles.boosterEnergyActivated))
speed = (GetParadoxBoostedStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].volatiles.transformed) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivated))
else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].volatiles.transformed) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleMons[battler].volatiles.boosterEnergyActivated))
speed = (GetParadoxBoostedStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed;
else if (ability == ABILITY_UNBURDEN && gDisableStructs[battler].unburdenActive)
else if (ability == ABILITY_UNBURDEN && gBattleMons[battler].volatiles.unburdenActive)
speed *= 2;
// player's badge boost
@ -5053,17 +5046,17 @@ static void TurnValuesCleanUp(bool8 var0)
{
memset(&gProtectStructs[i], 0, sizeof(struct ProtectStruct));
if (gDisableStructs[i].isFirstTurn)
gDisableStructs[i].isFirstTurn--;
if (gBattleStruct->battlerState[i].isFirstTurn)
gBattleStruct->battlerState[i].isFirstTurn--;
if (gDisableStructs[i].rechargeTimer)
gDisableStructs[i].rechargeTimer--;
if (gBattleMons[i].volatiles.rechargeTimer)
gBattleMons[i].volatiles.rechargeTimer--;
gBattleStruct->battlerState[i].canPickupItem = FALSE;
gBattleStruct->battlerState[i].wasAboveHalfHp = FALSE;
}
if (gDisableStructs[i].substituteHP == 0)
if (gBattleMons[i].volatiles.substituteHP == 0)
gBattleMons[i].volatiles.substitute = FALSE;
if (gBattleMons[i].volatiles.semiInvulnerable != STATE_COMMANDER)
@ -5072,7 +5065,7 @@ static void TurnValuesCleanUp(bool8 var0)
gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF;
gBattleStruct->battlerState[i].usedEjectItem = FALSE;
gProtectStructs[i].lashOutAffected = FALSE;
gDisableStructs[i].endured = FALSE;
gBattleMons[i].volatiles.endured = FALSE;
}
gSideTimers[B_SIDE_PLAYER].followmeTimer = 0;
@ -5142,7 +5135,7 @@ static bool32 TryDoMoveEffectsBeforeMoves(void)
{
if (!gBattleStruct->battlerState[battlers[i]].focusPunchBattlers
&& !(gBattleMons[battlers[i]].status1 & STATUS1_SLEEP)
&& !(gDisableStructs[battlers[i]].truantCounter)
&& !(gBattleMons[battlers[i]].volatiles.truantCounter)
&& !(gProtectStructs[battlers[i]].noValidMoves))
{
gBattleStruct->battlerState[battlers[i]].focusPunchBattlers = TRUE;
@ -5240,7 +5233,7 @@ static void CheckChangingTurnOrderEffects(void)
&& GetMoveEffect(gChosenMoveByBattler[battler]) != EFFECT_FOCUS_PUNCH // quick claw message doesn't need to activate here
&& (gProtectStructs[battler].usedCustapBerry || gProtectStructs[battler].quickDraw)
&& !(gBattleMons[battler].status1 & STATUS1_SLEEP)
&& !(gDisableStructs[gBattlerAttacker].truantCounter)
&& !(gBattleMons[gBattlerAttacker].volatiles.truantCounter)
&& !(gProtectStructs[battler].noValidMoves))
{
if (gProtectStructs[battler].usedCustapBerry)
@ -5892,11 +5885,11 @@ enum Type GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, enum Mo
enum Type teraType;
if (gimmick == GIMMICK_TERA && ((teraType = GetMonData(mon, MON_DATA_TERA_TYPE)) != TYPE_STELLAR))
return teraType;
else if (type1 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type1 == TYPE_FLYING))
else if (type1 != TYPE_MYSTERY && !(gBattleMons[battler].volatiles.roostActive && type1 == TYPE_FLYING))
return type1;
else if (type2 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type2 == TYPE_FLYING))
else if (type2 != TYPE_MYSTERY && !(gBattleMons[battler].volatiles.roostActive && type2 == TYPE_FLYING))
return type2;
else if (gDisableStructs[battler].roostActive)
else if (gBattleMons[battler].volatiles.roostActive)
return (B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY);
else if (type3 != TYPE_MYSTERY)
return type3;

File diff suppressed because it is too large Load Diff

View File

@ -577,7 +577,7 @@ static bool8 IsNotSpecialBattleString(enum StringID stringId)
return FALSE;
}
void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags, struct DisableStruct *disableStructPtr)
void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags)
{
struct BattleTv *tvPtr;
u32 atkSide, defSide;

View File

@ -260,7 +260,7 @@ bool32 EndOrContinueWeather(void)
gBattleWeather = B_WEATHER_NONE;
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
gDisableStructs[battler].weatherAbilityDone = FALSE;
gBattleMons[battler].volatiles.weatherAbilityDone = FALSE;
ResetParadoxWeatherStat(battler);
}
gBattleCommunication[MULTISTRING_CHOOSER] = sBattleWeatherInfo[currBattleWeather].endMessage;
@ -470,28 +470,28 @@ void HandleAction_UseMove(void)
gCurrentMove = gChosenMove = MOVE_STRUGGLE;
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE);
}
else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gDisableStructs[gBattlerAttacker].rechargeTimer > 0)
else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gBattleMons[gBattlerAttacker].volatiles.rechargeTimer > 0)
{
gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker];
}
// encore forces you to use the same move
else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE
&& gDisableStructs[gBattlerAttacker].encoredMove == gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos])
else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gBattleMons[gBattlerAttacker].volatiles.encoredMove != MOVE_NONE
&& gBattleMons[gBattlerAttacker].volatiles.encoredMove == gBattleMons[gBattlerAttacker].moves[gBattleMons[gBattlerAttacker].volatiles.encoredMovePos])
{
gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove;
gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos;
gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].volatiles.encoredMove;
gCurrMovePos = gChosenMovePos = gBattleMons[gBattlerAttacker].volatiles.encoredMovePos;
if (GetConfig(CONFIG_ENCORE_TARGET) < GEN_5)
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
}
// check if the encored move wasn't overwritten
else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE
&& gDisableStructs[gBattlerAttacker].encoredMove != gBattleMons[gBattlerAttacker].moves[gDisableStructs[gBattlerAttacker].encoredMovePos])
else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gBattleMons[gBattlerAttacker].volatiles.encoredMove != MOVE_NONE
&& gBattleMons[gBattlerAttacker].volatiles.encoredMove != gBattleMons[gBattlerAttacker].moves[gBattleMons[gBattlerAttacker].volatiles.encoredMovePos])
{
gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos;
gCurrMovePos = gChosenMovePos = gBattleMons[gBattlerAttacker].volatiles.encoredMovePos;
gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
gDisableStructs[gBattlerAttacker].encoredMove = MOVE_NONE;
gDisableStructs[gBattlerAttacker].encoredMovePos = 0;
gDisableStructs[gBattlerAttacker].encoreTimer = 0;
gBattleMons[gBattlerAttacker].volatiles.encoredMove = MOVE_NONE;
gBattleMons[gBattlerAttacker].volatiles.encoredMovePos = 0;
gBattleMons[gBattlerAttacker].volatiles.encoreTimer = 0;
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
}
else if (gBattleMons[gBattlerAttacker].moves[gCurrMovePos] != gChosenMoveByBattler[gBattlerAttacker])
@ -1127,9 +1127,9 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState)
// If target was sky dropped in the middle of Outrage/Thrash/Petal Dance,
// confuse them upon release and display "confused by fatigue" message & animation.
// Don't do this if this CancelMultiTurnMoves is caused by falling asleep via Yawn.
if (gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns && skyDropState != SKY_DROP_STATUS_YAWN)
if (gBattleMons[otherSkyDropper].volatiles.rampageTurns && skyDropState != SKY_DROP_STATUS_YAWN)
{
gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns = 0;
gBattleMons[otherSkyDropper].volatiles.rampageTurns = 0;
// If the target can be confused, confuse them.
// Don't use CanBeConfused, can cause issues in edge cases.
@ -1138,9 +1138,7 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState)
|| IsAbilityAndRecord(otherSkyDropper, ability, ABILITY_OWN_TEMPO)
|| IsMistyTerrainAffected(otherSkyDropper, ability, GetBattlerHoldEffect(otherSkyDropper), gFieldStatuses)))
{
// Set confused status
gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2;
gBattleMons[otherSkyDropper].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
if (skyDropState == SKY_DROP_ATTACKCANCELER_CHECK)
{
gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET;
@ -1166,7 +1164,7 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState)
}
// Clear skyDropTargets data, unless this CancelMultiTurnMoves is caused by Yawn, attackcanceler, or VARIOUS_GRAVITY_ON_AIRBORNE_MONS
if (!(gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns) && gBattleStruct->skyDropTargets[battler] < 4)
if (!(gBattleMons[otherSkyDropper].volatiles.rampageTurns) && gBattleStruct->skyDropTargets[battler] < 4)
{
gBattleStruct->skyDropTargets[battler] = SKY_DROP_NO_TARGET;
gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET;
@ -1184,10 +1182,10 @@ const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState)
if (B_RAMPAGE_CANCELLING < GEN_5)
{
gBattleMons[battler].volatiles.multipleTurns = 0;
gBattleMons[battler].volatiles.lockConfusionTurns = 0;
gBattleMons[battler].volatiles.rampageTurns = 0;
}
else if (!gBattleMons[battler].volatiles.lockConfusionTurns
|| gBattleMons[battler].volatiles.lockConfusionTurns > 1)
else if (!gBattleMons[battler].volatiles.rampageTurns
|| gBattleMons[battler].volatiles.rampageTurns > 1)
{
gBattleMons[battler].volatiles.multipleTurns = 0;
}
@ -1199,8 +1197,8 @@ const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState)
if (gBattleStruct->skyDropTargets[battler] != SKY_DROP_NO_TARGET && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
result = CheckSkyDropState(battler, skyDropState);
gDisableStructs[battler].rolloutTimer = 0;
gDisableStructs[battler].furyCutterCounter = 0;
gBattleMons[battler].volatiles.rolloutTimer = 0;
gBattleMons[battler].volatiles.furyCutterCounter = 0;
return result;
}
@ -1395,10 +1393,10 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
if (GetConfig(CONFIG_ENCORE_TARGET) >= GEN_5
&& DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].encoredMove != move && gDisableStructs[battler].encoredMove != MOVE_NONE)
&& DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gBattleMons[battler].volatiles.encoredMove != move && gBattleMons[battler].volatiles.encoredMove != MOVE_NONE)
{
gBattleScripting.battler = battler;
gCurrentMove = gDisableStructs[battler].encoredMove;
gCurrentMove = gBattleMons[battler].volatiles.encoredMove;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[battler] = BattleScript_EncoredMoveInPalace;
@ -1412,7 +1410,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
return limitations;
}
if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].disabledMove == move && move != MOVE_NONE)
if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gBattleMons[battler].volatiles.disabledMove == move && move != MOVE_NONE)
{
gBattleScripting.battler = battler;
gCurrentMove = move;
@ -1443,7 +1441,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
}
}
if (GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].tauntTimer != 0 && IsBattleMoveStatus(move))
if (GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gBattleMons[battler].volatiles.tauntTimer != 0 && IsBattleMoveStatus(move))
{
if ((GetActiveGimmick(battler) == GIMMICK_DYNAMAX))
gCurrentMove = MOVE_MAX_GUARD;
@ -1461,7 +1459,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
}
}
if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer > 0 && IsSoundMove(move))
if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && gBattleMons[battler].volatiles.throatChopTimer > 0 && IsSoundMove(move))
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
@ -1672,19 +1670,19 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check)
else if (check & MOVE_LIMITATION_PLACEHOLDER && moveEffect == EFFECT_PLACEHOLDER)
unusableMoves |= 1u << i;
// Disable
else if (check & MOVE_LIMITATION_DISABLED && move == gDisableStructs[battler].disabledMove)
else if (check & MOVE_LIMITATION_DISABLED && move == gBattleMons[battler].volatiles.disabledMove)
unusableMoves |= 1u << i;
// Torment
else if (check & MOVE_LIMITATION_TORMENTED && move == gLastMoves[battler] && gBattleMons[battler].volatiles.torment == TRUE)
unusableMoves |= 1u << i;
// Taunt
else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IsBattleMoveStatus(move))
else if (check & MOVE_LIMITATION_TAUNT && gBattleMons[battler].volatiles.tauntTimer && IsBattleMoveStatus(move))
unusableMoves |= 1u << i;
// Imprison
else if (check & MOVE_LIMITATION_IMPRISON && GetImprisonedMovesCount(battler, move))
unusableMoves |= 1u << i;
// Encore
else if (check & MOVE_LIMITATION_ENCORE && gDisableStructs[battler].encoreTimer && gDisableStructs[battler].encoredMove != move)
else if (check & MOVE_LIMITATION_ENCORE && gBattleMons[battler].volatiles.encoreTimer && gBattleMons[battler].volatiles.encoredMove != move)
unusableMoves |= 1u << i;
// Choice Items
else if (check & MOVE_LIMITATION_CHOICE_ITEM && IsHoldEffectChoice(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move)
@ -1702,7 +1700,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check)
else if (check & MOVE_LIMITATION_BELCH && IsBelchPreventingMove(battler, move))
unusableMoves |= 1u << i;
// Throat Chop
else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer > 0 && IsSoundMove(move))
else if (check & MOVE_LIMITATION_THROAT_CHOP && gBattleMons[battler].volatiles.throatChopTimer > 0 && IsSoundMove(move))
unusableMoves |= 1u << i;
// Stuff Cheeks
else if (check & MOVE_LIMITATION_STUFF_CHEEKS && moveEffect == EFFECT_STUFF_CHEEKS && GetItemPocket(gBattleMons[battler].item) != POCKET_BERRIES)
@ -1793,7 +1791,7 @@ void TryToRevertMimicryAndFlags(void)
{
for (u32 battler = 0; battler < gBattlersCount; battler++)
{
gDisableStructs[battler].terrainAbilityDone = FALSE;
gBattleMons[battler].volatiles.terrainAbilityDone = FALSE;
ResetParadoxTerrainStat(battler);
if (IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MIMICRY))
RESTORE_BATTLER_TYPE(battler);
@ -1992,7 +1990,7 @@ static enum MoveCanceler CancelerSkyDrop(struct BattleContext *ctx)
static enum MoveCanceler CancelerRecharge(struct BattleContext *ctx)
{
if (gDisableStructs[ctx->battlerAtk].rechargeTimer > 0)
if (gBattleMons[ctx->battlerAtk].volatiles.rechargeTimer > 0)
{
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
@ -2132,7 +2130,7 @@ static enum MoveCanceler CancelerPowerPoints(struct BattleContext *ctx)
static enum MoveCanceler CancelerTruant(struct BattleContext *ctx)
{
if (GetBattlerAbility(ctx->battlerAtk) == ABILITY_TRUANT && gDisableStructs[ctx->battlerAtk].truantCounter)
if (GetBattlerAbility(ctx->battlerAtk) == ABILITY_TRUANT && gBattleMons[ctx->battlerAtk].volatiles.truantCounter)
{
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING;
@ -2176,8 +2174,8 @@ static enum MoveCanceler CancelerFlinch(struct BattleContext *ctx)
static enum MoveCanceler CancelerDisabled(struct BattleContext *ctx)
{
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE
&& gDisableStructs[ctx->battlerAtk].disabledMove == ctx->move
&& gDisableStructs[ctx->battlerAtk].disabledMove != MOVE_NONE)
&& gBattleMons[ctx->battlerAtk].volatiles.disabledMove == ctx->move
&& gBattleMons[ctx->battlerAtk].volatiles.disabledMove != MOVE_NONE)
{
gBattleScripting.battler = ctx->battlerAtk;
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
@ -2205,7 +2203,7 @@ static enum MoveCanceler CancelerVolatileBlocked(struct BattleContext *ctx)
gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents;
return MOVE_STEP_FAILURE;
}
else if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].throatChopTimer > 0 && IsSoundMove(ctx->move))
else if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gBattleMons[ctx->battlerAtk].volatiles.throatChopTimer > 0 && IsSoundMove(ctx->move))
{
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented;
@ -2216,7 +2214,7 @@ static enum MoveCanceler CancelerVolatileBlocked(struct BattleContext *ctx)
static enum MoveCanceler CancelerTaunted(struct BattleContext *ctx)
{
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gDisableStructs[ctx->battlerAtk].tauntTimer && IsBattleMoveStatus(ctx->move))
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gBattleMons[ctx->battlerAtk].volatiles.tauntTimer && IsBattleMoveStatus(ctx->move))
{
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted;
@ -2519,7 +2517,7 @@ static enum MoveCanceler CancelerPPDeduction(struct BattleContext *ctx)
// For item Metronome, echoed voice
if (ctx->move != gLastResultingMoves[ctx->battlerAtk] || gBattleStruct->unableToUseMove)
gDisableStructs[ctx->battlerAtk].metronomeItemCounter = 0;
gBattleMons[ctx->battlerAtk].volatiles.metronomeItemCounter = 0;
if (gBattleMons[ctx->battlerAtk].pp[movePosition] > ppToDeduct)
gBattleMons[ctx->battlerAtk].pp[movePosition] -= ppToDeduct;
@ -2629,11 +2627,11 @@ static enum MoveCanceler CancelerMoveFailure(struct BattleContext *ctx)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_FIRST_TURN_ONLY:
if (!gDisableStructs[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget)
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_MAT_BLOCK:
if (!gDisableStructs[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget)
if (!gBattleStruct->battlerState[ctx->battlerAtk].isFirstTurn || gSpecialStatuses[ctx->battlerAtk].instructedChosenTarget)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_FLING:
@ -2701,7 +2699,7 @@ static enum MoveCanceler CancelerMoveFailure(struct BattleContext *ctx)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_STOCKPILE:
if (gDisableStructs[ctx->battlerAtk].stockpileCounter >= 3)
if (gBattleMons[ctx->battlerAtk].volatiles.stockpileCounter >= 3)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_STUFF_CHEEKS:
@ -2710,7 +2708,7 @@ static enum MoveCanceler CancelerMoveFailure(struct BattleContext *ctx)
break;
case EFFECT_SWALLOW:
case EFFECT_SPIT_UP:
if (gDisableStructs[ctx->battlerAtk].stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed)
if (gBattleMons[ctx->battlerAtk].volatiles.stockpileCounter == 0 && !gBattleStruct->snatchedMoveIsUsed)
battleScript = BattleScript_ButItFailed;
break;
case EFFECT_TELEPORT:
@ -2806,7 +2804,7 @@ static enum MoveCanceler CancelerProtean(struct BattleContext *ctx)
if (ProteanTryChangeType(ctx->battlerAtk, ctx->abilityAtk, ctx->move, moveType))
{
if (GetConfig(CONFIG_PROTEAN_LIBERO) >= GEN_9)
gDisableStructs[ctx->battlerAtk].usedProteanLibero = TRUE;
gBattleMons[ctx->battlerAtk].volatiles.usedProteanLibero = TRUE;
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType);
gBattlerAbility = ctx->battlerAtk;
PrepareStringBattle(STRINGID_EMPTYSTRING3, ctx->battlerAtk);
@ -3190,7 +3188,7 @@ bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability)
gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag;
for (u32 i = 0; i < gBattlersCount; i++)
{
gDisableStructs[i].weatherAbilityDone = FALSE;
gBattleMons[i].volatiles.weatherAbilityDone = FALSE;
ResetParadoxWeatherStat(i);
}
return TRUE;
@ -3207,7 +3205,7 @@ bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability)
gWishFutureKnock.weatherDuration = 5;
for (u32 i = 0; i < gBattlersCount; i++)
{
gDisableStructs[i].weatherAbilityDone = FALSE;
gBattleMons[i].volatiles.weatherAbilityDone = FALSE;
ResetParadoxWeatherStat(i);
}
return TRUE;
@ -3227,7 +3225,7 @@ bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag)
gFieldStatuses |= statusFlag;
for (u32 i = 0; i < gBattlersCount; i++)
{
gDisableStructs[i].terrainAbilityDone = FALSE;
gBattleMons[i].volatiles.terrainAbilityDone = FALSE;
ResetParadoxTerrainStat(i);
}
if (GetBattlerHoldEffect(battler) == HOLD_EFFECT_TERRAIN_EXTENDER)
@ -3580,11 +3578,11 @@ bool32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, enum Ability ability
break;
case MOVE_ABSORBED_BY_BOOST_FLASH_FIRE:
gBattleStruct->pledgeMove = FALSE;
if (!gDisableStructs[battlerDef].flashFireBoosted)
if (!gBattleMons[battlerDef].volatiles.flashFireBoosted)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_BOOST;
battleScript = BattleScript_FlashFireBoost;
gDisableStructs[battlerDef].flashFireBoosted = TRUE;
gBattleMons[battlerDef].volatiles.flashFireBoosted = TRUE;
}
else
{
@ -4182,7 +4180,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
diagonalBattler = BATTLE_PARTNER(diagonalBattler);
// Imposter only activates when the battler first switches in
if (!gDisableStructs[battler].overwrittenAbility
if (!gBattleMons[battler].volatiles.overwrittenAbility
&& IsBattlerAlive(diagonalBattler)
&& !gBattleMons[diagonalBattler].volatiles.substitute
&& !gBattleMons[diagonalBattler].volatiles.transformed
@ -4226,7 +4224,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
case ABILITY_SLOW_START:
if (shouldAbilityTrigger)
{
gDisableStructs[battler].slowStartTimer = 5;
gBattleMons[battler].volatiles.slowStartTimer = B_SLOW_START_TIMER;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_SLOWSTART;
BattleScriptCall(BattleScript_SwitchInAbilityMsg);
effect++;
@ -4763,7 +4761,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_SPEED_BOOST:
if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && gDisableStructs[battler].isFirstTurn != 2)
if (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN, gLastUsedAbility) && gBattleStruct->battlerState[battler].isFirstTurn != 2)
{
SaveBattlerAttacker(gBattlerAttacker);
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
@ -4773,7 +4771,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_MOODY:
if (gDisableStructs[battler].isFirstTurn != 2)
if (gBattleStruct->battlerState[battler].isFirstTurn != 2)
{
u32 validToRaise = 0, validToLower = 0;
u32 statsNum = GetConfig(CONFIG_MOODY_ACC_EVASION) >= GEN_8 ? NUM_STATS : NUM_BATTLE_STATS;
@ -4804,10 +4802,10 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_TRUANT:
gDisableStructs[gBattlerAttacker].truantCounter ^= 1;
gBattleMons[gBattlerAttacker].volatiles.truantCounter ^= 1;
break;
case ABILITY_SLOW_START:
if (gDisableStructs[battler].slowStartTimer > 0 && --gDisableStructs[battler].slowStartTimer == 0)
if (gBattleMons[battler].volatiles.slowStartTimer > 0 && --gBattleMons[battler].volatiles.slowStartTimer == 0)
{
BattleScriptExecute(BattleScript_SlowStartEnds);
effect++;
@ -4883,18 +4881,18 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_CUD_CHEW:
if (gDisableStructs[battler].cudChew == TRUE)
if (gBattleMons[battler].volatiles.cudChew == TRUE)
{
gBattleScripting.battler = battler;
gDisableStructs[battler].cudChew = FALSE;
gBattleMons[battler].volatiles.cudChew = FALSE;
gLastUsedItem = GetBattlerPartyState(battler)->usedHeldItem;
GetBattlerPartyState(battler)->usedHeldItem = ITEM_NONE;
BattleScriptExecute(BattleScript_CudChewActivates);
effect++;
}
else if (!gDisableStructs[battler].cudChew && GetItemPocket(GetBattlerPartyState(battler)->usedHeldItem) == POCKET_BERRIES)
else if (!gBattleMons[battler].volatiles.cudChew && GetItemPocket(GetBattlerPartyState(battler)->usedHeldItem) == POCKET_BERRIES)
{
gDisableStructs[battler].cudChew = TRUE;
gBattleMons[battler].volatiles.cudChew = TRUE;
}
break;
default:
@ -5013,14 +5011,14 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
break;
case ABILITY_CURSED_BODY:
if (IsBattlerTurnDamaged(gBattlerTarget)
&& gDisableStructs[gBattlerAttacker].disabledMove == MOVE_NONE
&& gBattleMons[gBattlerAttacker].volatiles.disabledMove == MOVE_NONE
&& IsBattlerAlive(gBattlerAttacker)
&& !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL)
&& gChosenMove != MOVE_STRUGGLE
&& RandomPercentage(RNG_CURSED_BODY, 30))
{
gDisableStructs[gBattlerAttacker].disabledMove = gChosenMove;
gDisableStructs[gBattlerAttacker].disableTimer = 4;
gBattleMons[gBattlerAttacker].volatiles.disabledMove = gChosenMove;
gBattleMons[gBattlerAttacker].volatiles.disableTimer = B_DISABLE_TIMER;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gChosenMove);
BattleScriptCall(BattleScript_CursedBodyActivates);
effect++;
@ -5031,7 +5029,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (IsBattlerAlive(gBattlerAttacker)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), move)
&& gDisableStructs[gBattlerAttacker].overwrittenAbility != GetBattlerAbility(gBattlerTarget)
&& gBattleMons[gBattlerAttacker].volatiles.overwrittenAbility != GetBattlerAbility(gBattlerTarget)
&& gBattleMons[gBattlerAttacker].ability != ABILITY_MUMMY
&& gBattleMons[gBattlerAttacker].ability != ABILITY_LINGERING_AROMA
&& !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSuppressed)
@ -5044,7 +5042,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
RemoveAbilityFlags(gBattlerAttacker);
gLastUsedAbility = gBattleMons[gBattlerAttacker].ability;
gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerAttacker].volatiles.overwrittenAbility = gBattleMons[gBattlerTarget].ability;
BattleScriptCall(BattleScript_MummyActivates);
effect++;
break;
@ -5070,8 +5068,8 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
RemoveAbilityFlags(gBattlerAttacker);
gLastUsedAbility = gBattleMons[gBattlerAttacker].ability;
gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gLastUsedAbility;
gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerAttacker].volatiles.overwrittenAbility = gBattleMons[gBattlerTarget].ability;
gBattleMons[gBattlerTarget].ability = gBattleMons[gBattlerTarget].volatiles.overwrittenAbility = gLastUsedAbility;
BattleScriptCall(BattleScript_WanderingSpiritActivates);
effect++;
break;
@ -5330,10 +5328,10 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (!gBattleMons[battler].volatiles.perishSong)
{
gBattleMons[battler].volatiles.perishSong = TRUE;
gDisableStructs[battler].perishSongTimer = 3;
gBattleMons[battler].volatiles.perishSongTimer = 3;
}
gBattleMons[gBattlerAttacker].volatiles.perishSong = TRUE;
gDisableStructs[gBattlerAttacker].perishSongTimer = 3;
gBattleMons[gBattlerAttacker].volatiles.perishSongTimer = 3;
BattleScriptCall(BattleScript_PerishBodyActivates);
effect++;
}
@ -5610,9 +5608,9 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITYEFFECT_NEUTRALIZINGGAS:
if (ability == ABILITY_NEUTRALIZING_GAS && !gDisableStructs[battler].neutralizingGas)
if (ability == ABILITY_NEUTRALIZING_GAS && !gBattleMons[battler].volatiles.neutralizingGas)
{
gDisableStructs[battler].neutralizingGas = TRUE;
gBattleMons[battler].volatiles.neutralizingGas = TRUE;
gBattlerAbility = battler;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS;
BattleScriptCall(BattleScript_SwitchInAbilityMsg);
@ -5623,24 +5621,24 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
switch (ability)
{
case ABILITY_UNNERVE:
if (shouldAbilityTrigger && !gDisableStructs[battler].unnerveActivated)
if (shouldAbilityTrigger && !gBattleMons[battler].volatiles.unnerveActivated)
{
gBattleScripting.battler = battler;
gEffectBattler = GetOppositeBattler(battler);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_UNNERVE;
gDisableStructs[battler].unnerveActivated = TRUE;
gBattleMons[battler].volatiles.unnerveActivated = TRUE;
BattleScriptCall(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
case ABILITY_AS_ONE_ICE_RIDER:
case ABILITY_AS_ONE_SHADOW_RIDER:
if (shouldAbilityTrigger && !gDisableStructs[battler].unnerveActivated)
if (shouldAbilityTrigger && !gBattleMons[battler].volatiles.unnerveActivated)
{
gBattleScripting.battler = battler;
gEffectBattler = GetOppositeBattler(battler);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_ASONE;
gDisableStructs[battler].unnerveActivated = TRUE;
gBattleMons[battler].volatiles.unnerveActivated = TRUE;
BattleScriptCall(BattleScript_ActivateAsOne);
effect++;
}
@ -5722,30 +5720,30 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
if (battlerWeatherAffected && !CanBattlerFormChange(battler, FORM_CHANGE_BATTLE_WEATHER))
{
// If Hail/Snow activates when in Eiscue is in base, prevent reversion when Eiscue Noice gets broken
gDisableStructs[battler].weatherAbilityDone = TRUE;
gBattleMons[battler].volatiles.weatherAbilityDone = TRUE;
}
if (((!gDisableStructs[battler].weatherAbilityDone && battlerWeatherAffected)
if (((!gBattleMons[battler].volatiles.weatherAbilityDone && battlerWeatherAffected)
|| gBattleWeather == B_WEATHER_NONE
|| !HasWeatherEffect()) // Air Lock active
&& TryBattleFormChange(battler, FORM_CHANGE_BATTLE_WEATHER))
{
gBattleScripting.battler = battler;
gDisableStructs[battler].weatherAbilityDone = TRUE;
gBattleMons[battler].volatiles.weatherAbilityDone = TRUE;
BattleScriptCall(BattleScript_BattlerFormChangeWithString);
effect++;
}
break;
}
case ABILITY_PROTOSYNTHESIS:
if (!gDisableStructs[battler].weatherAbilityDone
if (!gBattleMons[battler].volatiles.weatherAbilityDone
&& (gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect()
&& !gBattleMons[battler].volatiles.transformed
&& !gDisableStructs[battler].boosterEnergyActivated)
&& !gBattleMons[battler].volatiles.boosterEnergyActivated)
{
gDisableStructs[battler].weatherAbilityDone = TRUE;
gDisableStructs[battler].paradoxBoostedStat = GetParadoxHighestStatId(battler);
PREPARE_STAT_BUFFER(gBattleTextBuff1, gDisableStructs[battler].paradoxBoostedStat);
gBattleMons[battler].volatiles.weatherAbilityDone = TRUE;
gBattleMons[battler].volatiles.paradoxBoostedStat = GetParadoxHighestStatId(battler);
PREPARE_STAT_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.paradoxBoostedStat);
gBattleScripting.battler = battler;
BattleScriptCall(BattleScript_ProtosynthesisActivates);
effect++;
@ -5762,9 +5760,9 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
switch (gLastUsedAbility)
{
case ABILITY_MIMICRY:
if (!gDisableStructs[battler].terrainAbilityDone && ChangeTypeBasedOnTerrain(battler))
if (!gBattleMons[battler].volatiles.terrainAbilityDone && ChangeTypeBasedOnTerrain(battler))
{
gDisableStructs[battler].terrainAbilityDone = TRUE;
gBattleMons[battler].volatiles.terrainAbilityDone = TRUE;
ChangeTypeBasedOnTerrain(battler);
gBattlerAbility = gBattleScripting.battler = battler;
BattleScriptCall(BattleScript_MimicryActivates);
@ -5772,14 +5770,14 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, u32 battler, enum Ability ab
}
break;
case ABILITY_QUARK_DRIVE:
if (!gDisableStructs[battler].terrainAbilityDone
if (!gBattleMons[battler].volatiles.terrainAbilityDone
&& gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN
&& !gBattleMons[battler].volatiles.transformed
&& !gDisableStructs[battler].boosterEnergyActivated)
&& !gBattleMons[battler].volatiles.boosterEnergyActivated)
{
gDisableStructs[battler].terrainAbilityDone = TRUE;
gDisableStructs[battler].paradoxBoostedStat = GetParadoxHighestStatId(battler);
PREPARE_STAT_BUFFER(gBattleTextBuff1, gDisableStructs[battler].paradoxBoostedStat);
gBattleMons[battler].volatiles.terrainAbilityDone = TRUE;
gBattleMons[battler].volatiles.paradoxBoostedStat = GetParadoxHighestStatId(battler);
PREPARE_STAT_BUFFER(gBattleTextBuff1, gBattleMons[battler].volatiles.paradoxBoostedStat);
gBattlerAbility = gBattleScripting.battler = battler;
BattleScriptCall(BattleScript_QuarkDriveActivates);
effect++;
@ -5818,7 +5816,7 @@ bool32 IsNeutralizingGasOnField(void)
for (i = 0; i < gBattlersCount; i++)
{
if (gDisableStructs[i].neutralizingGas && !gBattleMons[i].volatiles.gastroAcid)
if (gBattleMons[i].volatiles.neutralizingGas && !gBattleMons[i].volatiles.gastroAcid)
return TRUE;
}
@ -6117,23 +6115,23 @@ u32 GetParadoxHighestStatId(u32 battler)
static void ResetParadoxWeatherStat(u32 battler)
{
if (gBattleMons[battler].ability == ABILITY_PROTOSYNTHESIS
&& !gDisableStructs[battler].boosterEnergyActivated)
gDisableStructs[battler].paradoxBoostedStat = 0;
&& !gBattleMons[battler].volatiles.boosterEnergyActivated)
gBattleMons[battler].volatiles.paradoxBoostedStat = 0;
}
static void ResetParadoxTerrainStat(u32 battler)
{
if (gBattleMons[battler].ability == ABILITY_QUARK_DRIVE
&& !gDisableStructs[battler].boosterEnergyActivated)
gDisableStructs[battler].paradoxBoostedStat = 0;
&& !gBattleMons[battler].volatiles.boosterEnergyActivated)
gBattleMons[battler].volatiles.paradoxBoostedStat = 0;
}
u32 GetParadoxBoostedStatId(u32 battler)
{
if (gDisableStructs[battler].paradoxBoostedStat == 0)
gDisableStructs[battler].paradoxBoostedStat = GetParadoxHighestStatId(battler);
if (gBattleMons[battler].volatiles.paradoxBoostedStat == 0)
gBattleMons[battler].volatiles.paradoxBoostedStat = GetParadoxHighestStatId(battler);
return gDisableStructs[battler].paradoxBoostedStat;
return gBattleMons[battler].volatiles.paradoxBoostedStat;
}
bool32 CanBeSlept(u32 battlerAtk, u32 battlerDef, enum Ability abilityDef, enum SleepClauseBlock isBlockedBySleepClause)
@ -6467,7 +6465,7 @@ bool32 HasEnoughHpToEatBerry(u32 battler, enum Ability ability, u32 hpFraction,
void ClearVariousBattlerFlags(u32 battler)
{
gDisableStructs[battler].furyCutterCounter = 0;
gBattleMons[battler].volatiles.furyCutterCounter = 0;
gBattleMons[battler].volatiles.destinyBond = 0;
gBattleMons[battler].volatiles.glaiveRush = FALSE;
gBattleMons[battler].volatiles.grudge = FALSE;
@ -6924,7 +6922,7 @@ u32 GetBattlerWeight(u32 battler)
if (holdEffect == HOLD_EFFECT_FLOAT_STONE)
weight /= 2;
for (i = 0; i < gDisableStructs[battler].autotomizeCount; i++)
for (i = 0; i < gBattleMons[battler].volatiles.autotomizeCount; i++)
{
if (weight > 1000)
{
@ -7105,7 +7103,7 @@ const struct TypePower gNaturalGiftTable[] =
static inline u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower)
{
u32 i;
for (i = 0; i < gDisableStructs[battlerAtk].rolloutTimer; i++)
for (i = 0; i < gBattleMons[battlerAtk].volatiles.rolloutTimer; i++)
basePower *= 2;
if (gBattleMons[battlerAtk].volatiles.defenseCurl)
basePower *= 2;
@ -7114,7 +7112,7 @@ static inline u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower)
static inline u32 CalcFuryCutterBasePower(u32 battlerAtk, u32 basePower)
{
for (u32 i = 0; i < gDisableStructs[battlerAtk].furyCutterCounter; i++)
for (u32 i = 0; i < gBattleMons[battlerAtk].volatiles.furyCutterCounter; i++)
basePower *= 2;
return min(basePower, 160); // The duration to reach 160 depends on a gen
}
@ -7213,7 +7211,7 @@ static inline u32 CalcMoveBasePower(struct BattleContext *ctx)
basePower *= 1 + GetMoveStrikeCount(move) - gMultiHitCounter;
break;
case EFFECT_SPIT_UP:
basePower = 100 * gDisableStructs[battlerAtk].stockpileCounter;
basePower = 100 * gBattleMons[battlerAtk].volatiles.stockpileCounter;
break;
case EFFECT_REVENGE:
if (gProtectStructs[battlerAtk].revengeDoubled & 1u << battlerDef)
@ -7318,12 +7316,12 @@ static inline u32 CalcMoveBasePower(struct BattleContext *ctx)
break;
case EFFECT_PAYBACK:
if (HasBattlerActedThisTurn(battlerDef)
&& (B_PAYBACK_SWITCH_BOOST < GEN_5 || gDisableStructs[battlerDef].isFirstTurn != 2))
&& (B_PAYBACK_SWITCH_BOOST < GEN_5 || gBattleStruct->battlerState[battlerDef].isFirstTurn != 2))
basePower *= 2;
break;
case EFFECT_BOLT_BEAK:
if (!HasBattlerActedThisTurn(battlerDef)
|| gDisableStructs[battlerDef].isFirstTurn == 2)
|| gBattleStruct->battlerState[battlerDef].isFirstTurn == 2)
basePower *= 2;
break;
case EFFECT_FUSION_COMBO:
@ -7645,7 +7643,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct BattleContext *ctx)
case ABILITY_PROTOSYNTHESIS:
{
enum Stat defHighestStat = GetParadoxBoostedStatId(battlerDef);
if ((ctx->weather & B_WEATHER_SUN || gDisableStructs[battlerDef].boosterEnergyActivated)
if ((ctx->weather & B_WEATHER_SUN || gBattleMons[battlerDef].volatiles.boosterEnergyActivated)
&& ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF))
&& !(gBattleMons[battlerDef].volatiles.transformed))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
@ -7654,7 +7652,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct BattleContext *ctx)
case ABILITY_QUARK_DRIVE:
{
u32 defHighestStat = GetParadoxBoostedStatId(battlerDef);
if ((ctx->fieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerDef].boosterEnergyActivated)
if ((ctx->fieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleMons[battlerDef].volatiles.boosterEnergyActivated)
&& ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF))
&& !(gBattleMons[battlerDef].volatiles.transformed))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.7));
@ -7855,7 +7853,7 @@ static inline u32 CalcAttackStat(struct BattleContext *ctx)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
break;
case ABILITY_SLOW_START:
if (gDisableStructs[battlerAtk].slowStartTimer > 0)
if (gBattleMons[battlerAtk].volatiles.slowStartTimer > 0)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5));
break;
case ABILITY_SOLAR_POWER:
@ -7867,7 +7865,7 @@ static inline u32 CalcAttackStat(struct BattleContext *ctx)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5));
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE && gDisableStructs[battlerAtk].flashFireBoosted)
if (moveType == TYPE_FIRE && gBattleMons[battlerAtk].volatiles.flashFireBoosted)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
break;
case ABILITY_SWARM:
@ -7913,7 +7911,7 @@ static inline u32 CalcAttackStat(struct BattleContext *ctx)
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5));
break;
case ABILITY_STAKEOUT:
if (gDisableStructs[battlerDef].isFirstTurn == 2) // just switched in
if (gBattleStruct->battlerState[battlerDef].isFirstTurn == 2) // just switched in
modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0));
break;
case ABILITY_GUTS:
@ -7945,7 +7943,7 @@ static inline u32 CalcAttackStat(struct BattleContext *ctx)
if (!(gBattleMons[battlerAtk].volatiles.transformed))
{
enum Stat atkHighestStat = GetParadoxBoostedStatId(battlerAtk);
if (ctx->weather & B_WEATHER_SUN || gDisableStructs[battlerAtk].boosterEnergyActivated)
if (ctx->weather & B_WEATHER_SUN || gBattleMons[battlerAtk].volatiles.boosterEnergyActivated)
{
if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
@ -7956,7 +7954,7 @@ static inline u32 CalcAttackStat(struct BattleContext *ctx)
if (!(gBattleMons[battlerAtk].volatiles.transformed))
{
enum Stat atkHighestStat = GetParadoxBoostedStatId(battlerAtk);
if (ctx->fieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerAtk].boosterEnergyActivated)
if (ctx->fieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleMons[battlerAtk].volatiles.boosterEnergyActivated)
{
if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK))
modifier = uq4_12_multiply(modifier, UQ_4_12(1.3));
@ -8498,7 +8496,7 @@ static inline uq4_12_t GetAttackerItemsModifier(u32 battlerAtk, uq4_12_t typeEff
{
case HOLD_EFFECT_METRONOME:
metronomeBoostBase = PercentToUQ4_12(GetBattlerHoldEffectParam(battlerAtk));
metronomeTurns = min(gDisableStructs[battlerAtk].metronomeItemCounter, 5);
metronomeTurns = min(gBattleMons[battlerAtk].volatiles.metronomeItemCounter, 5);
// according to bulbapedia this is the "correct" way to calculate the metronome boost
// due to the limited domain of damage numbers it will never really matter whether this is off by one
return uq4_12_add(UQ_4_12(1.0), metronomeBoostBase * metronomeTurns);
@ -9094,7 +9092,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(struct BattleCont
MulByTypeEffectiveness(ctx, &modifier, types[1]);
if (types[2] != TYPE_MYSTERY && types[2] != types[1] && types[2] != types[0])
MulByTypeEffectiveness(ctx, &modifier, types[2]);
if (ctx->moveType == TYPE_FIRE && gDisableStructs[ctx->battlerDef].tarShot)
if (ctx->moveType == TYPE_FIRE && gBattleMons[ctx->battlerDef].volatiles.tarShot)
modifier = uq4_12_multiply(modifier, UQ_4_12(2.0));
if (ctx->updateFlags && (illusionSpecies = GetIllusionMonSpecies(ctx->battlerDef)))
@ -9888,7 +9886,7 @@ u32 TryImmunityAbilityHealStatus(u32 battler)
case ABILITY_OBLIVIOUS:
if (gBattleMons[battler].volatiles.infatuation)
effect = 3;
else if (GetConfig(CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && gDisableStructs[battler].tauntTimer != 0)
else if (GetConfig(CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && gBattleMons[battler].volatiles.tauntTimer != 0)
effect = 4;
break;
}
@ -9910,7 +9908,7 @@ u32 TryImmunityAbilityHealStatus(u32 battler)
BattleScriptCall(BattleScript_AbilityCuredStatus);
break;
case 4: // get rid of taunt
gDisableStructs[battler].tauntTimer = 0;
gBattleMons[battler].volatiles.tauntTimer = 0;
BattleScriptCall(BattleScript_AbilityCuredStatus);
break;
}
@ -10601,7 +10599,7 @@ void GetBattlerTypes(u32 battler, bool32 ignoreTera, enum Type types[static 3])
types[2] = gBattleMons[battler].types[2];
// Roost.
if (!isTera && gDisableStructs[battler].roostActive)
if (!isTera && gBattleMons[battler].volatiles.roostActive)
{
if (types[0] == TYPE_FLYING && types[1] == TYPE_FLYING)
types[0] = types[1] = B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY;
@ -10889,7 +10887,7 @@ bool32 TrySwitchInEjectPack(enum EjectPackTiming timing)
for (u32 i = 0; i < gBattlersCount; i++)
{
if (gDisableStructs[i].tryEjectPack
if (gBattleMons[i].volatiles.tryEjectPack
&& GetBattlerHoldEffect(i) == HOLD_EFFECT_EJECT_PACK
&& IsBattlerAlive(i)
&& CountUsablePartyMons(i) > 0)
@ -10907,7 +10905,7 @@ bool32 TrySwitchInEjectPack(enum EjectPackTiming timing)
SortBattlersBySpeed(battlers, FALSE);
for (u32 i = 0; i < gBattlersCount; i++)
gDisableStructs[i].tryEjectPack = FALSE;
gBattleMons[i].volatiles.tryEjectPack = FALSE;
for (u32 i = 0; i < gBattlersCount; i++)
{
@ -10950,7 +10948,8 @@ bool32 EmergencyExitCanBeTriggered(u32 battler)
// Gets the value of a volatile status flag for a certain battler
// Primarily used for the debug menu and scripts. Outside of it explicit references are preferred
u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile)
// Uses Arm because there is a compiler bug when it tries to compile in thumb
ARM_FUNC u32 GetBattlerVolatile(u32 battler, enum Volatile _volatile)
{
switch (_volatile)
{
@ -11092,7 +11091,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abil
enum BattleMoveEffects moveEffect = GetMoveEffect(move);
u32 nonVolatileStatus = GetMoveNonVolatileStatus(move);
if ((gBattleMons[battlerDef].volatiles.lockOn && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
if ((gBattleMons[battlerDef].volatiles.lockOn && gBattleMons[battlerDef].volatiles.battlerWithSureHit == battlerAtk)
|| (GetConfig(CONFIG_TOXIC_NEVER_MISS) >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|| gBattleMons[battlerDef].volatiles.glaiveRush)
{
@ -11505,7 +11504,7 @@ static u32 GetSleepTalkMove(void)
return move;
// Set Sleep Talk as used move, so it works with Last Resort.
gDisableStructs[gBattlerAttacker].usedMoves |= 1u << gCurrMovePos;
gBattleMons[gBattlerAttacker].volatiles.usedMoves |= 1u << gCurrMovePos;
do
{
movePosition = MOD(Random(), MAX_MON_MOVES);
@ -11545,7 +11544,7 @@ void RemoveAbilityFlags(u32 battler)
switch (GetBattlerAbility(battler))
{
case ABILITY_FLASH_FIRE:
gDisableStructs[battler].flashFireBoosted = FALSE;
gBattleMons[battler].volatiles.flashFireBoosted = FALSE;
break;
case ABILITY_VESSEL_OF_RUIN:
gBattleMons[battler].volatiles.vesselOfRuin = FALSE;
@ -11626,3 +11625,12 @@ bool32 IsUsableWhileAsleepEffect(enum BattleMoveEffects effect)
return FALSE;
}
}
void SetWrapTurns(u32 battler, enum HoldEffect holdEffect)
{
u32 normalWrapTurns = B_WRAP_TURNS - 2; // 5 turns
if (holdEffect == HOLD_EFFECT_GRIP_CLAW)
gBattleMons[battler].volatiles.wrapTurns = B_BINDING_TURNS >= GEN_5 ? B_WRAP_TURNS : normalWrapTurns;
else
gBattleMons[battler].volatiles.wrapTurns = B_BINDING_TURNS >= GEN_5 ? RandomUniform(RNG_WRAP, 4, normalWrapTurns) : RandomUniform(RNG_WRAP, 2, normalWrapTurns);
}

View File

@ -741,7 +741,7 @@ void RecordedBattle_CheckMovesetChanges(u8 mode)
movePp.moves[j] = gBattleMons[battler].moves[moveSlots[j]];
movePp.currentPp[j] = gBattleMons[battler].pp[moveSlots[j]];
movePp.maxPp[j] = ppBonuses[moveSlots[j]];
mimickedMoveSlots[j] = (gDisableStructs[battler].mimickedMoves & (1u << j)) >> j;
mimickedMoveSlots[j] = (gBattleMons[battler].volatiles.mimickedMoves & (1u << j)) >> j;
}
for (j = 0; j < MAX_MON_MOVES; j++)
{
@ -749,11 +749,11 @@ void RecordedBattle_CheckMovesetChanges(u8 mode)
gBattleMons[battler].pp[j] = movePp.currentPp[j];
}
gBattleMons[battler].ppBonuses = 0;
gDisableStructs[battler].mimickedMoves = 0;
gBattleMons[battler].volatiles.mimickedMoves = 0;
for (j = 0; j < MAX_MON_MOVES; j++)
{
gBattleMons[battler].ppBonuses |= movePp.maxPp[j] << (j << 1);
gDisableStructs[battler].mimickedMoves |= mimickedMoveSlots[j] << j;
gBattleMons[battler].volatiles.mimickedMoves |= mimickedMoveSlots[j] << j;
}
if (!(gBattleMons[battler].volatiles.transformed))

View File

@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Booster Energy's Protosynthesis boost is preserved when weat
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
MESSAGE("The sunlight faded.");
} THEN {
EXPECT(gDisableStructs[B_POSITION_PLAYER_LEFT].paradoxBoostedStat == STAT_ATK);
EXPECT(gBattleMons[B_POSITION_PLAYER_LEFT].volatiles.paradoxBoostedStat == STAT_ATK);
}
}
@ -173,7 +173,7 @@ SINGLE_BATTLE_TEST("Booster Energy's Quark Drive boost is preserved when terrain
ANIMATION(ANIM_TYPE_MOVE, MOVE_GRASSY_TERRAIN, opponent);
MESSAGE("The grass disappeared from the battlefield.");
} THEN {
EXPECT(gDisableStructs[B_POSITION_PLAYER_LEFT].paradoxBoostedStat == STAT_ATK);
EXPECT(gBattleMons[B_POSITION_PLAYER_LEFT].volatiles.paradoxBoostedStat == STAT_ATK);
}
}

View File

@ -196,7 +196,7 @@ DOUBLE_BATTLE_TEST("Ally Switch doesn't increase the Protect-like moves counter
} WHEN {
TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); }
} THEN {
EXPECT(gDisableStructs[B_POSITION_PLAYER_RIGHT].protectUses == 0);
EXPECT(gBattleMons[B_POSITION_PLAYER_RIGHT].volatiles.protectUses == 0);
}
}
@ -211,7 +211,7 @@ DOUBLE_BATTLE_TEST("Ally Switch increases the Protect-like moves counter (Gen9+)
} WHEN {
TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); }
} THEN {
EXPECT(gDisableStructs[B_POSITION_PLAYER_RIGHT].protectUses == 1);
EXPECT(gBattleMons[B_POSITION_PLAYER_RIGHT].volatiles.protectUses == 1);
}
}