From a1e67572b60e72c951ac87337bcd56c8472a2e8d Mon Sep 17 00:00:00 2001 From: Nephrite Date: Fri, 11 Jul 2025 23:53:49 +0300 Subject: [PATCH] Replaces STATUS2 usage with volatiles in code (#7262) Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- asm/macros/battle_script.inc | 46 +-- data/battle_scripts_1.s | 38 +- .../how_to_battle_script_command_macro.md | 2 +- include/battle.h | 2 +- include/battle_controllers.h | 4 +- include/battle_gfx_sfx_util.h | 2 +- include/battle_main.h | 2 +- include/battle_util.h | 5 +- include/constants/battle.h | 28 +- include/constants/battle_script_commands.h | 1 - include/item.h | 3 +- include/metaprogram.h | 84 +++-- include/pokemon.h | 4 +- src/battle_ai_main.c | 56 +-- src/battle_ai_switch_items.c | 21 +- src/battle_ai_util.c | 38 +- src/battle_controller_player.c | 2 +- src/battle_controllers.c | 20 +- src/battle_debug.c | 10 +- src/battle_dynamax.c | 4 +- src/battle_end_turn.c | 34 +- src/battle_gfx_sfx_util.c | 12 +- src/battle_main.c | 82 ++--- src/battle_message.c | 5 - src/battle_script_commands.c | 348 ++++++++---------- src/battle_terastal.c | 2 +- src/battle_util.c | 220 ++++++----- src/battle_util2.c | 4 +- src/battle_z_move.c | 4 +- src/data/moves_info.h | 2 +- src/item.c | 19 +- src/item_use.c | 25 +- src/pokemon.c | 2 +- src/recorded_battle.c | 2 +- test/battle/ability/shield_dust.c | 6 +- test/battle/gimmick/dynamax.c | 4 +- test/battle/hold_effect/berserk_gene.c | 6 +- test/battle/hold_effect/covert_cloak.c | 6 +- test/battle/item_effect/cure_status.c | 2 +- test/battle/move_effect/attract.c | 12 +- test/battle/move_effect/baton_pass.c | 2 +- test/battle/move_effect/captivate.c | 4 +- test/battle/move_effect_secondary/thrash.c | 2 +- test/battle/move_effect_secondary/trap_both.c | 4 +- .../battle/{status2 => volatiles}/confusion.c | 0 45 files changed, 583 insertions(+), 598 deletions(-) rename test/battle/{status2 => volatiles}/confusion.c (100%) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index d9a7ca5fed..ba4b4619aa 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -596,27 +596,15 @@ .byte \notChosenMove .endm - .macro statusanimation battler:req + .macro statusanimation battler:req, status=0, isVolatile=FALSE .byte 0x64 .byte \battler - .endm - - .macro status2animation battler:req, status2:req - .byte 0x65 - .byte \battler - .4byte \status2 - .endm - - .macro setmoveeffect effect:req - sethword sMOVE_EFFECT, \effect - sethword sSAVED_MOVE_EFFECT, \effect - .endm - - .macro chosenstatusanimation battler:req, isStatus2:req, status:req - .byte 0x66 - .byte \battler - .byte \isStatus2 .4byte \status + .byte \isVolatile + .endm + + .macro volatileanimation battler:req, volatile:req + statusanimation \battler, \volatile, TRUE .endm .macro yesnobox @@ -979,8 +967,11 @@ .4byte \failInstr .endm - .macro setforesight + .macro setvolatile battler:req, volatile:req, value=TRUE .byte 0xb1 + .byte \battler + .byte \volatile + .byte \value .endm .macro trysetperishsong failInstr:req @@ -1041,10 +1032,6 @@ .byte 0xbe .endm - .macro setdefensecurlbit - .byte 0xbf - .endm - .macro recoverbasedonsunlight failInstr:req .byte 0xc0 .4byte \failInstr @@ -2094,10 +2081,6 @@ .4byte \failInstr .endm - .macro setpowder battler:req - various \battler, VARIOUS_SET_POWDER - .endm - .macro bringdownairbornebattler battler:req various \battler, VARIOUS_GRAVITY_ON_AIRBORNE_MONS .endm @@ -2353,12 +2336,9 @@ setbyte sSTATCHANGER, \stat | \stages << 3 | \down << 7 .endm - .macro chosenstatus1animation battler:req, status:req - chosenstatusanimation \battler, 0x0, \status - .endm - - .macro chosenstatus2animation battler:req, status:req - chosenstatusanimation \battler, 0x1, \status + .macro setmoveeffect effect:req + sethword sMOVE_EFFECT, \effect + sethword sSAVED_MOVE_EFFECT, \effect .endm .macro sethword dst:req, value:req diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index f7d988026d..b51fe1ee26 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1329,7 +1329,7 @@ BattleScript_EffectPowder:: attackstring ppreduce jumpifvolatile BS_TARGET, VOLATILE_POWDER, BattleScript_ButItFailed - setpowder BS_TARGET + setvolatile BS_TARGET, VOLATILE_POWDER attackanimation waitanimation printstring STRINGID_COVEREDINPOWDER @@ -3929,7 +3929,7 @@ BattleScript_EffectForesight:: ppreduce accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON jumpifvolatile BS_TARGET, VOLATILE_FORESIGHT, BattleScript_ButItFailed - setforesight + setvolatile BS_TARGET, VOLATILE_FORESIGHT BattleScript_IdentifiedFoe: attackanimation waitanimation @@ -4026,7 +4026,7 @@ BattleScript_TryDestinyKnotTarget: infatuatewithbattler BS_TARGET, BS_ATTACKER playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT waitanimation - status2animation BS_TARGET, STATUS2_INFATUATION + volatileanimation BS_TARGET, VOLATILE_INFATUATION waitanimation printstring STRINGID_DESTINYKNOTACTIVATES waitmessage B_WAIT_TIME_LONG @@ -4038,7 +4038,7 @@ BattleScript_TryDestinyKnotAttacker: infatuatewithbattler BS_ATTACKER, BS_TARGET playanimation BS_TARGET, B_ANIM_HELD_ITEM_EFFECT waitanimation - status2animation BS_ATTACKER, STATUS2_INFATUATION + volatileanimation BS_ATTACKER, VOLATILE_INFATUATION waitanimation printstring STRINGID_DESTINYKNOTACTIVATES waitmessage B_WAIT_TIME_LONG @@ -4332,7 +4332,7 @@ BattleScript_EffectDefenseCurl:: attackcanceler attackstring ppreduce - setdefensecurlbit + setvolatile BS_TARGET, VOLATILE_DEFENSE_CURL setstatchanger STAT_DEF, 1, FALSE statbuffchange BS_ATTACKER, STAT_CHANGE_ALLOW_PTR | STAT_CHANGE_ONLY_CHECKING, BattleScript_DefenseCurlDoStatUpAnim jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_StatUpPrintString @@ -6866,7 +6866,7 @@ BattleScript_PrintUproarOverTurns:: end2 BattleScript_ThrashConfuses:: - chosenstatus2animation BS_ATTACKER, STATUS2_CONFUSION + volatileanimation BS_ATTACKER, VOLATILE_CONFUSION printstring STRINGID_PKMNFATIGUECONFUSION waitmessage B_WAIT_TIME_LONG end2 @@ -6874,7 +6874,7 @@ BattleScript_ThrashConfuses:: BattleScript_MoveUsedIsConfused:: printstring STRINGID_PKMNISCONFUSED waitmessage B_WAIT_TIME_LONG - status2animation BS_ATTACKER, STATUS2_CONFUSION + volatileanimation BS_ATTACKER, VOLATILE_CONFUSION jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, FALSE, BattleScript_MoveUsedIsConfusedRet BattleScript_DoSelfConfusionDmg:: cancelmultiturnmoves BS_ATTACKER @@ -6900,7 +6900,7 @@ BattleScript_MoveUsedPowder:: ppreduce pause B_WAIT_TIME_SHORT cancelmultiturnmoves BS_ATTACKER - status2animation BS_ATTACKER, STATUS2_POWDER + volatileanimation BS_ATTACKER, VOLATILE_POWDER waitanimation effectivenesssound hitanimation BS_ATTACKER @@ -6938,7 +6938,7 @@ BattleScript_WrapEnds:: BattleScript_MoveUsedIsInLove:: printstring STRINGID_PKMNINLOVE waitmessage B_WAIT_TIME_LONG - status2animation BS_ATTACKER, STATUS2_INFATUATION + volatileanimation BS_ATTACKER, VOLATILE_INFATUATION return BattleScript_MoveUsedIsInLoveCantAttack:: @@ -6949,13 +6949,13 @@ BattleScript_MoveUsedIsInLoveCantAttack:: BattleScript_NightmareTurnDmg:: printstring STRINGID_PKMNLOCKEDINNIGHTMARE waitmessage B_WAIT_TIME_LONG - status2animation BS_ATTACKER, STATUS2_NIGHTMARE + volatileanimation BS_ATTACKER, VOLATILE_NIGHTMARE goto BattleScript_DoTurnDmg BattleScript_CurseTurnDmg:: printstring STRINGID_PKMNAFFLICTEDBYCURSE waitmessage B_WAIT_TIME_LONG - status2animation BS_ATTACKER, STATUS2_CURSED + volatileanimation BS_ATTACKER, VOLATILE_CURSED goto BattleScript_DoTurnDmg BattleScript_TargetPRLZHeal:: @@ -7085,7 +7085,7 @@ BattleScript_MoveEffectWrap:: return BattleScript_MoveEffectConfusion:: - chosenstatus2animation BS_EFFECT_BATTLER, STATUS2_CONFUSION + volatileanimation BS_EFFECT_BATTLER, VOLATILE_CONFUSION printstring STRINGID_PKMNWASCONFUSED waitmessage B_WAIT_TIME_LONG return @@ -8195,7 +8195,7 @@ BattleScript_BanefulBunkerEffect:: BattleScript_CuteCharmActivates:: call BattleScript_AbilityPopUp - status2animation BS_ATTACKER, STATUS2_INFATUATION + volatileanimation BS_ATTACKER, VOLATILE_INFATUATION printstring STRINGID_PKMNSXINFATUATEDY waitmessage B_WAIT_TIME_LONG call BattleScript_TryDestinyKnotTarget @@ -9455,9 +9455,9 @@ BattleScript_EffectConfuseSide:: BattleScript_ConfuseSideLoop: jumpifabsent BS_TARGET, BattleScript_ConfuseSideIncrement trysetconfusion BattleScript_ConfuseSideIncrement - status2animation BS_EFFECT_BATTLER, STATUS2_CONFUSION + volatileanimation BS_EFFECT_BATTLER, VOLATILE_CONFUSION BattleScript_ConfuseSidePrintMessage: - printfromtable gStatus2StringIds + printstring STRINGID_PKMNWASCONFUSED waitmessage B_WAIT_TIME_LONG BattleScript_ConfuseSideIncrement: jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_ConfuseSideEnd @@ -9477,9 +9477,9 @@ BattleScript_EffectInfatuateSide:: BattleScript_InfatuateSideLoop: jumpifabsent BS_TARGET, BattleScript_InfatuateSideIncrement trysetinfatuation BattleScript_InfatuateSideIncrement - status2animation BS_EFFECT_BATTLER, STATUS2_INFATUATION + volatileanimation BS_EFFECT_BATTLER, VOLATILE_INFATUATION BattleScript_InfatuateSidePrintMessage: - printfromtable gStatus2StringIds + printstring STRINGID_PKMNFELLINLOVE waitmessage B_WAIT_TIME_LONG BattleScript_InfatuateSideIncrement: jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_InfatuateSideEnd @@ -9495,7 +9495,7 @@ BattleScript_TormentSideLoop: jumpifabsent BS_TARGET, BattleScript_TormentSideIncrement trysettorment BattleScript_TormentSideIncrement BattleScript_TormentSidePrintMessage: - printfromtable gStatus2StringIds + printstring STRINGID_PKMNSUBJECTEDTOTORMENT waitmessage B_WAIT_TIME_LONG BattleScript_TormentSideIncrement: jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_TormentSideEnd @@ -9516,7 +9516,7 @@ BattleScript_MeanLookSideLoop: jumpifabsent BS_TARGET, BattleScript_MeanLookSideIncrement trysetescapeprevention BattleScript_MeanLookSideIncrement BattleScript_MeanLookSidePrintMessage: - printfromtable gStatus2StringIds + printstring STRINGID_TARGETCANTESCAPENOW waitmessage B_WAIT_TIME_LONG BattleScript_MeanLookSideIncrement: jumpifbytenotequal gBattlerTarget, sBATTLER, BattleScript_MeanLookSideEnd diff --git a/docs/tutorials/how_to_battle_script_command_macro.md b/docs/tutorials/how_to_battle_script_command_macro.md index 2bbf503fbe..afb9a15e89 100644 --- a/docs/tutorials/how_to_battle_script_command_macro.md +++ b/docs/tutorials/how_to_battle_script_command_macro.md @@ -35,7 +35,7 @@ void BS_TrySetOctolock(void) else { gDisableStructs[battler].octolock = TRUE; - gBattleMons[battler].status2 |= STATUS2_ESCAPE_PREVENTION; + gBattleMons[battler].volatiles.escapePrevention = TRUE; gDisableStructs[battler].battlerPreventingEscape = gBattlerAttacker; gBattlescriptCurrInstr = cmd->nextInstr; } diff --git a/include/battle.h b/include/battle.h index cdeac89719..b537f779af 100644 --- a/include/battle.h +++ b/include/battle.h @@ -44,7 +44,7 @@ // Used to exclude moves learned temporarily by Transform or Mimic #define MOVE_IS_PERMANENT(battler, moveSlot) \ - (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) \ + (!(gBattleMons[battler].volatiles.transformed) \ && !(gDisableStructs[battler].mimickedMoves & (1u << moveSlot))) // Battle Actions diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 80c8c6ee38..d5166ce6f8 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -301,8 +301,8 @@ void BtlController_EmitChooseItem(u32 battler, u32 bufferId, u8 *battlePartyOrde void BtlController_EmitChoosePokemon(u32 battler, u32 bufferId, u8 caseId, u8 slotId, u16 abilityId, u8 battlerPreventingSwitchout, u8 *data); void BtlController_EmitHealthBarUpdate(u32 battler, u32 bufferId, u16 hpValue); void BtlController_EmitExpUpdate(u32 battler, u32 bufferId, u8 partyId, s32 expPoints); -void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status1, u32 status2); -void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 status2, u32 status); +void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status); +void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 isVolatile, u32 status); void BtlController_EmitDataTransfer(u32 battler, u32 bufferId, u16 size, void *data); void BtlController_EmitTwoReturnValues(u32 battler, u32 bufferId, u8 ret8, u32 ret32); void BtlController_EmitChosenMonReturnValue(u32 battler, u32 bufferId, u8 partyId, u8 *battlePartyOrder); diff --git a/include/battle_gfx_sfx_util.h b/include/battle_gfx_sfx_util.h index c2cc901171..ae71eb5b50 100644 --- a/include/battle_gfx_sfx_util.h +++ b/include/battle_gfx_sfx_util.h @@ -7,7 +7,7 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler); void SpriteCB_WaitForBattlerBallReleaseAnim(struct Sprite *sprite); void SpriteCB_TrainerSlideIn(struct Sprite *sprite); void SpriteCB_TrainerSpawn(struct Sprite *sprite); -void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isStatus2, u32 status); +void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isVolatile, u32 status); bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId, u16 argument); void InitAndLaunchSpecialAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId); bool8 IsBattleSEPlaying(u8 battler); diff --git a/include/battle_main.h b/include/battle_main.h index 23e030f6d3..6367f7e0f4 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -89,7 +89,7 @@ void SpriteCB_TrainerThrowObject(struct Sprite *sprite); void AnimSetCenterToCornerVecX(struct Sprite *sprite); void BeginBattleIntroDummy(void); void BeginBattleIntro(void); -void SwitchInClearSetData(u32 battler); +void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy); const u8* FaintClearSetData(u32 battler); void BattleTurnPassed(void); u8 IsRunningFromBattleImpossible(u32 battler); diff --git a/include/battle_util.h b/include/battle_util.h index 9eca2dacd7..8161e8d2d2 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -392,9 +392,10 @@ bool32 HadMoreThanHalfHpNowDoesnt(u32 battler); void UpdateStallMons(void); bool32 TryRestoreHPBerries(u32 battler, enum ItemCaseId caseId); bool32 TrySwitchInEjectPack(enum ItemCaseId caseID); -u32 GetMonVolatile(u32 battler, enum Volatile volatile); -void SetMonVolatile(u32 battler, enum Volatile volatile, u32 newValue); +u32 GetMonVolatile(u32 battler, enum Volatile _volatile); +void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue); u32 TryBoosterEnergy(u32 battler, u32 ability, enum ItemCaseId caseID); +bool32 ItemHealMonVolatile(u32 battler, u16 itemId); void PushHazardTypeToQueue(u32 side, enum Hazards hazardType); bool32 IsHazardOnSide(u32 side, enum Hazards hazardType); bool32 AreAnyHazardsOnSide(u32 side); diff --git a/include/constants/battle.h b/include/constants/battle.h index f0861ad43a..b87176ff7a 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -142,23 +142,21 @@ enum VolatileFlags V_BATON_PASSABLE = (1 << 0), }; -// Volatile status ailments -// These are removed after exiting the battle or switching -/* Definitions with names e.g. "Confusion" are accessible in the debug menu - * Enum, Type, (Field name, (optional)bitSize), Flags, (optional)(Debug menu header, (optional)max. value) - */ +/* Volatile status ailments + * These are removed after exiting the battle or switching + * Enum, Type Type, max value, flags */ #define VOLATILE_DEFINITIONS(F) \ - F(VOLATILE_CONFUSION, confusionTurns, (u32, 3), V_BATON_PASSABLE) \ + F(VOLATILE_CONFUSION, confusionTurns, (u32, 6), V_BATON_PASSABLE) \ F(VOLATILE_FLINCHED, flinched, (u32, 1)) \ - F(VOLATILE_UPROAR, uproarTurns, (u32, 3)) \ + F(VOLATILE_UPROAR, uproarTurns, (u32, 5)) \ F(VOLATILE_TORMENT, torment, (u32, 1)) \ - F(VOLATILE_BIDE, bideTurns, (u32, 2)) \ - F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 2)) \ + F(VOLATILE_BIDE, bideTurns, (u32, 3)) \ + F(VOLATILE_LOCK_CONFUSE, lockConfusionTurns, (u32, 3)) \ F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \ F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \ F(VOLATILE_POWDER, powder, (u32, 1)) \ F(VOLATILE_UNUSED, padding, (u32, 1)) \ - F(VOLATILE_INFATUATION, infatuation, (u32, 4)) \ + F(VOLATILE_INFATUATION, infatuation, (enum BattlerId, MAX_BITS(4))) \ F(VOLATILE_DEFENSE_CURL, defenseCurl, (u32, 1)) \ F(VOLATILE_TRANSFORMED, transformed, (u32, 1)) \ F(VOLATILE_RECHARGE, recharge, (u32, 1)) \ @@ -174,18 +172,22 @@ enum VolatileFlags F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE) -/* Use within a macro to get the maximum allowed value for a volatile. Requires _typeBitSize and debug parameters as input. */ -#define GET_VOLATILE_MAXIMUM(_typeBitSize, ...) INVOKE_WITH_B(GET_VOLATILE_MAXIMUM_, _typeBitSize) -#define GET_VOLATILE_MAXIMUM_(_type, ...) FIRST(__VA_OPT__(MAX_BITS(FIRST(__VA_ARGS__)),) MAX_BITS((sizeof(_type) * 8))) +/* Use within a macro to get the maximum allowed value for a volatile. Requires _typeMaxValue as input. */ +#define GET_VOLATILE_MAXIMUM(_typeMaxValue, ...) INVOKE_WITH_B(GET_VOLATILE_MAXIMUM_, _typeMaxValue) +#define GET_VOLATILE_MAXIMUM_(_type, ...) FIRST(__VA_OPT__(FIRST(__VA_ARGS__),) MAX_BITS((sizeof(_type) * 8))) #define UNPACK_VOLATILE_ENUMS(_enum, ...) _enum, enum Volatile { + VOLATILE_NONE, VOLATILE_DEFINITIONS(UNPACK_VOLATILE_ENUMS) /* Expands to VOLATILE_CONFUSION, VOLATILE_FLINCHED, etc. */ }; +// Helper macros +#define INFATUATED_WITH(battler) (battler + 1) + // Old flags #define STATUS2_CONFUSION (1 << 0 | 1 << 1 | 1 << 2) #define STATUS2_CONFUSION_TURN(num) ((num) << 0) diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 34497fc52e..b38d1cb9a6 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -149,7 +149,6 @@ enum CmdVarious VARIOUS_SET_AURORA_VEIL, VARIOUS_TRY_THIRD_TYPE, VARIOUS_ACUPRESSURE, - VARIOUS_SET_POWDER, VARIOUS_GRAVITY_ON_AIRBORNE_MONS, VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS, VARIOUS_JUMP_IF_ROAR_FAILS, diff --git a/include/item.h b/include/item.h index 565784c85a..5fbb12ec43 100644 --- a/include/item.h +++ b/include/item.h @@ -2,6 +2,7 @@ #define GUARD_ITEM_H #include "constants/item.h" +#include "constants/item_effects.h" #include "constants/items.h" #include "constants/moves.h" #include "constants/tms_hms.h" @@ -187,7 +188,7 @@ u8 GetItemBattleUsage(u16 itemId); u32 GetItemSecondaryId(u32 itemId); u32 GetItemFlingPower(u32 itemId); u32 GetItemStatus1Mask(u16 itemId); -u32 GetItemStatus2Mask(u16 itemId); +bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile volatile); u32 GetItemSellPrice(u32 itemId); #endif // GUARD_ITEM_H diff --git a/include/metaprogram.h b/include/metaprogram.h index 47fa99af72..197ed0b756 100644 --- a/include/metaprogram.h +++ b/include/metaprogram.h @@ -120,42 +120,51 @@ #define DEFAULT_3(_default, ...) DEFAULT(_default __VA_OPT__(, THIRD(__VA_ARGS__))) #define DEFAULT_4(_default, ...) DEFAULT(_default __VA_OPT__(, FOURTH(__VA_ARGS__))) +/* Simply a lists numbers 0-31, allows for word-spanning macros */ +#define BITS_32(F, ...) \ + F(0, __VA_ARGS__) \ + F(1, __VA_ARGS__) \ + F(2, __VA_ARGS__) \ + F(3, __VA_ARGS__) \ + F(4, __VA_ARGS__) \ + F(5, __VA_ARGS__) \ + F(6, __VA_ARGS__) \ + F(7, __VA_ARGS__) \ + F(8, __VA_ARGS__) \ + F(9, __VA_ARGS__) \ + F(10, __VA_ARGS__) \ + F(11, __VA_ARGS__) \ + F(12, __VA_ARGS__) \ + F(13, __VA_ARGS__) \ + F(14, __VA_ARGS__) \ + F(15, __VA_ARGS__) \ + F(16, __VA_ARGS__) \ + F(17, __VA_ARGS__) \ + F(18, __VA_ARGS__) \ + F(19, __VA_ARGS__) \ + F(20, __VA_ARGS__) \ + F(21, __VA_ARGS__) \ + F(22, __VA_ARGS__) \ + F(23, __VA_ARGS__) \ + F(24, __VA_ARGS__) \ + F(25, __VA_ARGS__) \ + F(26, __VA_ARGS__) \ + F(27, __VA_ARGS__) \ + F(28, __VA_ARGS__) \ + F(29, __VA_ARGS__) \ + F(30, __VA_ARGS__) \ + F(31, __VA_ARGS__) + +/* Compares _n to 1 shifted by _b by _operation (==, <, > etc) */ +#define OP_BIT_SHIFT(_b, _n, _operation) (_n) _operation (1 << _b) ? _b : + /* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word. Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */ -#define BIT_INDEX(n) \ - (n) == (1 << 0) ? 0 : \ - (n) == (1 << 1) ? 1 : \ - (n) == (1 << 2) ? 2 : \ - (n) == (1 << 3) ? 3 : \ - (n) == (1 << 4) ? 4 : \ - (n) == (1 << 5) ? 5 : \ - (n) == (1 << 6) ? 6 : \ - (n) == (1 << 7) ? 7 : \ - (n) == (1 << 8) ? 8 : \ - (n) == (1 << 9) ? 9 : \ - (n) == (1 << 10) ? 10 : \ - (n) == (1 << 11) ? 11 : \ - (n) == (1 << 12) ? 12 : \ - (n) == (1 << 13) ? 13 : \ - (n) == (1 << 14) ? 14 : \ - (n) == (1 << 15) ? 15 : \ - (n) == (1 << 16) ? 16 : \ - (n) == (1 << 17) ? 17 : \ - (n) == (1 << 18) ? 18 : \ - (n) == (1 << 19) ? 19 : \ - (n) == (1 << 20) ? 20 : \ - (n) == (1 << 21) ? 21 : \ - (n) == (1 << 22) ? 22 : \ - (n) == (1 << 23) ? 23 : \ - (n) == (1 << 24) ? 24 : \ - (n) == (1 << 25) ? 25 : \ - (n) == (1 << 26) ? 26 : \ - (n) == (1 << 27) ? 27 : \ - (n) == (1 << 28) ? 28 : \ - (n) == (1 << 29) ? 29 : \ - (n) == (1 << 30) ? 30 : \ - (n) == (1 << 31) ? 31 : \ - *(u32 *)NULL +#define BIT_INDEX(_n) BITS_32(OP_BIT_SHIFT, _n, ==) *(u32 *)NULL + +/* (Credit to MGriffin) A way to find the minimum required number of bits to +store a number (max: 32). Sample: https://godbolt.org/z/xb4KdPMhT */ +#define BIT_SIZE(_n) (BITS_32(OP_BIT_SHIFT, _n, <) 32) #define COMPRESS_BITS_0 0, 1 #define COMPRESS_BITS_1 1, 1 @@ -167,11 +176,10 @@ Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1 #define COMPRESS_BITS_7 7, 1 /* Will try and compress a set bit (or up to three sequential bits) into a single byte -Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */ +Input must be of the form (upper << lower) where upper can be up to 7, lower up to 31 */ #define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val -#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked) -#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__) -#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower))) +#define COMPRESS_BITS_STEP_2(_unpacked) INVOKE(COMPRESS_BITS_STEP_3, COMPRESS_BITS_## _unpacked) +#define COMPRESS_BITS_STEP_3(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower))) /* Will read a compressed bit stored by COMPRESS_BIT into a single byte */ #define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F)) diff --git a/include/pokemon.h b/include/pokemon.h index 1a6bb8c696..ac525624cc 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -310,8 +310,8 @@ enum { MON_SPR_GFX_MANAGERS_COUNT }; -#define UNPACK_VOLATILE_STRUCT(_enum, _fieldName, _typeBitSize, ...) INVOKE(UNPACK_VOLATILE_STRUCT_, _fieldName, UNPACK_B(_typeBitSize)); -#define UNPACK_VOLATILE_STRUCT_(_fieldName, _type, ...) _type FIRST(__VA_OPT__(_fieldName:FIRST(__VA_ARGS__),) _fieldName) +#define UNPACK_VOLATILE_STRUCT(_enum, _fieldName, _typeMaxValue, ...) INVOKE(UNPACK_VOLATILE_STRUCT_, _fieldName, UNPACK_B(_typeMaxValue)); +#define UNPACK_VOLATILE_STRUCT_(_fieldName, _type, ...) _type FIRST(__VA_OPT__(_fieldName:BIT_SIZE(FIRST(__VA_ARGS__)),) _fieldName) struct Volatiles { diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 43d01dfa2e..3c582e3072 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1653,19 +1653,21 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // AI_CBM_HighRiskForDamage if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < UQ_4_12(2.0)) ADJUST_SCORE(-10); - if (HasDamagingMove(battlerDef) && !((gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE) + if (HasDamagingMove(battlerDef) && !(gBattleMons[battlerAtk].volatiles.substitute || IsBattlerIncapacitated(battlerDef, abilityDef) || gBattleMons[battlerDef].volatiles.infatuation || gBattleMons[battlerDef].volatiles.confusionTurns)) ADJUST_SCORE(-10); - if (HasMoveWithEffect(battlerAtk, EFFECT_SUBSTITUTE) && !(gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE)) + if (HasMoveWithEffect(battlerAtk, EFFECT_SUBSTITUTE) && !gBattleMons[battlerAtk].volatiles.substitute) ADJUST_SCORE(-10); if (HasNonVolatileMoveEffect(battlerAtk, MOVE_EFFECT_SLEEP) && ! (gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) ADJUST_SCORE(-10); break; case EFFECT_COUNTER: case EFFECT_MIRROR_COAT: - if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION)) + if (IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) + || gBattleMons[battlerDef].volatiles.infatuation + || gBattleMons[battlerDef].volatiles.confusionTurns > 0) ADJUST_SCORE(-1); if ((predictedMove == MOVE_NONE || GetBattleMoveCategory(predictedMove) == DAMAGE_CATEGORY_STATUS || DoesSubstituteBlockMove(battlerAtk, BATTLE_PARTNER(battlerDef), predictedMove)) @@ -1717,7 +1719,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_FOCUS_ENERGY: - if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY_ANY) + if (gBattleMons[battlerAtk].volatiles.dragonCheer || gBattleMons[battlerAtk].volatiles.focusEnergy) ADJUST_SCORE(-10); break; case EFFECT_CONFUSE: @@ -1727,7 +1729,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_SUBSTITUTE: - if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_INFILTRATOR) + if (gBattleMons[battlerAtk].volatiles.substitute || aiData->abilities[battlerDef] == ABILITY_INFILTRATOR) ADJUST_SCORE(-8); else if (aiData->hpPercents[battlerAtk] <= 25) ADJUST_SCORE(-10); @@ -1737,7 +1739,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_SHED_TAIL: if (CountUsablePartyMons(battlerAtk) == 0) ADJUST_SCORE(-10); - if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_INFILTRATOR) + if (gBattleMons[battlerAtk].volatiles.substitute || aiData->abilities[battlerDef] == ABILITY_INFILTRATOR) ADJUST_SCORE(-8); else if (aiData->hpPercents[battlerAtk] <= 50) ADJUST_SCORE(-10); @@ -1808,7 +1810,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_NIGHTMARE: - if (gBattleMons[battlerDef].status2 & STATUS2_NIGHTMARE) + if (gBattleMons[battlerDef].volatiles.nightmare) ADJUST_SCORE(-10); else if (!AI_IsBattlerAsleepOrComatose(battlerDef)) ADJUST_SCORE(-8); @@ -1818,7 +1820,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_CURSE: if (IS_BATTLER_OF_TYPE(battlerAtk, TYPE_GHOST)) { - if (gBattleMons[battlerDef].status2 & STATUS2_CURSED + if (gBattleMons[battlerDef].volatiles.cursed || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) ADJUST_SCORE(-10); else if (aiData->hpPercents[battlerAtk] <= 50) @@ -1857,7 +1859,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); // only one mon needs to set up Sticky Web break; case EFFECT_FORESIGHT: - if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT) + if (gBattleMons[battlerDef].volatiles.foresight) ADJUST_SCORE(-10); else if (gBattleMons[battlerDef].statStages[STAT_EVASION] <= 4 || !(IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) @@ -1945,7 +1947,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_BATON_PASS: if (CountUsablePartyMons(battlerAtk) == 0) ADJUST_SCORE(-10); - else if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + else if (gBattleMons[battlerAtk].volatiles.substitute || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) || AnyStatIsRaised(battlerAtk)) break; @@ -2005,7 +2007,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_TORMENT: if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) ADJUST_SCORE(-10); - else if (gBattleMons[battlerDef].status2 & STATUS2_TORMENT + else if (gBattleMons[battlerDef].volatiles.torment || DoesPartnerHaveSameMoveEffect(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) { ADJUST_SCORE(-10); @@ -2162,8 +2164,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-6); break; case EFFECT_TRANSFORM: - if (gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED - || (gBattleMons[battlerDef].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))) //Leave out Illusion b/c AI is supposed to be fooled + if (gBattleMons[battlerAtk].volatiles.transformed + || gBattleMons[battlerDef].volatiles.transformed + || gBattleMons[battlerDef].volatiles.substitute) //Leave out Illusion b/c AI is supposed to be fooled ADJUST_SCORE(-10); break; case EFFECT_SPITE: @@ -2206,7 +2209,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_DESTINY_BOND: if (DoesDestinyBondFail(battlerAtk)) ADJUST_SCORE(-10); - if (gBattleMons[battlerDef].status2 & STATUS2_DESTINY_BOND) + if (gBattleMons[battlerDef].volatiles.destinyBond) ADJUST_SCORE(-10); else if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX) ADJUST_SCORE(-10); @@ -2703,7 +2706,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) || MoveHasAdditionalEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE) || IsZMove(instructedMove) || (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF) - || gBattleMons[battlerDef].status2 & STATUS2_MULTIPLETURNS + || gBattleMons[battlerDef].volatiles.multipleTurns || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) { ADJUST_SCORE(-10); @@ -2975,7 +2978,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-7); break; case EFFECT_PERISH_SONG: - if (!(gBattleMons[battlerDef].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED))) + if (!(gBattleMons[battlerDef].volatiles.escapePrevention || gBattleMons[battlerDef].volatiles.wrapped)) { if (IsTrappingMove(aiData->partnerMove) || predictedMove == MOVE_INGRAIN) ADJUST_SCORE(WEAK_EFFECT); @@ -3038,7 +3041,9 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_DRAGON_CHEER: - if (gBattleMons[battlerAtkPartner].status2 & STATUS2_FOCUS_ENERGY_ANY || !HasDamagingMove(battlerAtkPartner)) + if (gBattleMons[battlerAtkPartner].volatiles.dragonCheer + || gBattleMons[battlerAtkPartner].volatiles.focusEnergy + || !HasDamagingMove(battlerAtkPartner)) ADJUST_SCORE(-5); else if (atkPartnerHoldEffect == HOLD_EFFECT_SCOPE_LENS || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_DRAGON) @@ -4147,7 +4152,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_BATON_PASS: - if ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE + if ((gAiLogicData->shouldSwitch & (1u << battlerAtk)) && (gBattleMons[battlerAtk].volatiles.substitute || (gStatuses3[battlerAtk] & (STATUS3_ROOTED | STATUS3_AQUA_RING | STATUS3_MAGNET_RISE | STATUS3_POWER_TRICK)) || AnyStatIsRaised(battlerAtk))) ADJUST_SCORE(BEST_EFFECT); @@ -4411,7 +4416,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) } break; case EFFECT_DEFENSE_CURL: - if (HasMoveWithEffect(battlerAtk, EFFECT_ROLLOUT) && !(gBattleMons[battlerAtk].status2 & STATUS2_DEFENSE_CURL)) + if (HasMoveWithEffect(battlerAtk, EFFECT_ROLLOUT) && !gBattleMons[battlerAtk].volatiles.defenseCurl) ADJUST_SCORE(DECENT_EFFECT); ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_DEF)); break; @@ -4456,7 +4461,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) && BattlerWillFaintFromSecondaryDamage(battlerDef, aiData->abilities[battlerDef])) break; // Don't use if the attract won't have a change to activate if (gBattleMons[battlerDef].status1 & STATUS1_ANY - || (gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || gBattleMons[battlerDef].volatiles.confusionTurns > 0 || (!AI_CanBattlerEscape(battlerDef) && IsBattlerTrapped(battlerAtk, battlerDef))) ADJUST_SCORE(GOOD_EFFECT); else @@ -5049,7 +5054,7 @@ case EFFECT_GUARD_SPLIT: break; case EFFECT_RAPID_SPIN: if ((AreAnyHazardsOnSide(GetBattlerSide(battlerAtk)) && CountUsablePartyMons(battlerAtk) != 0) - || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].status2 & STATUS2_WRAPPED)) + || (gStatuses3[battlerAtk] & STATUS3_LEECHSEED || gBattleMons[battlerAtk].volatiles.wrapped)) ADJUST_SCORE(GOOD_EFFECT); case EFFECT_SPECTRAL_THIEF: ADJUST_SCORE(AI_ShouldCopyStatChanges(battlerAtk, battlerDef)); @@ -5204,13 +5209,13 @@ case EFFECT_GUARD_SPLIT: score += AI_TryToClearStats(battlerAtk, battlerDef, FALSE); break; case MOVE_EFFECT_BUG_BITE: // And pluck - if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) + if (gBattleMons[battlerDef].volatiles.substitute || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) break; else if (GetItemPocket(aiData->items[battlerDef]) == POCKET_BERRIES) ADJUST_SCORE(DECENT_EFFECT); break; case MOVE_EFFECT_INCINERATE: - if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) + if (gBattleMons[battlerDef].volatiles.substitute || aiData->abilities[battlerDef] == ABILITY_STICKY_HOLD) break; else if (GetItemPocket(aiData->items[battlerDef]) == POCKET_BERRIES || aiData->holdEffects[battlerDef] == HOLD_EFFECT_GEMS) ADJUST_SCORE(DECENT_EFFECT); @@ -5949,9 +5954,10 @@ static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < UQ_4_12(2.0)) ADJUST_SCORE(10); - if (HasDamagingMove(battlerDef) && !((gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE) + if (HasDamagingMove(battlerDef) && !(gBattleMons[battlerAtk].volatiles.substitute || IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) - || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))) + || gBattleMons[battlerDef].volatiles.infatuation + || gBattleMons[battlerDef].volatiles.confusionTurns > 0)) ADJUST_SCORE(10); } break; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 587b085500..ae01363a42 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -692,7 +692,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) && gAiLogicData->abilities[opposingBattler] != ABILITY_KEEN_EYE && gAiLogicData->abilities[opposingBattler] != ABILITY_MINDS_EYE && (B_ILLUMINATE_EFFECT >= GEN_9 && gAiLogicData->abilities[opposingBattler] != ABILITY_ILLUMINATE) - && !(gBattleMons[battler].status2 & STATUS2_FORESIGHT) + && !gBattleMons[battler].volatiles.foresight && !(gStatuses3[battler] & STATUS3_MIRACLE_EYED)) switchMon = FALSE; @@ -713,12 +713,12 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) return SetSwitchinAndSwitch(battler, PARTY_SIZE); //Cursed - if (gBattleMons[battler].status2 & STATUS2_CURSED + if (gBattleMons[battler].volatiles.cursed && (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_CURSED, GetSwitchChance(SHOULD_SWITCH_CURSED_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_CURSED, GetSwitchChance(SHOULD_SWITCH_CURSED)))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); //Nightmare - if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE + if (gBattleMons[battler].volatiles.nightmare && (hasStatRaised ? RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, GetSwitchChance(SHOULD_SWITCH_NIGHTMARE_STATS_RAISED)) : RandomPercentage(RNG_AI_SWITCH_NIGHTMARE, GetSwitchChance(SHOULD_SWITCH_NIGHTMARE)))) return SetSwitchinAndSwitch(battler, PARTY_SIZE); @@ -729,7 +729,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) } // Infatuation - if (gBattleMons[battler].status2 & STATUS2_INFATUATION + if (gBattleMons[battler].volatiles.infatuation && !AiExpectsToFaintPlayer(battler) && gAiLogicData->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_INFATUATION, GetSwitchChance(SHOULD_SWITCH_INFATUATION))) @@ -1079,7 +1079,9 @@ bool32 ShouldSwitch(u32 battler) s32 i; s32 availableToSwitch; - if (gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + if (gBattleMons[battler].volatiles.wrapped) + return FALSE; + if (gBattleMons[battler].volatiles.escapePrevention) return FALSE; if (gStatuses3[battler] & STATUS3_ROOTED) return FALSE; @@ -1228,7 +1230,9 @@ void ModifySwitchAfterMoveScoring(u32 battler) s32 i; s32 availableToSwitch; - if (gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION)) + if (gBattleMons[battler].volatiles.wrapped) + return; + if (gBattleMons[battler].volatiles.escapePrevention) return; if (gStatuses3[battler] & STATUS3_ROOTED) return; @@ -2405,7 +2409,7 @@ static bool32 ShouldUseItem(u32 battler) shouldUse = TRUE; if (itemEffects[3] & ITEM3_PARALYSIS && gBattleMons[battler].status1 & STATUS1_PARALYSIS) shouldUse = TRUE; - if (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].status2 & STATUS2_CONFUSION) + if (itemEffects[3] & ITEM3_CONFUSION && gBattleMons[battler].volatiles.confusionTurns > 0) shouldUse = TRUE; break; case EFFECT_ITEM_INCREASE_STAT: @@ -2417,7 +2421,8 @@ static bool32 ShouldUseItem(u32 battler) break; case EFFECT_ITEM_SET_FOCUS_ENERGY: if (!gDisableStructs[battler].isFirstTurn - || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY + || gBattleMons[battler].volatiles.dragonCheer + || gBattleMons[battler].volatiles.focusEnergy || AI_OpponentCanFaintAiWithMod(battler, 0)) break; shouldUse = TRUE; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 48403d4e11..c9fb43c143 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -373,7 +373,9 @@ bool32 AI_CanBattlerEscape(u32 battler) bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef) { - if (gBattleMons[battlerDef].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED)) + if (gBattleMons[battlerDef].volatiles.wrapped) + return TRUE; + if (gBattleMons[battlerDef].volatiles.escapePrevention) return TRUE; if (gStatuses3[battlerDef] & (STATUS3_ROOTED | STATUS3_SKY_DROPPED)) return TRUE; @@ -1880,7 +1882,9 @@ bool32 ShouldSetSnow(u32 battler, u32 ability, enum ItemHoldEffect holdEffect) bool32 IsBattlerDamagedByStatus(u32 battler) { return gBattleMons[battler].status1 & STATUS1_DAMAGING - || gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_NIGHTMARE | STATUS2_CURSED) + || gBattleMons[battler].volatiles.wrapped + || gBattleMons[battler].volatiles.nightmare + || gBattleMons[battler].volatiles.cursed || gStatuses3[battler] & (STATUS3_PERISH_SONG | STATUS3_LEECHSEED) || gStatuses4[battler] & (STATUS4_SALT_CURE) || gSideStatuses[GetBattlerSide(battler)] & (SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_DAMAGE_NON_TYPES); @@ -2028,7 +2032,7 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) tempScore += WEAK_EFFECT; if (gStatuses3[battlerDef] & STATUS3_ROOTED) tempScore += WEAK_EFFECT; - if (gBattleMons[battlerDef].status2 & STATUS2_CURSED) + if (gBattleMons[battlerDef].volatiles.cursed) tempScore += WEAK_EFFECT; break; case STAT_EVASION: @@ -2038,7 +2042,7 @@ u32 IncreaseStatDownScore(u32 battlerAtk, u32 battlerDef, u32 stat) tempScore += WEAK_EFFECT; if (gStatuses3[battlerDef] & STATUS3_ROOTED) tempScore += WEAK_EFFECT; - if (gBattleMons[battlerDef].status2 & STATUS2_CURSED) + if (gBattleMons[battlerDef].volatiles.cursed) tempScore += WEAK_EFFECT; break; } @@ -2801,7 +2805,7 @@ static u32 GetLeechSeedDamage(u32 battlerId) static u32 GetNightmareDamage(u32 battlerId) { u32 damage = 0; - if ((gBattleMons[battlerId].status2 & STATUS2_NIGHTMARE) && gBattleMons[battlerId].status1 & STATUS1_SLEEP) + if (gBattleMons[battlerId].volatiles.nightmare && gBattleMons[battlerId].status1 & STATUS1_SLEEP) { damage = GetNonDynamaxMaxHP(battlerId) / 4; if (damage == 0) @@ -2813,7 +2817,7 @@ static u32 GetNightmareDamage(u32 battlerId) static u32 GetCurseDamage(u32 battlerId) { u32 damage = 0; - if (gBattleMons[battlerId].status2 & STATUS2_CURSED) + if (gBattleMons[battlerId].volatiles.cursed) { damage = GetNonDynamaxMaxHP(battlerId) / 4; if (damage == 0) @@ -2827,7 +2831,7 @@ static u32 GetTrapDamage(u32 battlerId) // ai has no knowledge about turns remaining u32 damage = 0; enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[gBattleStruct->wrappedBy[battlerId]]; - if (gBattleMons[battlerId].status2 & STATUS2_WRAPPED) + if (gBattleMons[battlerId].volatiles.wrapped) { if (holdEffect == HOLD_EFFECT_BINDING_BAND) damage = GetNonDynamaxMaxHP(battlerId) / (B_BINDING_DAMAGE >= GEN_6 ? 6 : 8); @@ -3233,7 +3237,7 @@ bool32 IsBattlerIncapacitated(u32 battler, u32 ability) if (gBattleMons[battler].status1 & STATUS1_SLEEP && !HasMoveWithEffect(battler, EFFECT_SLEEP_TALK)) return TRUE; - if (gBattleMons[battler].status2 & STATUS2_RECHARGE || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0)) + if (gBattleMons[battler].volatiles.recharge || (ability == ABILITY_TRUANT && gDisableStructs[battler].truantCounter != 0)) return TRUE; return FALSE; @@ -3372,7 +3376,7 @@ bool32 AI_CanParalyze(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 move, bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability) { - if ((gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + if (gBattleMons[battlerDef].volatiles.confusionTurns > 0 || (ability == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, gAiLogicData->abilities[battlerAtk], move)) || IsBattlerTerrainAffected(battlerDef, STATUS_FIELD_MISTY_TERRAIN) || gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD @@ -3421,7 +3425,7 @@ bool32 AI_CanGiveFrostbite(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 b bool32 AI_CanBeInfatuated(u32 battlerAtk, u32 battlerDef, u32 defAbility) { - if ((gBattleMons[battlerDef].status2 & STATUS2_INFATUATION) + if (gBattleMons[battlerDef].volatiles.infatuation || gAiLogicData->effectiveness[battlerAtk][battlerDef][gAiThinkingStruct->movesetIndex] == UQ_4_12(0.0) || defAbility == ABILITY_OBLIVIOUS || !AreBattlersOfOppositeGender(battlerAtk, battlerDef) @@ -3441,8 +3445,8 @@ u32 ShouldTryToFlinch(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbi } else if ((atkAbility == ABILITY_SERENE_GRACE || gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS - || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION - || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || gBattleMons[battlerDef].volatiles.infatuation + || gBattleMons[battlerDef].volatiles.confusionTurns > 0) || ((AI_IsFaster(battlerAtk, battlerDef, move)) && CanTargetFaintAi(battlerDef, battlerAtk))) { return 2; // good idea to flinch @@ -4357,8 +4361,8 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe || IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS) || (HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY)) // filter out Fake Out - || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION - || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) + || gBattleMons[battlerDef].volatiles.infatuation + || gBattleMons[battlerDef].volatiles.confusionTurns > 0) ADJUST_SCORE_PTR(GOOD_EFFECT); else ADJUST_SCORE_PTR(DECENT_EFFECT); @@ -4396,7 +4400,7 @@ void IncreaseConfusionScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score && gAiLogicData->holdEffects[battlerDef] != HOLD_EFFECT_CURE_STATUS) { if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS - || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION + || gBattleMons[battlerDef].volatiles.infatuation || (gAiLogicData->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY))) ADJUST_SCORE_PTR(GOOD_EFFECT); else @@ -4801,9 +4805,9 @@ void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) if (AreAnyHazardsOnSide(GetBattlerSide(battlerDef)) && CountUsablePartyMons(battlerDef) != 0) ADJUST_SCORE_PTR(-2); - if (gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE && AI_IsFaster(battlerAtk, battlerDef, move)) + if (gBattleMons[battlerAtk].volatiles.substitute && AI_IsFaster(battlerAtk, battlerDef, move)) ADJUST_SCORE_PTR(-10); - if (gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE) + if (gBattleMons[battlerDef].volatiles.substitute) ADJUST_SCORE_PTR(GOOD_EFFECT); if (gStatuses3[battlerAtk] & STATUS3_LEECHSEED) diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 0147875995..751a2eca46 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -1025,7 +1025,7 @@ void HandleMoveSwitching(u32 battler) gBattleMons[battler].pp[i] = moveInfo->currentPp[i]; } - if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + if (!(gBattleMons[battler].volatiles.transformed)) { for (i = 0; i < MAX_MON_MOVES; i++) { diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 51f7e75d37..14b39bbb1f 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -1043,24 +1043,20 @@ void BtlController_EmitExpUpdate(u32 battler, u32 bufferId, u8 partyId, s32 expP PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 6); } -void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status1, u32 status2) +void BtlController_EmitStatusIconUpdate(u32 battler, u32 bufferId, u32 status) { gBattleResources->transferBuffer[0] = CONTROLLER_STATUSICONUPDATE; - gBattleResources->transferBuffer[1] = status1; - gBattleResources->transferBuffer[2] = (status1 & 0x0000FF00) >> 8; - gBattleResources->transferBuffer[3] = (status1 & 0x00FF0000) >> 16; - gBattleResources->transferBuffer[4] = (status1 & 0xFF000000) >> 24; - gBattleResources->transferBuffer[5] = status2; - gBattleResources->transferBuffer[6] = (status2 & 0x0000FF00) >> 8; - gBattleResources->transferBuffer[7] = (status2 & 0x00FF0000) >> 16; - gBattleResources->transferBuffer[8] = (status2 & 0xFF000000) >> 24; - PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 9); + gBattleResources->transferBuffer[1] = status; + gBattleResources->transferBuffer[2] = (status & 0x0000FF00) >> 8; + gBattleResources->transferBuffer[3] = (status & 0x00FF0000) >> 16; + gBattleResources->transferBuffer[4] = (status & 0xFF000000) >> 24; + PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 5); } -void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 status2, u32 status) +void BtlController_EmitStatusAnimation(u32 battler, u32 bufferId, bool8 isVolatile, u32 status) { gBattleResources->transferBuffer[0] = CONTROLLER_STATUSANIMATION; - gBattleResources->transferBuffer[1] = status2; + gBattleResources->transferBuffer[1] = isVolatile; gBattleResources->transferBuffer[2] = status; gBattleResources->transferBuffer[3] = (status & 0x0000FF00) >> 8; gBattleResources->transferBuffer[4] = (status & 0x00FF0000) >> 16; diff --git a/src/battle_debug.c b/src/battle_debug.c index 30f3d6766b..cd3b3cd253 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -1668,13 +1668,13 @@ static void UpdateBattlerValue(struct BattleDebugMenu *data) if (data->modifyArrows.currValue) { if (IsBattlerAlive(BATTLE_OPPOSITE(data->battlerId))) - gBattleMons[data->battlerId].status2 |= STATUS2_INFATUATED_WITH(BATTLE_OPPOSITE(data->battlerId)); + gBattleMons[data->battlerId].volatiles.infatuation = INFATUATED_WITH(BATTLE_OPPOSITE(data->battlerId)); else - gBattleMons[data->battlerId].status2 |= STATUS2_INFATUATED_WITH(BATTLE_PARTNER(BATTLE_OPPOSITE(data->battlerId))); + gBattleMons[data->battlerId].volatiles.infatuation = INFATUATED_WITH(BATTLE_PARTNER(BATTLE_OPPOSITE(data->battlerId))); } else { - gBattleMons[data->battlerId].status2 &= ~STATUS2_INFATUATION; + gBattleMons[data->battlerId].volatiles.infatuation = 0; } break; } @@ -2034,7 +2034,7 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data) data->modifyArrows.maxDigits = 1; data->modifyArrows.modifiedValPtr = NULL; data->modifyArrows.typeOfVal = VAR_IN_LOVE; - data->modifyArrows.currValue = (gBattleMons[data->battlerId].status2 & STATUS2_INFATUATION) != 0; + data->modifyArrows.currValue = gBattleMons[data->battlerId].volatiles.infatuation; } break; case LIST_ITEM_STATUS1: @@ -2046,7 +2046,7 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data) data->modifyArrows.currValue = GetMonVolatile(data->battlerId, data->currentSecondaryListItemId); data->modifyArrows.typeOfVal = VAL_VOLATILE; data->modifyArrows.minValue = 0; -#define UNPACK_VOLATILE_MAX_SIZE(_enum, _fieldName, _typeBitSize, ...) case _enum: data->modifyArrows.maxValue = min(MAX_u16, GET_VOLATILE_MAXIMUM(_typeBitSize)); break; +#define UNPACK_VOLATILE_MAX_SIZE(_enum, _fieldName, _typeMaxValue, ...) case _enum: data->modifyArrows.maxValue = min(MAX_u16, GET_VOLATILE_MAXIMUM(_typeMaxValue)); break; switch (data->currentSecondaryListItemId) { VOLATILE_DEFINITIONS(UNPACK_VOLATILE_MAX_SIZE) diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index a34ecc21b3..c6e91742e8 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -181,14 +181,14 @@ void ActivateDynamax(u32 battler) gBattleStruct->dynamax.dynamaxTurns[battler] = gBattleTurnCounter + DYNAMAX_TURNS_COUNT; // Substitute is removed upon Dynamaxing. - gBattleMons[battler].status2 &= ~STATUS2_SUBSTITUTE; + gBattleMons[battler].volatiles.substitute = FALSE; ClearBehindSubstituteBit(battler); // Choiced Moves are reset upon Dynamaxing. gBattleStruct->choicedMove[battler] = MOVE_NONE; // Try Gigantamax form change. - if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) // Ditto cannot Gigantamax. + if (!gBattleMons[battler].volatiles.transformed) // Ditto cannot Gigantamax. TryBattleFormChange(battler, FORM_CHANGE_BATTLE_GIGANTAMAX); BattleScriptExecute(BattleScript_DynamaxBegins); diff --git a/src/battle_end_turn.c b/src/battle_end_turn.c index b63fd3938f..e56b383ba1 100644 --- a/src/battle_end_turn.c +++ b/src/battle_end_turn.c @@ -458,21 +458,21 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler) gBattleStruct->eventBlockCounter++; break; case FIRST_EVENT_BLOCK_THRASH: - if (gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE && !(gStatuses3[battler] & STATUS3_SKY_DROPPED)) + if (gBattleMons[battler].volatiles.lockConfusionTurns && !(gStatuses3[battler] & STATUS3_SKY_DROPPED)) { - gBattleMons[battler].status2 -= STATUS2_LOCK_CONFUSE_TURN(1); + gBattleMons[battler].volatiles.lockConfusionTurns--; if (WasUnableToUseMove(battler)) { CancelMultiTurnMoves(battler, SKY_DROP_IGNORE); } - else if (!(gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) && (gBattleMons[battler].status2 & STATUS2_MULTIPLETURNS)) + else if (!gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.multipleTurns) { - gBattleMons[battler].status2 &= ~STATUS2_MULTIPLETURNS; - if (!(gBattleMons[battler].status2 & STATUS2_CONFUSION)) + gBattleMons[battler].volatiles.multipleTurns = FALSE; + if (!gBattleMons[battler].volatiles.confusionTurns) { gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; SetMoveEffect(battler, battler, TRUE, FALSE); - if (gBattleMons[battler].status2 & STATUS2_CONFUSION) + if (gBattleMons[battler].volatiles.confusionTurns) BattleScriptExecute(BattleScript_ThrashConfuses); effect = TRUE; } @@ -705,7 +705,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) gBattleStruct->turnEffectsBattlerId++; - if (gBattleMons[battler].status2 & STATUS2_NIGHTMARE + if (gBattleMons[battler].volatiles.nightmare && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { @@ -719,7 +719,7 @@ static bool32 HandleEndTurnNightmare(u32 battler) } else { - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; } } @@ -732,7 +732,7 @@ static bool32 HandleEndTurnCurse(u32 battler) gBattleStruct->turnEffectsBattlerId++; - if (gBattleMons[battler].status2 & STATUS2_CURSED + if (gBattleMons[battler].volatiles.cursed && IsBattlerAlive(battler) && !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD)) { @@ -752,7 +752,7 @@ static bool32 HandleEndTurnWrap(u32 battler) gBattleStruct->turnEffectsBattlerId++; - if (gBattleMons[battler].status2 & STATUS2_WRAPPED && IsBattlerAlive(battler)) + if (gBattleMons[battler].volatiles.wrapped && IsBattlerAlive(battler)) { if (--gDisableStructs[battler].wrapTurns != 0) { @@ -773,7 +773,7 @@ static bool32 HandleEndTurnWrap(u32 battler) } else // broke free { - gBattleMons[battler].status2 &= ~STATUS2_WRAPPED; + gBattleMons[battler].volatiles.wrapped = FALSE; PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[battler]); BattleScriptExecute(BattleScript_WrapEnds); } @@ -867,7 +867,7 @@ static bool32 HandleEndTurnTorment(u32 battler) if (gDisableStructs[battler].tormentTimer == gBattleTurnCounter) { - gBattleMons[battler].status2 &= ~STATUS2_TORMENT; + gBattleMons[battler].volatiles.torment = FALSE; BattleScriptExecute(BattleScript_TormentEnds); effect = TRUE; } @@ -1349,7 +1349,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) switch (gBattleStruct->eventBlockCounter) { case THIRD_EVENT_BLOCK_UPROAR: - if (gBattleMons[battler].status2 & STATUS2_UPROAR) + if (gBattleMons[battler].volatiles.uproarTurns) { for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++) { @@ -1357,7 +1357,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) && GetBattlerAbility(gBattlerAttacker) != ABILITY_SOUNDPROOF) { gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = 1; BattleScriptExecute(BattleScript_MonWokeUpInUproar); BtlController_EmitSetMonData(gBattlerAttacker, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1); @@ -1372,16 +1372,16 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler) else { gBattlerAttacker = battler; - gBattleMons[battler].status2 -= STATUS2_UPROAR_TURN(1); // uproar timer goes down + gBattleMons[battler].volatiles.uproarTurns--; // uproar timer goes down if (WasUnableToUseMove(battler)) { CancelMultiTurnMoves(battler, SKY_DROP_IGNORE); gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS; } - else if (gBattleMons[battler].status2 & STATUS2_UPROAR) + else if (gBattleMons[battler].volatiles.uproarTurns) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_CONTINUES; - gBattleMons[battler].status2 |= STATUS2_MULTIPLETURNS; + gBattleMons[battler].volatiles.multipleTurns = TRUE; } else { diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index ca1b8fcb02..930419e3d9 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -459,10 +459,10 @@ static void SpriteCB_TrainerSlideVertical(struct Sprite *sprite) #undef sSpeedX -void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isStatus2, u32 status) +void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isVolatile, u32 status) { gBattleSpritesDataPtr->healthBoxesData[battler].statusAnimActive = 1; - if (!isStatus2) + if (!isVolatile) { if (status == STATUS1_FREEZE || status == STATUS1_FROSTBITE) LaunchStatusAnimation(battler, B_ANIM_STATUS_FRZ); @@ -479,13 +479,13 @@ void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 isStatus2, u32 statu } else { - if (status & STATUS2_INFATUATION) + if (status == VOLATILE_INFATUATION) LaunchStatusAnimation(battler, B_ANIM_STATUS_INFATUATION); - else if (status & STATUS2_CONFUSION) + else if (status == VOLATILE_CONFUSION) LaunchStatusAnimation(battler, B_ANIM_STATUS_CONFUSION); - else if (status & STATUS2_CURSED) + else if (status == VOLATILE_CURSED) LaunchStatusAnimation(battler, B_ANIM_STATUS_CURSED); - else if (status & STATUS2_NIGHTMARE) + else if (status == VOLATILE_NIGHTMARE) LaunchStatusAnimation(battler, B_ANIM_STATUS_NIGHTMARE); else // no animation gBattleSpritesDataPtr->healthBoxesData[battler].statusAnimActive = 0; diff --git a/src/battle_main.c b/src/battle_main.c index 869720c680..22c27ea460 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3117,14 +3117,13 @@ static void BattleStartClearSetData(void) } } -#define UNPACK_VOLATILE_BATON_PASSABLES(_enum, _fieldName, _typeBitSize, ...) __VA_OPT__(if ((FIRST(__VA_ARGS__)) & V_BATON_PASSABLE) gBattleMons[battler].volatiles._fieldName = volatilesCopy._fieldName;) +#define UNPACK_VOLATILE_BATON_PASSABLES(_enum, _fieldName, _typeMaxValue, ...) __VA_OPT__(if ((FIRST(__VA_ARGS__)) & V_BATON_PASSABLE) gBattleMons[battler].volatiles._fieldName = volatilesCopy->_fieldName;) -void SwitchInClearSetData(u32 battler) +void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy) { s32 i; enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); struct DisableStruct disableStructCopy = gDisableStructs[battler]; - struct Volatiles volatilesCopy = gBattleMons[battler].volatiles; ClearIllusionMon(battler); if (effect != EFFECT_BATON_PASS) @@ -3133,8 +3132,8 @@ void SwitchInClearSetData(u32 battler) gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; for (i = 0; i < gBattlersCount; i++) { - if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == battler) - gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; + if (gBattleMons[i].volatiles.escapePrevention && gDisableStructs[i].battlerPreventingEscape == battler) + gBattleMons[i].volatiles.escapePrevention = FALSE; if ((gStatuses3[i] & STATUS3_ALWAYS_HITS) && gDisableStructs[i].battlerWithSureHit == battler) { gStatuses3[i] &= ~STATUS3_ALWAYS_HITS; @@ -3142,15 +3141,17 @@ void SwitchInClearSetData(u32 battler) } } } + + // Clear volatiles - reapply some if Baton Pass was used + memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles)); if (effect == EFFECT_BATON_PASS) { // Transfer Baton Passable volatile statuses - memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles)); VOLATILE_DEFINITIONS(UNPACK_VOLATILE_BATON_PASSABLES) /* Expands to the following (compiler removes `if` statements): - * gBattleMons[battler].volatiles.confusionTurns = volatilesCopy.confusionTurns; - * gBattleMons[battler].volatiles.substitute = volatilesCopy.substitute; - * gBattleMons[battler].volatiles.escapePrevention = volatilesCopy.escapePrevention; + * gBattleMons[battler].volatiles.confusionTurns = volatilesCopy->confusionTurns; + * gBattleMons[battler].volatiles.substitute = volatilesCopy->substitute; + * gBattleMons[battler].volatiles.escapePrevention = volatilesCopy->escapePrevention; * ...etc */ gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED @@ -3172,17 +3173,16 @@ void SwitchInClearSetData(u32 battler) } else { - gBattleMons[battler].status2 = 0; gStatuses3[battler] = 0; gStatuses4[battler] = 0; } for (i = 0; i < gBattlersCount; i++) { - if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(battler)) - gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(battler); - if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && gBattleStruct->wrappedBy[i] == battler) - gBattleMons[i].status2 &= ~STATUS2_WRAPPED; + if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler)) + gBattleMons[i].volatiles.infatuation = 0; + if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler) + gBattleMons[i].volatiles.wrapped = FALSE; if ((gStatuses4[i] & STATUS4_SYRUP_BOMB) && gBattleStruct->stickySyrupdBy[i] == battler) gStatuses4[i] &= ~STATUS4_SYRUP_BOMB; } @@ -3203,7 +3203,7 @@ void SwitchInClearSetData(u32 battler) } else if (effect == EFFECT_SHED_TAIL) { - gBattleMons[battler].status2 |= STATUS2_SUBSTITUTE; + gBattleMons[battler].volatiles.substitute = TRUE; gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP; } @@ -3289,18 +3289,18 @@ const u8* FaintClearSetData(u32 battler) for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; - gBattleMons[battler].status2 = 0; + memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles)); gStatuses3[battler] &= STATUS3_GASTRO_ACID; // Edge case: Keep Gastro Acid if pokemon's ability can have effect after fainting, for example Innards Out. gStatuses4[battler] = 0; for (i = 0; i < gBattlersCount; i++) { - if ((gBattleMons[i].status2 & STATUS2_ESCAPE_PREVENTION) && gDisableStructs[i].battlerPreventingEscape == battler) - gBattleMons[i].status2 &= ~STATUS2_ESCAPE_PREVENTION; - if (gBattleMons[i].status2 & STATUS2_INFATUATED_WITH(battler)) - gBattleMons[i].status2 &= ~STATUS2_INFATUATED_WITH(battler); - if ((gBattleMons[i].status2 & STATUS2_WRAPPED) && gBattleStruct->wrappedBy[i] == battler) - gBattleMons[i].status2 &= ~STATUS2_WRAPPED; + if (gBattleMons[i].volatiles.escapePrevention && gDisableStructs[i].battlerPreventingEscape == battler) + gBattleMons[i].volatiles.escapePrevention = FALSE; + if (gBattleMons[i].volatiles.infatuation == INFATUATED_WITH(battler)) + gBattleMons[i].volatiles.infatuation = 0; + if (gBattleMons[i].volatiles.wrapped && gBattleStruct->wrappedBy[i] == battler) + gBattleMons[i].volatiles.wrapped = FALSE; if ((gStatuses4[i] & STATUS4_SYRUP_BOMB) && gBattleStruct->stickySyrupdBy[i] == battler) gStatuses4[i] &= ~STATUS4_SYRUP_BOMB; } @@ -3403,17 +3403,17 @@ 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].status2 & STATUS2_LOCK_CONFUSE) + if (gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns) { - gBattleMons[otherSkyDropper].status2 &= ~(STATUS2_LOCK_CONFUSE); + gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns = 0; // If the released mon can be confused, do so. // Don't use CanBeConfused here, since it can cause issues in edge cases. if (!(GetBattlerAbility(otherSkyDropper) == ABILITY_OWN_TEMPO - || gBattleMons[otherSkyDropper].status2 & STATUS2_CONFUSION + || gBattleMons[otherSkyDropper].volatiles.confusionTurns || IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN))) { - gBattleMons[otherSkyDropper].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); + gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2; gBattlerAttacker = otherSkyDropper; result = BattleScript_ThrashConfuses; } @@ -3476,7 +3476,7 @@ static void DoBattleIntro(void) gBattleMons[battler].types[2] = TYPE_MYSTERY; gBattleMons[battler].ability = GetAbilityBySpecies(gBattleMons[battler].species, gBattleMons[battler].abilityNum); gBattleStruct->hpOnSwitchout[GetBattlerSide(battler)] = gBattleMons[battler].hp; - gBattleMons[battler].status2 = 0; + memset(&gBattleMons[battler].volatiles, 0, sizeof(struct Volatiles)); for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; #if TESTING @@ -3905,7 +3905,7 @@ static void TryDoEventsBeforeFirstTurn(void) for (i = 0; i < gBattlersCount; i++) { - gBattleMons[i].status2 &= ~STATUS2_FLINCHED; + gBattleMons[i].volatiles.flinched = FALSE; // Record party slots of player's mons that appeared in battle if (!BattlerHasAi(i)) gBattleStruct->appearedInBattle |= 1u << gBattlerPartyIndexes[i]; @@ -3945,8 +3945,8 @@ static void HandleEndTurn_ContinueBattle(void) gBattleCommunication[i] = 0; for (i = 0; i < gBattlersCount; i++) { - gBattleMons[i].status2 &= ~STATUS2_FLINCHED; - if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS)) + gBattleMons[i].volatiles.flinched = FALSE; + if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].volatiles.multipleTurns)) CancelMultiTurnMoves(i, SKY_DROP_IGNORE); } gBattleStruct->eventBlockCounter = 0; @@ -4003,8 +4003,8 @@ void BattleTurnPassed(void) gChosenMoveByBattler[i] = MOVE_NONE; gBattleStruct->monToSwitchIntoId[i] = PARTY_SIZE; gStatuses4[i] &= ~STATUS4_ELECTRIFIED; - gBattleMons[i].status2 &= ~STATUS2_FLINCHED; - gBattleMons[i].status2 &= ~STATUS2_POWDER; + gBattleMons[i].volatiles.flinched = FALSE; + gBattleMons[i].volatiles.powder = FALSE; if (gBattleStruct->battlerState[i].stompingTantrumTimer > 0) gBattleStruct->battlerState[i].stompingTantrumTimer--; @@ -4192,8 +4192,8 @@ static void HandleTurnActionSelectionState(void) } else { - if (gBattleMons[battler].status2 & STATUS2_MULTIPLETURNS - || gBattleMons[battler].status2 & STATUS2_RECHARGE) + if (gBattleMons[battler].volatiles.multipleTurns + || gBattleMons[battler].volatiles.recharge) { gChosenActionByBattler[battler] = B_ACTION_USE_MOVE; gBattleCommunication[battler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY; @@ -4347,8 +4347,8 @@ static void HandleTurnActionSelectionState(void) gBattleCommunication[battler] = STATE_WAIT_SET_BEFORE_ACTION; gBattleCommunication[GetPartnerBattler(battler)] = STATE_BEFORE_ACTION_CHOSEN; RecordedBattle_ClearBattlerAction(battler, 1); - if (gBattleMons[GetPartnerBattler(battler)].status2 & STATUS2_MULTIPLETURNS - || gBattleMons[GetPartnerBattler(battler)].status2 & STATUS2_RECHARGE) + if (gBattleMons[GetPartnerBattler(battler)].volatiles.multipleTurns + || gBattleMons[GetPartnerBattler(battler)].volatiles.recharge) { BtlController_EmitEndBounceEffect(battler, B_COMM_TO_CONTROLLER); MarkBattlerForControllerExec(battler); @@ -4740,9 +4740,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect h speed *= 2; else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0) speed /= 2; - else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battler].boosterEnergyActivated)) + else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].volatiles.transformed) && ((gBattleWeather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battler].boosterEnergyActivated)) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; - else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivated)) + else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].volatiles.transformed) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivated)) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; else if (ability == ABILITY_UNBURDEN && gDisableStructs[battler].unburdenActive) speed *= 2; @@ -4762,7 +4762,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, enum ItemHoldEffect h speed /= 2; else if (holdEffect == HOLD_EFFECT_CHOICE_SCARF && GetActiveGimmick(battler) != GIMMICK_DYNAMAX) speed = (speed * 150) / 100; - else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battler].species == SPECIES_DITTO && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + else if (holdEffect == HOLD_EFFECT_QUICK_POWDER && gBattleMons[battler].species == SPECIES_DITTO && !(gBattleMons[battler].volatiles.transformed)) speed *= 2; // various effects @@ -5108,13 +5108,13 @@ static void TurnValuesCleanUp(bool8 var0) { gDisableStructs[i].rechargeTimer--; if (gDisableStructs[i].rechargeTimer == 0) - gBattleMons[i].status2 &= ~STATUS2_RECHARGE; + gBattleMons[i].volatiles.recharge = FALSE; } gBattleStruct->battlerState[i].canPickupItem = FALSE; } if (gDisableStructs[i].substituteHP == 0) - gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + gBattleMons[i].volatiles.substitute = FALSE; if (!(gStatuses3[i] & STATUS3_COMMANDER)) gBattleStruct->battlerState[i].commandingDondozo = FALSE; diff --git a/src/battle_message.c b/src/battle_message.c index 6be243ba51..9027d5a36e 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -1379,11 +1379,6 @@ const u16 gStatusConditionsStringIds[] = STRINGID_PKMNWASPOISONED, STRINGID_PKMNBADLYPOISONED, STRINGID_PKMNWASBURNED, STRINGID_PKMNWASPARALYZED, STRINGID_PKMNFELLASLEEP, STRINGID_PKMNGOTFROSTBITE }; -const u16 gStatus2StringIds[] = -{ - STRINGID_PKMNWASCONFUSED, STRINGID_PKMNFELLINLOVE, STRINGID_TARGETCANTESCAPENOW, STRINGID_PKMNSUBJECTEDTOTORMENT -}; - const u16 gDamageNonTypesStartStringIds[] = { [B_MSG_TRAPPED_WITH_VINES] = STRINGID_TEAMTRAPPEDWITHVINES, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index c0842af259..a50fb27956 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -449,8 +449,8 @@ static void Cmd_drawpartystatussummary(void); static void Cmd_hidepartystatussummary(void); static void Cmd_jumptocalledmove(void); static void Cmd_statusanimation(void); -static void Cmd_status2animation(void); -static void Cmd_chosenstatusanimation(void); +static void Cmd_unused_0x65(void); +static void Cmd_unused_0x66(void); static void Cmd_yesnobox(void); static void Cmd_cancelallactions(void); static void Cmd_setgravity(void); @@ -525,7 +525,7 @@ static void Cmd_tryspiteppreduce(void); static void Cmd_healpartystatus(void); static void Cmd_cursetarget(void); static void Cmd_trysetspikes(void); -static void Cmd_setforesight(void); +static void Cmd_setvolatile(void); static void Cmd_trysetperishsong(void); static void Cmd_handlerollout(void); static void Cmd_jumpifconfusedandstatmaxed(void); @@ -539,7 +539,7 @@ static void Cmd_tryrestorehpberry(void); static void Cmd_halvehp(void); static void Cmd_copyfoestats(void); static void Cmd_rapidspinfree(void); -static void Cmd_setdefensecurlbit(void); +static void Cmd_unused_0xBF(void); static void Cmd_recoverbasedonsunlight(void); static void Cmd_setstickyweb(void); static void Cmd_selectfirstvalidtarget(void); @@ -708,8 +708,8 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_hidepartystatussummary, //0x62 Cmd_jumptocalledmove, //0x63 Cmd_statusanimation, //0x64 - Cmd_status2animation, //0x65 - Cmd_chosenstatusanimation, //0x66 + Cmd_unused_0x65, //0x65 + Cmd_unused_0x66, //0x66 Cmd_yesnobox, //0x67 Cmd_cancelallactions, //0x68 Cmd_setgravity, //0x69 @@ -784,7 +784,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_healpartystatus, //0xAE Cmd_cursetarget, //0xAF Cmd_trysetspikes, //0xB0 - Cmd_setforesight, //0xB1 + Cmd_setvolatile, //0xB1 Cmd_trysetperishsong, //0xB2 Cmd_handlerollout, //0xB3 Cmd_jumpifconfusedandstatmaxed, //0xB4 @@ -798,7 +798,7 @@ void (*const gBattleScriptingCommandsTable[])(void) = Cmd_halvehp, //0xBC Cmd_copyfoestats, //0xBD Cmd_rapidspinfree, //0xBE - Cmd_setdefensecurlbit, //0xBF + Cmd_unused_0xBF, //0xBF Cmd_recoverbasedonsunlight, //0xC0 Cmd_setstickyweb, //0xC1 Cmd_selectfirstvalidtarget, //0xC2 @@ -1137,9 +1137,9 @@ u32 NumAffectedSpreadMoveTargets(void) u32 NumFaintedBattlersByAttacker(u32 battlerAtk) { - u32 numMonsFainted = 0; + u32 battler, numMonsFainted = 0; - for (u32 battler = 0; battler < gBattlersCount; battler++) + for (battler = 0; battler < gBattlersCount; battler++) { if (battler == battlerAtk) continue; @@ -1268,7 +1268,7 @@ static void Cmd_attackcanceler(void) if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE && !(gHitMarker & (HITMARKER_ALLOW_NO_PP | HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT)) - && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) + && !(gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) { gBattlescriptCurrInstr = BattleScript_NoPPForMove; gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; @@ -1279,7 +1279,7 @@ static void Cmd_attackcanceler(void) // Check if no available target present on the field or if Sky Battles ban the move if ((NoTargetPresent(gBattlerAttacker, gCurrentMove) - && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) + && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) || (IsMoveNotAllowedInSkyBattles(gCurrentMove))) { gBattleStruct->noTargetPresent = TRUE; @@ -1289,7 +1289,7 @@ static void Cmd_attackcanceler(void) else gBattlescriptCurrInstr = BattleScript_FailedFromAtkString; - if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) + if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); return; } @@ -1354,7 +1354,8 @@ static void Cmd_attackcanceler(void) return; } - for (u32 i = 0; i < gBattlersCount; i++) + u32 i; + for (i = 0; i < gBattlersCount; i++) { if ((gProtectStructs[gBattlerByTurnOrder[i]].stealMove) && MoveCanBeSnatched(gCurrentMove)) { @@ -1382,7 +1383,7 @@ static void Cmd_attackcanceler(void) } else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) && (effect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) - && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) + && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) && effect != EFFECT_SUCKER_PUNCH && effect != EFFECT_COUNTER && effect != EFFECT_UPPER_HAND) @@ -1504,13 +1505,14 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u } else { - u32 numTargets = 0; - u32 numMisses = 0; - u32 moveType = GetBattleMoveType(move); - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); + u32 battlerDef, + numTargets = 0, + numMisses = 0, + moveType = GetBattleMoveType(move), + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); bool32 calcSpreadMove = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(move); - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { if (gBattleStruct->calculatedSpreadMoveAccuracy) break; @@ -1624,7 +1626,7 @@ static void Cmd_ppreduce(void) if (gBattleControllerExecFlags) return; - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS) + if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns) gHitMarker |= HITMARKER_NO_PPDEDUCT; if (moveTarget == MOVE_TARGET_BOTH @@ -1739,8 +1741,8 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA } else { - critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0) - + 1 * ((gBattleMons[battlerAtk].status2 & STATUS2_DRAGON_CHEER) != 0) + critChance = 2 * (gBattleMons[battlerAtk].volatiles.focusEnergy != 0) + + 1 * (gBattleMons[battlerAtk].volatiles.dragonCheer != 0) + GetMoveCriticalHitStage(move) + GetHoldEffectCritChanceIncrease(battlerAtk, holdEffectAtk) + 2 * (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(battlerAtk) == AFFECTION_FIVE_HEARTS) @@ -1789,9 +1791,9 @@ s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec if (bonusCritStage > 0) critChance *= bonusCritStage; - if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) + if (gBattleMons[battlerAtk].volatiles.focusEnergy) critChance *= 4; - else if (gBattleMons[battlerAtk].status2 & STATUS2_DRAGON_CHEER) + else if (gBattleMons[battlerAtk].volatiles.dragonCheer) critChance *= 2; if (holdEffectCritStage > 0) @@ -1836,14 +1838,15 @@ static void Cmd_critcalc(void) { CMD_ARGS(); - u32 partySlot = gBattlerPartyIndexes[gBattlerAttacker]; - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); + u32 partySlot = gBattlerPartyIndexes[gBattlerAttacker], + moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove), + abilityAtk = GetBattlerAbility(gBattlerAttacker), + battlerDef; bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(gCurrentMove); - u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); gPotentialItemEffectBattler = gBattlerAttacker; - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { if (gBattleStruct->calculatedDamageDone) break; @@ -2120,7 +2123,7 @@ static inline bool32 DoesBattlerNegateDamage(u32 battler) u32 species = gBattleMons[battler].species; u32 ability = GetBattlerAbility(battler); - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gBattleMons[battler].volatiles.transformed) return FALSE; if (ability == ABILITY_DISGUISE && species == SPECIES_MIMIKYU) return TRUE; @@ -2307,7 +2310,7 @@ static void Cmd_attackanimation(void) if (!(moveResultFlags & MOVE_RESULT_NO_EFFECT)) { u32 multihit; - if (gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE) + if (gBattleMons[gBattlerTarget].volatiles.substitute) { multihit = gMultiHitCounter; } @@ -3138,20 +3141,20 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai break; case MOVE_EFFECT_CONFUSION: if (!CanBeConfused(gEffectBattler) - || gBattleMons[gEffectBattler].status2 & STATUS2_CONFUSION + || gBattleMons[gEffectBattler].volatiles.confusionTurns || (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary)) { gBattlescriptCurrInstr++; } else { - gBattleMons[gEffectBattler].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); // 2-5 turns + gBattleMons[gEffectBattler].volatiles.confusionTurns = ((Random()) % 4) + 2; // 2-5 turns // If the confusion is activating due to being released from Sky Drop, go to "confused due to fatigue" script. // Otherwise, do normal confusion script. if (GetMoveEffect(gCurrentMove) == EFFECT_SKY_DROP) { - gBattleMons[gEffectBattler].status2 &= ~(STATUS2_LOCK_CONFUSE); + gBattleMons[gEffectBattler].volatiles.lockConfusionTurns = 0; gBattlerAttacker = gEffectBattler; gBattlescriptCurrInstr = BattleScript_ThrashConfuses; } @@ -3179,14 +3182,14 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai gBattlescriptCurrInstr++; } } - else if (gBattleMons[gEffectBattler].status2 & STATUS2_FLINCHED) + else if (gBattleMons[gEffectBattler].volatiles.flinched) { gBattlescriptCurrInstr++; } else if (GetBattlerTurnOrderNum(gEffectBattler) > gCurrentTurnActionNumber && !(GetActiveGimmick(gEffectBattler) == GIMMICK_DYNAMAX)) { - gBattleMons[gEffectBattler].status2 |= STATUS2_FLINCHED; + gBattleMons[gEffectBattler].volatiles.flinched = TRUE; gBattlescriptCurrInstr++; } else @@ -3195,11 +3198,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } break; case MOVE_EFFECT_UPROAR: - if (!(gBattleMons[gEffectBattler].status2 & STATUS2_UPROAR)) + if (!gBattleMons[gEffectBattler].volatiles.uproarTurns) { - gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS; + gBattleMons[gEffectBattler].volatiles.multipleTurns = TRUE; gLockedMoves[gEffectBattler] = gCurrentMove; - gBattleMons[gEffectBattler].status2 |= STATUS2_UPROAR_TURN(B_UPROAR_TURNS >= GEN_5 ? 3 : (Random() & 3) + 2); + gBattleMons[gEffectBattler].volatiles.uproarTurns = B_UPROAR_TURNS >= GEN_5 ? 3 : (Random() & 3) + 2; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_MoveEffectUproar; @@ -3260,13 +3263,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } break; case MOVE_EFFECT_WRAP: - if (gBattleMons[gEffectBattler].status2 & STATUS2_WRAPPED) + if (gBattleMons[gEffectBattler].volatiles.wrapped) { gBattlescriptCurrInstr++; } else { - gBattleMons[gEffectBattler].status2 |= STATUS2_WRAPPED; + gBattleMons[gEffectBattler].volatiles.wrapped = TRUE; if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_GRIP_CLAW) gDisableStructs[gEffectBattler].wrapTurns = B_BINDING_TURNS >= GEN_5 ? 7 : 5; else @@ -3401,13 +3404,13 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai if (B_SKIP_RECHARGE == GEN_1 && !IsBattlerAlive(gBattlerTarget)) // Skip recharge if gen 1 and foe is KO'd break; - gBattleMons[gEffectBattler].status2 |= STATUS2_RECHARGE; + gBattleMons[gEffectBattler].volatiles.recharge = TRUE; gDisableStructs[gEffectBattler].rechargeTimer = 2; gLockedMoves[gEffectBattler] = gCurrentMove; gBattlescriptCurrInstr++; break; case MOVE_EFFECT_RAGE: - gBattleMons[gBattlerAttacker].status2 |= STATUS2_RAGE; + gBattleMons[gBattlerAttacker].volatiles.rage = TRUE; gBattlescriptCurrInstr++; break; case MOVE_EFFECT_STEAL_ITEM: @@ -3440,15 +3443,15 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } break; case MOVE_EFFECT_PREVENT_ESCAPE: - if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION)) + if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) { - gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE; gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; } gBattlescriptCurrInstr++; break; case MOVE_EFFECT_NIGHTMARE: - gBattleMons[gBattlerTarget].status2 |= STATUS2_NIGHTMARE; + gBattleMons[gBattlerTarget].volatiles.nightmare = TRUE; gBattlescriptCurrInstr++; break; case MOVE_EFFECT_ALL_STATS_UP: @@ -3484,15 +3487,15 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai break; case MOVE_EFFECT_THRASH: // Petal Dance doesn't lock mons that copy the move with Dancer - if (gSpecialStatuses[gEffectBattler].dancerUsedMove || gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE) + if (gSpecialStatuses[gEffectBattler].dancerUsedMove || gBattleMons[gEffectBattler].volatiles.lockConfusionTurns) { gBattlescriptCurrInstr++; } else { - gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS; + gBattleMons[gEffectBattler].volatiles.multipleTurns = TRUE; gLockedMoves[gEffectBattler] = gCurrentMove; - gBattleMons[gEffectBattler].status2 |= STATUS2_LOCK_CONFUSE_TURN(RandomUniform(RNG_RAMPAGE_TURNS, 2, 3)); + gBattleMons[gEffectBattler].volatiles.lockConfusionTurns = RandomUniform(RNG_RAMPAGE_TURNS, 2, 3); } break; case MOVE_EFFECT_CLEAR_SMOG: @@ -3597,19 +3600,19 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai } break; case MOVE_EFFECT_TRAP_BOTH: - if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_ESCAPE_PREVENTION)) + if (!(gBattleMons[gBattlerTarget].volatiles.escapePrevention || gBattleMons[gBattlerAttacker].volatiles.escapePrevention)) { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_BothCanNoLongerEscape; } - if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION)) + if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_ESCAPE_PREVENTION)) + if (!gBattleMons[gBattlerAttacker].volatiles.escapePrevention) gDisableStructs[gBattlerAttacker].battlerPreventingEscape = gBattlerTarget; - gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; - gBattleMons[gBattlerAttacker].status2 |= STATUS2_ESCAPE_PREVENTION; + gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE; + gBattleMons[gBattlerAttacker].volatiles.escapePrevention = TRUE; break; case MOVE_EFFECT_REMOVE_ARG_TYPE: { @@ -3893,7 +3896,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) gBattleMons[gBattlerTarget].pp[i] -= ppToDeduct; if (!(gDisableStructs[gBattlerTarget].mimickedMoves & (1u << i)) - && !(gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[gBattlerTarget].volatiles.transformed)) { BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[gBattlerTarget].pp[i]), &gBattleMons[gBattlerTarget].pp[i]); MarkBattlerForControllerExec(gBattlerTarget); @@ -4128,9 +4131,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai { if (!IsBattlerAlly(battler, gBattlerTarget)) continue; - if (!(gBattleMons[battler].status2 & STATUS2_WRAPPED)) + if (!gBattleMons[battler].volatiles.wrapped) { - gBattleMons[battler].status2 |= STATUS2_WRAPPED; + gBattleMons[battler].volatiles.wrapped = TRUE; if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_GRIP_CLAW) gDisableStructs[battler].wrapTurns = (B_BINDING_TURNS >= GEN_5) ? 7 : 5; else @@ -4539,12 +4542,12 @@ static void Cmd_jumpifstatus(void) static void Cmd_jumpifvolatile(void) { - CMD_ARGS(u8 battler, u8 volatileStatus, const u8 *jumpInstr); + CMD_ARGS(u8 battler, u8 _volatile, const u8 *jumpInstr); u8 battler = GetBattlerForBattleScript(cmd->battler); const u8 *jumpInstr = cmd->jumpInstr; - if (GetMonVolatile(battler, cmd->volatileStatus) && IsBattlerAlive(battler)) + if (GetMonVolatile(battler, cmd->_volatile) && IsBattlerAlive(battler)) gBattlescriptCurrInstr = jumpInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -6119,7 +6122,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_RAGE: // rage check - if (gBattleMons[gBattlerTarget].status2 & STATUS2_RAGE + if (gBattleMons[gBattlerTarget].volatiles.rage && IsBattlerAlive(gBattlerTarget) && gBattlerAttacker != gBattlerTarget && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) @@ -6313,7 +6316,7 @@ static void Cmd_moveend(void) for (i = 0; i < gBattlersCount; i++) { if (gDisableStructs[i].substituteHP == 0) - gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + gBattleMons[i].volatiles.substitute = FALSE; } gBattleScripting.moveendState++; break; @@ -6348,7 +6351,7 @@ static void Cmd_moveend(void) if (!IsOnPlayerSide(gBattlerAttacker)) UpdateStallMons(); if ((gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE)) - || (gBattleMons[gBattlerAttacker].status2 & (STATUS2_FLINCHED)) + || (gBattleMons[gBattlerAttacker].volatiles.flinched) || gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility) gBattleStruct->battlerState[gBattlerAttacker].stompingTantrumTimer = 2; @@ -7050,7 +7053,7 @@ static void Cmd_moveend(void) if (B_RAMPAGE_CANCELLING >= GEN_5 && MoveHasAdditionalEffectSelf(gCurrentMove, MOVE_EFFECT_THRASH) // If we're rampaging && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT // And it is unusable - && (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn + && gBattleMons[gBattlerAttacker].volatiles.lockConfusionTurns != 1) // And won't end this turn CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it if (gBattleStruct->savedAttackerCount > 0) @@ -7320,10 +7323,9 @@ static void Cmd_switchindataupdate(void) { gBattleMons[battler].statStages[i] = oldData.statStages[i]; } - gBattleMons[battler].status2 = oldData.status2; } - SwitchInClearSetData(battler); + SwitchInClearSetData(battler, &oldData.volatiles); if (gBattleTypeFlags & BATTLE_TYPE_PALACE && gBattleMons[battler].maxHP / 2 >= gBattleMons[battler].hp @@ -7843,7 +7845,7 @@ static void UpdateSentMonFlags(u32 battler) static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId) { - gBattleMons[battler].status2 &= ~STATUS2_DESTINY_BOND; + gBattleMons[battler].volatiles.destinyBond = FALSE; gHitMarker &= ~HITMARKER_DESTINYBOND; gBattleScripting.battler = battler; gBattleCommunication[MULTISTRING_CHOOSER] = multistringId; @@ -8220,7 +8222,7 @@ static void Cmd_handlelearnnewmove(void) u32 battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); if (gBattlerPartyIndexes[battler] == monId - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[battler].volatiles.transformed)) { GiveMoveToBattleMon(&gBattleMons[battler], learnMove); } @@ -8228,7 +8230,7 @@ static void Cmd_handlelearnnewmove(void) { battler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); if (gBattlerPartyIndexes[battler] == monId - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[battler].volatiles.transformed)) { GiveMoveToBattleMon(&gBattleMons[battler], learnMove); } @@ -8643,58 +8645,29 @@ static void Cmd_jumptocalledmove(void) static void Cmd_statusanimation(void) { - CMD_ARGS(u8 battler); + CMD_ARGS(u8 battler, u32 status, bool8 isVolatile); if (gBattleControllerExecFlags == 0) { - u32 battler = GetBattlerForBattleScript(cmd->battler); + u32 battler = GetBattlerForBattleScript(cmd->battler), + statusFlag = (cmd->isVolatile || cmd->status) ? cmd->status : gBattleMons[battler].status1; if (!(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE) && gDisableStructs[battler].substituteHP == 0 && !(gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION))) { - BtlController_EmitStatusAnimation(battler, B_COMM_TO_CONTROLLER, FALSE, gBattleMons[battler].status1); + BtlController_EmitStatusAnimation(battler, B_COMM_TO_CONTROLLER, cmd->isVolatile, statusFlag); MarkBattlerForControllerExec(battler); } gBattlescriptCurrInstr = cmd->nextInstr; } } -static void Cmd_status2animation(void) +static void Cmd_unused_0x65(void) { - CMD_ARGS(u8 battler, u32 status2); - - if (gBattleControllerExecFlags == 0) - { - u32 battler = GetBattlerForBattleScript(cmd->battler); - u32 status2ToAnim = cmd->status2; - if (!(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE) - && gDisableStructs[battler].substituteHP == 0 - && !(gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION))) - { - BtlController_EmitStatusAnimation(battler, B_COMM_TO_CONTROLLER, TRUE, gBattleMons[battler].status2 & status2ToAnim); - MarkBattlerForControllerExec(battler); - } - gBattlescriptCurrInstr = cmd->nextInstr; - } } -static void Cmd_chosenstatusanimation(void) +static void Cmd_unused_0x66(void) { - CMD_ARGS(u8 battler, bool8 isStatus2, u32 status); - - if (gBattleControllerExecFlags == 0) - { - u32 battler = GetBattlerForBattleScript(cmd->battler); - u32 wantedStatus = cmd->status; - if (!(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE) - && gDisableStructs[battler].substituteHP == 0 - && !(gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION))) - { - BtlController_EmitStatusAnimation(battler, B_COMM_TO_CONTROLLER, cmd->isStatus2, wantedStatus); - MarkBattlerForControllerExec(battler); - } - gBattlescriptCurrInstr = cmd->nextInstr; - } } static void Cmd_yesnobox(void) @@ -9454,13 +9427,13 @@ static bool32 TryTidyUpClear(u32 battlerAtk, bool32 clear) for (i = 0; i < MAX_BATTLERS_COUNT; i++) { - if (gBattleMons[i].status2 & STATUS2_SUBSTITUTE) + if (gBattleMons[i].volatiles.substitute) { if (clear) { gBattlerTarget = i; gDisableStructs[i].substituteHP = 0; - gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; + gBattleMons[i].volatiles.substitute = FALSE; BattleScriptCall(BattleScript_SubstituteFade); } gBattlerAttacker = saveBattler; @@ -9799,7 +9772,7 @@ static void Cmd_various(void) { VARIOUS_ARGS(u8 infatuateWith); gBattleScripting.battler = battler; - gBattleMons[battler].status2 |= STATUS2_INFATUATED_WITH(GetBattlerForBattleScript(cmd->infatuateWith)); + gBattleMons[battler].volatiles.infatuation = INFATUATED_WITH(GetBattlerForBattleScript(cmd->infatuateWith)); gBattlescriptCurrInstr = cmd->nextInstr; return; } @@ -9939,12 +9912,6 @@ static void Cmd_various(void) gStatuses3[battler] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS | STATUS3_ON_AIR | STATUS3_SKY_DROPPED); break; } - case VARIOUS_SET_POWDER: - { - VARIOUS_ARGS(); - gBattleMons[battler].status2 |= STATUS2_POWDER; - break; - } case VARIOUS_ACUPRESSURE: { VARIOUS_ARGS(const u8 *failInstr); @@ -10953,10 +10920,10 @@ static void Cmd_various(void) gBattleStruct->skyDropTargets[gBattlerAttacker] = gBattlerTarget; gBattleStruct->skyDropTargets[gBattlerTarget] = gBattlerAttacker; - // End any multiturn effects caused by the target except STATUS2_LOCK_CONFUSE - gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_MULTIPLETURNS); - gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_UPROAR); - gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_BIDE); + // End any multiturn effects caused by the target except VOLATILE_LOCK_CONFUSE + gBattleMons[gBattlerTarget].volatiles.multipleTurns = 0; + gBattleMons[gBattlerTarget].volatiles.uproarTurns= 0; + gBattleMons[gBattlerTarget].volatiles.bideTurns = 0; gDisableStructs[gBattlerTarget].rolloutTimer = 0; gDisableStructs[gBattlerTarget].furyCutterCounter = 0; @@ -10982,7 +10949,7 @@ static void Cmd_various(void) } // Confuse target if they were in the middle of Petal Dance/Outrage/Thrash when targeted. - if (gBattleMons[gBattlerTarget].status2 & STATUS2_LOCK_CONFUSE) + if (gBattleMons[gBattlerTarget].volatiles.lockConfusionTurns) gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; return; } @@ -10999,11 +10966,11 @@ static void Cmd_various(void) gBattleStruct->skyDropTargets[gEffectBattler] = SKY_DROP_NO_TARGET; // If the target was in the middle of Outrage/Thrash/etc. when targeted by Sky Drop, confuse them on release and do proper animation - if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE && CanBeConfused(gEffectBattler)) + if (gBattleMons[gEffectBattler].volatiles.lockConfusionTurns && CanBeConfused(gEffectBattler)) { - gBattleMons[gEffectBattler].status2 &= ~(STATUS2_LOCK_CONFUSE); + gBattleMons[gEffectBattler].volatiles.lockConfusionTurns = 0; gBattlerAttacker = gEffectBattler; - gBattleMons[gBattlerTarget].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); + gBattleMons[gBattlerTarget].volatiles.confusionTurns = ((Random()) % 4) + 2; gBattlescriptCurrInstr = BattleScript_ThrashConfuses; return; } @@ -11225,7 +11192,7 @@ static void Cmd_various(void) } else { - if (!(gBattleMons[battler].status2 & STATUS2_ESCAPE_PREVENTION)) + if (!gBattleMons[battler].volatiles.escapePrevention) gDisableStructs[battler].noRetreat = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -11235,9 +11202,9 @@ static void Cmd_various(void) { VARIOUS_ARGS(); // Check infatuation - if (gBattleMons[battler].status2 & STATUS2_INFATUATION) + if (gBattleMons[battler].volatiles.infatuation) { - gBattleMons[battler].status2 &= ~(STATUS2_INFATUATION); + gBattleMons[battler].volatiles.infatuation = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); } @@ -11256,9 +11223,9 @@ static void Cmd_various(void) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED } // Check torment - if (gBattleMons[battler].status2 & STATUS2_TORMENT) + if (gBattleMons[battler].volatiles.torment == TRUE) { - gBattleMons[battler].status2 &= ~(STATUS2_TORMENT); + gBattleMons[battler].volatiles.torment = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; } // Check heal block @@ -11673,7 +11640,7 @@ bool8 UproarWakeUpCheck(u8 battler) for (i = 0; i < gBattlersCount; i++) { - if (!(gBattleMons[i].status2 & STATUS2_UPROAR) || hasSoundproof) + if (!(gBattleMons[i].volatiles.uproarTurns) || hasSoundproof) continue; gBattleScripting.battler = i; @@ -12317,10 +12284,10 @@ static void Cmd_setbide(void) { CMD_ARGS(); - gBattleMons[gBattlerAttacker].status2 |= STATUS2_MULTIPLETURNS; + gBattleMons[gBattlerAttacker].volatiles.multipleTurns = TRUE; gLockedMoves[gBattlerAttacker] = gCurrentMove; gBideDmg[gBattlerAttacker] = 0; - gBattleMons[gBattlerAttacker].status2 |= STATUS2_BIDE_TURN(2); + gBattleMons[gBattlerAttacker].volatiles.bideTurns = 2; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -12838,14 +12805,14 @@ static void Cmd_tryinfatuating(void) } else { - if (gBattleMons[gBattlerTarget].status2 & STATUS2_INFATUATION + if (gBattleMons[gBattlerTarget].volatiles.infatuation || !AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; } else { - gBattleMons[gBattlerTarget].status2 |= STATUS2_INFATUATED_WITH(gBattlerAttacker); + gBattleMons[gBattlerTarget].volatiles.infatuation = INFATUATED_WITH(gBattlerAttacker); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -12865,7 +12832,7 @@ static void Cmd_updatestatusicon(void) { if (!(gAbsentBattlerFlags & (1u << battler))) { - BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1, gBattleMons[battler].status2); + BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1); MarkBattlerForControllerExec(battler); } } @@ -12876,7 +12843,7 @@ static void Cmd_updatestatusicon(void) battler = gBattlerAttacker; if (!(gAbsentBattlerFlags & (1u << battler))) { - BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1, gBattleMons[battler].status2); + BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1); MarkBattlerForControllerExec(battler); } if ((IsDoubleBattle())) @@ -12884,7 +12851,7 @@ static void Cmd_updatestatusicon(void) battler = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerAttacker))); if (!(gAbsentBattlerFlags & (1u << battler))) { - BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1, gBattleMons[battler].status2); + BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1); MarkBattlerForControllerExec(battler); } } @@ -12893,7 +12860,7 @@ static void Cmd_updatestatusicon(void) else { battler = GetBattlerForBattleScript(cmd->battler); - BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1, gBattleMons[battler].status2); + BtlController_EmitStatusIconUpdate(battler, B_COMM_TO_CONTROLLER, gBattleMons[battler].status1); MarkBattlerForControllerExec(battler); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -12924,22 +12891,22 @@ static void Cmd_setfocusenergy(void) enum BattleMoveEffects effect = GetMoveEffect(gCurrentMove); if ((effect == EFFECT_DRAGON_CHEER && (!(IsDoubleBattle()) || (gAbsentBattlerFlags & (1u << battler)))) - || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) + || gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) { gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_FAILED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FOCUS_ENERGY_FAILED; } else if (effect == EFFECT_DRAGON_CHEER && !IS_BATTLER_OF_TYPE(battler, TYPE_DRAGON)) { - gBattleMons[battler].status2 |= STATUS2_DRAGON_CHEER; + gBattleMons[battler].volatiles.dragonCheer = TRUE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED; } else { if (GetGenConfig(GEN_CONFIG_FOCUS_ENERGY_CRIT_RATIO) >= GEN_3) - gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; + gBattleMons[battler].volatiles.focusEnergy = TRUE; else - gBattleMons[battler].status2 |= STATUS2_DRAGON_CHEER; + gBattleMons[battler].volatiles.dragonCheer = TRUE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -12951,7 +12918,7 @@ static void Cmd_transformdataexecution(void) gChosenMove = MOVE_UNAVAILABLE; gBattlescriptCurrInstr = cmd->nextInstr; - if (gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED + if (gBattleMons[gBattlerTarget].volatiles.transformed || gBattleStruct->illusion[gBattlerTarget].state == ILLUSION_ON || gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER) { @@ -12964,7 +12931,7 @@ static void Cmd_transformdataexecution(void) u8 *battleMonAttacker, *battleMonTarget; u8 timesGotHit; - gBattleMons[gBattlerAttacker].status2 |= STATUS2_TRANSFORMED; + gBattleMons[gBattlerAttacker].volatiles.transformed = TRUE; gDisableStructs[gBattlerAttacker].disabledMove = MOVE_NONE; gDisableStructs[gBattlerAttacker].disableTimer = 0; gDisableStructs[gBattlerAttacker].transformedMonPersonality = gBattleMons[gBattlerTarget].personality; @@ -13029,8 +12996,8 @@ static void Cmd_setsubstitute(void) if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) gBattleStruct->moveDamage[gBattlerAttacker] = 1; - gBattleMons[gBattlerAttacker].status2 |= STATUS2_SUBSTITUTE; - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_WRAPPED; + gBattleMons[gBattlerAttacker].volatiles.substitute = TRUE; + gBattleMons[gBattlerAttacker].volatiles.wrapped = FALSE; if (factor == 2) gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker] / 2; else @@ -13047,7 +13014,7 @@ static void Cmd_mimicattackcopy(void) CMD_ARGS(const u8 *failInstr); if ((IsMoveMimicBanned(gLastMoves[gBattlerTarget])) - || (gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED) + || (gBattleMons[gBattlerAttacker].volatiles.transformed) || gLastMoves[gBattlerTarget] == MOVE_NONE || gLastMoves[gBattlerTarget] == MOVE_UNAVAILABLE) { @@ -13296,7 +13263,7 @@ static void Cmd_settypetorandomresistance(void) gBattlescriptCurrInstr = cmd->failInstr; } else if (gBattleMoveEffects[GetMoveEffect(gLastLandedMoves[gBattlerAttacker])].twoTurnEffect - && gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS) + && gBattleMons[gLastHitBy[gBattlerAttacker]].volatiles.multipleTurns) { gBattlescriptCurrInstr = cmd->failInstr; } @@ -13422,7 +13389,7 @@ static void Cmd_copymovepermanently(void) gChosenMove = MOVE_UNAVAILABLE; - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED) + if (!(gBattleMons[gBattlerAttacker].volatiles.transformed) && gLastPrintedMoves[gBattlerTarget] != MOVE_UNAVAILABLE && !IsMoveSketchBanned(gLastPrintedMoves[gBattlerTarget])) { @@ -13541,14 +13508,14 @@ static void Cmd_trysetdestinybond(void) } else { - gBattleMons[gBattlerAttacker].status2 |= STATUS2_DESTINY_BOND; + gBattleMons[gBattlerAttacker].volatiles.destinyBond = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; } } static void TrySetDestinyBondToHappen(void) { - if (gBattleMons[gBattlerTarget].status2 & STATUS2_DESTINY_BOND + if (gBattleMons[gBattlerTarget].volatiles.destinyBond && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget) && !(gHitMarker & HITMARKER_GRUDGE)) { @@ -13629,7 +13596,7 @@ static void Cmd_tryspiteppreduce(void) // if (MOVE_IS_PERMANENT(gBattlerTarget, i)), but backwards if (!(gDisableStructs[gBattlerTarget].mimickedMoves & (1u << i)) - && !(gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[gBattlerTarget].volatiles.transformed)) { BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[gBattlerTarget].pp[i]), &gBattleMons[gBattlerTarget].pp[i]); MarkBattlerForControllerExec(gBattlerTarget); @@ -13672,7 +13639,7 @@ static void Cmd_healpartystatus(void) else gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SOOTHING_AROMA; gBattleMons[gBattlerAttacker].status1 = 0; - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE; } else { @@ -13688,7 +13655,7 @@ static void Cmd_healpartystatus(void) || !(isSoundMove && GetBattlerAbility(partner) == ABILITY_SOUNDPROOF)) { gBattleMons[partner].status1 = 0; - gBattleMons[partner].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[partner].volatiles.nightmare = FALSE; } else { @@ -13753,13 +13720,13 @@ static void Cmd_cursetarget(void) { CMD_ARGS(const u8 *failInstr); - if (gBattleMons[gBattlerTarget].status2 & STATUS2_CURSED) + if (gBattleMons[gBattlerTarget].volatiles.cursed) { gBattlescriptCurrInstr = cmd->failInstr; } else { - gBattleMons[gBattlerTarget].status2 |= STATUS2_CURSED; + gBattleMons[gBattlerTarget].volatiles.cursed = TRUE; gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) gBattleStruct->moveDamage[gBattlerAttacker] = 1; @@ -13787,11 +13754,11 @@ static void Cmd_trysetspikes(void) } } -static void Cmd_setforesight(void) +static void Cmd_setvolatile(void) { - CMD_ARGS(); + CMD_ARGS(u8 battler, u8 _volatile, u8 value); - gBattleMons[gBattlerTarget].status2 |= STATUS2_FORESIGHT; + SetMonVolatile(GetBattlerForBattleScript(cmd->battler), cmd->_volatile, cmd->value); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -13835,16 +13802,16 @@ static void Cmd_handlerollout(void) } else { - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) // First hit. + if (!(gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) // First hit. { gDisableStructs[gBattlerAttacker].rolloutTimer = 5; gDisableStructs[gBattlerAttacker].rolloutTimerStartValue = 5; - gBattleMons[gBattlerAttacker].status2 |= STATUS2_MULTIPLETURNS; + gBattleMons[gBattlerAttacker].volatiles.multipleTurns = TRUE; gLockedMoves[gBattlerAttacker] = gCurrentMove; } if (--gDisableStructs[gBattlerAttacker].rolloutTimer == 0) // Last hit. { - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_MULTIPLETURNS; + gBattleMons[gBattlerAttacker].volatiles.multipleTurns = FALSE; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -13855,7 +13822,7 @@ static void Cmd_jumpifconfusedandstatmaxed(void) { CMD_ARGS(u8 stat, const u8 *jumpInstr); - if (gBattleMons[gBattlerTarget].status2 & STATUS2_CONFUSION + if (gBattleMons[gBattlerTarget].volatiles.confusionTurns > 0 && !CompareStat(gBattlerTarget, cmd->stat, MAX_STAT_STAGE, CMP_LESS_THAN)) gBattlescriptCurrInstr = cmd->jumpInstr; // Fails if we're confused AND stat cannot be raised else @@ -14130,10 +14097,10 @@ static void Cmd_rapidspinfree(void) u8 atkSide = GetBattlerSide(gBattlerAttacker); - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_WRAPPED) + if (gBattleMons[gBattlerAttacker].volatiles.wrapped) { gBattleScripting.battler = gBattlerTarget; - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_WRAPPED; + gBattleMons[gBattlerAttacker].volatiles.wrapped = FALSE; gBattlerTarget = gBattleStruct->wrappedBy[gBattlerAttacker]; PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleStruct->wrappedMove[gBattlerAttacker]); BattleScriptCall(BattleScript_WrapFree); @@ -14163,12 +14130,8 @@ static void Cmd_rapidspinfree(void) } } -static void Cmd_setdefensecurlbit(void) +static void Cmd_unused_0xBF(void) { - CMD_ARGS(); - - gBattleMons[gBattlerAttacker].status2 |= STATUS2_DEFENSE_CURL; - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_recoverbasedonsunlight(void) @@ -14536,14 +14499,14 @@ static void Cmd_settorment(void) { CMD_ARGS(const u8 *failInstr); - if (gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT + if (gBattleMons[gBattlerTarget].volatiles.torment == TRUE || (GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX)) { gBattlescriptCurrInstr = cmd->failInstr; } else { - gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT; + gBattleMons[gBattlerTarget].volatiles.torment = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -15300,7 +15263,7 @@ static void Cmd_settypebasedhalvers(void) bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) { - if (!(gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE)) + if (!gBattleMons[battlerDef].volatiles.substitute) return FALSE; else if (MoveIgnoresSubstitute(move)) return FALSE; @@ -15313,7 +15276,7 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) bool32 DoesDisguiseBlockMove(u32 battler, u32 move) { if (!(gBattleMons[battler].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) - || gBattleMons[battler].status2 & STATUS2_TRANSFORMED + || gBattleMons[battler].volatiles.transformed || (!gProtectStructs[battler].confusionSelfDmg && (IsBattleMoveStatus(move) || gHitMarker & HITMARKER_PASSIVE_DAMAGE)) || gHitMarker & HITMARKER_IGNORE_DISGUISE || !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_DISGUISE)) @@ -16881,34 +16844,23 @@ void BS_ItemCureStatus(void) { NATIVE_ARGS(const u8 *noStatusInstr); u32 battler = gBattlerAttacker; - u32 previousStatus2 = 0; bool32 statusChanged = FALSE; struct Pokemon *party = GetBattlerParty(gBattlerAttacker); - // Heal Status2 conditions if battler is active. + // Heal volatile conditions if battler is active. if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker]) - { - previousStatus2 = gBattleMons[battler].status2; - gBattleMons[gBattlerAttacker].status2 &= ~GetItemStatus2Mask(gLastUsedItem); - } + statusChanged = ItemHealMonVolatile(battler, gLastUsedItem); else if (IsDoubleBattle() - && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) - { - battler = BATTLE_PARTNER(gBattlerAttacker); - previousStatus2 = gBattleMons[battler].status2; - gBattleMons[battler].status2 &= ~GetItemStatus2Mask(gLastUsedItem); - } - - if (previousStatus2 != gBattleMons[battler].status2) - statusChanged = TRUE; + && gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)]) + statusChanged = ItemHealMonVolatile(BATTLE_PARTNER(gBattlerAttacker), gLastUsedItem); // Heal Status1 conditions. if (!HealStatusConditions(&party[gBattleStruct->itemPartyIndex[gBattlerAttacker]], GetItemStatus1Mask(gLastUsedItem), battler)) { statusChanged = TRUE; if (GetItemStatus1Mask(gLastUsedItem) & STATUS1_SLEEP) - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; - if (GetItemStatus2Mask(gLastUsedItem) & STATUS2_CONFUSION) + gBattleMons[battler].volatiles.nightmare = FALSE; + if (ItemHasVolatileFlag(gLastUsedItem, VOLATILE_CONFUSION)) gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION; } @@ -17168,7 +17120,7 @@ void BS_TrySetOctolock(void) else { gDisableStructs[battler].octolock = TRUE; - gBattleMons[battler].status2 |= STATUS2_ESCAPE_PREVENTION; + gBattleMons[battler].volatiles.escapePrevention = TRUE; gDisableStructs[battler].battlerPreventingEscape = gBattlerAttacker; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17962,7 +17914,7 @@ void BS_CheckPokeFlute(void) if (GetBattlerAbility(i) != ABILITY_SOUNDPROOF) { gBattleMons[i].status1 &= ~STATUS1_SLEEP; - gBattleMons[i].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[i].volatiles.nightmare = FALSE; } } @@ -18243,8 +18195,7 @@ void BS_TrySetConfusion(void) if (CanBeConfused(gBattlerTarget)) { - gBattleMons[gBattlerTarget].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); - gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gBattleMons[gBattlerTarget].volatiles.confusionTurns = ((Random()) % 4) + 2; gBattleCommunication[MULTIUSE_STATE] = 1; gEffectBattler = gBattlerTarget; gBattlescriptCurrInstr = cmd->nextInstr; @@ -18259,13 +18210,12 @@ void BS_TrySetInfatuation(void) { NATIVE_ARGS(const u8 *failInstr); - if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_INFATUATION) + if (!gBattleMons[gBattlerTarget].volatiles.infatuation && gBattleMons[gBattlerTarget].ability != ABILITY_OBLIVIOUS && !IsAbilityOnSide(gBattlerTarget, ABILITY_AROMA_VEIL) && AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget)) { - gBattleMons[gBattlerTarget].status2 |= STATUS2_INFATUATED_WITH(gBattlerAttacker); - gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattleMons[gBattlerTarget].volatiles.infatuation = INFATUATED_WITH(gBattlerAttacker); gBattleCommunication[MULTIUSE_STATE] = 2; gEffectBattler = gBattlerTarget; gBattlescriptCurrInstr = cmd->nextInstr; @@ -18280,11 +18230,10 @@ void BS_TrySetEscapePrevention(void) { NATIVE_ARGS(const u8 *failInstr); - if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_ESCAPE_PREVENTION)) + if (!gBattleMons[gBattlerTarget].volatiles.escapePrevention) { - gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION; + gBattleMons[gBattlerTarget].volatiles.escapePrevention = TRUE; gDisableStructs[gBattlerTarget].battlerPreventingEscape = gBattlerAttacker; - gBattleCommunication[MULTISTRING_CHOOSER] = 2; gEffectBattler = gBattlerTarget; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -18298,12 +18247,11 @@ void BS_TrySetTorment(void) { NATIVE_ARGS(const u8 *failInstr); - if (!(gBattleMons[gBattlerTarget].status2 & STATUS2_TORMENT) + if (!(gBattleMons[gBattlerTarget].volatiles.torment == TRUE) && !IsAbilityOnSide(gBattlerTarget, ABILITY_AROMA_VEIL)) { - gBattleMons[gBattlerTarget].status2 |= STATUS2_TORMENT; + gBattleMons[gBattlerTarget].volatiles.torment = TRUE; gDisableStructs[gBattlerTarget].tormentTimer = gBattleTurnCounter + 3; // 3 turns excluding current turn - gBattleCommunication[MULTISTRING_CHOOSER] = 3; gEffectBattler = gBattlerTarget; gBattlescriptCurrInstr = cmd->nextInstr; } diff --git a/src/battle_terastal.c b/src/battle_terastal.c index 6984f3fc6c..8799dc7ab2 100644 --- a/src/battle_terastal.c +++ b/src/battle_terastal.c @@ -64,7 +64,7 @@ bool32 CanTerastallize(u32 battler) { enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler, FALSE); - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS) + if (gBattleMons[battler].volatiles.transformed && GET_BASE_SPECIES_ID(gBattleMons[battler].species) == SPECIES_TERAPAGOS) return FALSE; // Prevents Zigzagoon from terastalizing in vanilla. diff --git a/src/battle_util.c b/src/battle_util.c index d882f28fa4..088436c4c1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -412,7 +412,7 @@ void HandleAction_UseMove(void) gHitMarker |= HITMARKER_NO_PPDEDUCT; gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); } - else if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + else if (gBattleMons[gBattlerAttacker].volatiles.multipleTurns || gBattleMons[gBattlerAttacker].volatiles.recharge) { gCurrentMove = gChosenMove = gLockedMoves[gBattlerAttacker]; } @@ -1056,18 +1056,18 @@ 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].status2 & STATUS2_LOCK_CONFUSE && skyDropState != SKY_DROP_STATUS_YAWN) + if (gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns && skyDropState != SKY_DROP_STATUS_YAWN) { - gBattleMons[otherSkyDropper].status2 &= ~(STATUS2_LOCK_CONFUSE); + gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns = 0; // If the target can be confused, confuse them. // Don't use CanBeConfused, can cause issues in edge cases. - if (!(gBattleMons[otherSkyDropper].status2 & STATUS2_CONFUSION + if (!(gBattleMons[otherSkyDropper].volatiles.confusionTurns > 0 || IsAbilityAndRecord(otherSkyDropper, GetBattlerAbility(otherSkyDropper), ABILITY_OWN_TEMPO) || IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN))) { // Set confused status - gBattleMons[otherSkyDropper].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); + gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2; if (skyDropState == SKY_DROP_ATTACKCANCELLER_CHECK) { @@ -1094,7 +1094,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].status2 & STATUS2_LOCK_CONFUSE) && gBattleStruct->skyDropTargets[battler] < 4) + if (!(gBattleMons[otherSkyDropper].volatiles.lockConfusionTurns) && gBattleStruct->skyDropTargets[battler] < 4) { gBattleStruct->skyDropTargets[battler] = SKY_DROP_NO_TARGET; gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET; @@ -1106,18 +1106,18 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState) const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState) { const u8 *result = NULL; - gBattleMons[battler].status2 &= ~(STATUS2_UPROAR); - gBattleMons[battler].status2 &= ~(STATUS2_BIDE); + gBattleMons[battler].volatiles.uproarTurns = 0; + gBattleMons[battler].volatiles.bideTurns = 0; if (B_RAMPAGE_CANCELLING < GEN_5) { - gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS); - gBattleMons[battler].status2 &= ~(STATUS2_LOCK_CONFUSE); + gBattleMons[battler].volatiles.multipleTurns = 0; + gBattleMons[battler].volatiles.lockConfusionTurns = 0; } - else if (!(gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) - || ((gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) > STATUS2_LOCK_CONFUSE_TURN(1))) + else if (!gBattleMons[battler].volatiles.lockConfusionTurns + || gBattleMons[battler].volatiles.lockConfusionTurns > 1) { - gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS); + gBattleMons[battler].volatiles.multipleTurns = 0; } // Clear battler's semi-invulnerable bits if they are not held by Sky Drop. @@ -1341,7 +1341,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && move == gLastMoves[battler] && move != MOVE_STRUGGLE && (gBattleMons[battler].status2 & STATUS2_TORMENT)) + if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && move == gLastMoves[battler] && move != MOVE_STRUGGLE && (gBattleMons[battler].volatiles.torment == TRUE)) { CancelMultiTurnMoves(battler, SKY_DROP_IGNORE); if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -1588,7 +1588,7 @@ u32 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_DISABLED && move == gDisableStructs[battler].disabledMove) unusableMoves |= 1u << i; // Torment - else if (check & MOVE_LIMITATION_TORMENTED && move == gLastMoves[battler] && gBattleMons[battler].status2 & STATUS2_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)) @@ -1849,8 +1849,8 @@ void TryClearRageAndFuryCutter(void) s32 i; for (i = 0; i < gBattlersCount; i++) { - if ((gBattleMons[i].status2 & STATUS2_RAGE) && gChosenMoveByBattler[i] != MOVE_RAGE) - gBattleMons[i].status2 &= ~STATUS2_RAGE; + if (gBattleMons[i].volatiles.rage && gChosenMoveByBattler[i] != MOVE_RAGE) + gBattleMons[i].volatiles.rage = FALSE; if (gDisableStructs[i].furyCutterCounter != 0 && gChosenMoveByBattler[i] != MOVE_FURY_CUTTER) gDisableStructs[i].furyCutterCounter = 0; } @@ -1871,7 +1871,7 @@ static inline bool32 TryFormChangeBeforeMove(void) static inline bool32 TryActivatePowderStatus(u32 move) { u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER)) + if (!gBattleMons[gBattlerAttacker].volatiles.powder) return FALSE; if (GetBattleMoveType(move) == TYPE_FIRE && !gBattleStruct->pledgeMove) return TRUE; @@ -1890,7 +1890,7 @@ void SetAtkCancellerForCalledMove(void) static enum MoveCanceller CancellerFlags(void) { - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_DESTINY_BOND; + gBattleMons[gBattlerAttacker].volatiles.destinyBond = FALSE; gStatuses3[gBattlerAttacker] &= ~STATUS3_GRUDGE; gStatuses4[gBattlerAttacker] &= ~STATUS4_GLAIVE_RUSH; return MOVE_STEP_SUCCESS; @@ -1917,9 +1917,9 @@ static enum MoveCanceller CancellerSkyDrop(void) static enum MoveCanceller CancellerRecharge(void) { - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + if (gBattleMons[gBattlerAttacker].volatiles.recharge) { - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RECHARGE; + gBattleMons[gBattlerAttacker].volatiles.recharge = TRUE; gDisableStructs[gBattlerAttacker].rechargeTimer = 0; CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; @@ -1937,7 +1937,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(void) { TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR; BattleScriptCall(BattleScript_MoveUsedWokeUp); return MOVE_STEP_REMOVES_STATUS; @@ -1967,7 +1967,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(void) else { TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[gBattlerAttacker].volatiles.nightmare = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP; BattleScriptCall(BattleScript_MoveUsedWokeUp); return MOVE_STEP_REMOVES_STATUS; @@ -2067,7 +2067,7 @@ static enum MoveCanceller CancellerTruant(void) static enum MoveCanceller CancellerFlinch(void) { - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED) + if (gBattleMons[gBattlerAttacker].volatiles.flinched) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); @@ -2154,11 +2154,11 @@ static enum MoveCanceller CancellerConfused(void) if (gBattleStruct->isAtkCancelerForCalledMove) return MOVE_STEP_SUCCESS; - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) + if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns) { if (!(gStatuses4[gBattlerAttacker] & STATUS4_INFINITE_CONFUSION)) - gBattleMons[gBattlerAttacker].status2 -= STATUS2_CONFUSION_TURN(1); - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) + gBattleMons[gBattlerAttacker].volatiles.confusionTurns--; + if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns) { // confusion dmg if (RandomPercentage(RNG_CONFUSION, (GetGenConfig(GEN_CONFIG_CONFUSION_SELF_DMG_CHANCE) >= GEN_7 ? 33 : 50))) @@ -2212,9 +2212,9 @@ static enum MoveCanceller CancellerParalysed(void) static enum MoveCanceller CancellerInfatuation(void) { - if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) + if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].volatiles.infatuation) { - gBattleScripting.battler = CountTrailingZeroBits((gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) >> 0x10); + gBattleScripting.battler = gBattleMons[gBattlerAttacker].volatiles.infatuation - 1; if (!RandomPercentage(RNG_INFATUATION, 50)) { BattleScriptCall(BattleScript_MoveUsedIsInLove); @@ -2234,17 +2234,16 @@ static enum MoveCanceller CancellerInfatuation(void) static enum MoveCanceller CancellerBide(void) { - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) + if (gBattleMons[gBattlerAttacker].volatiles.bideTurns) { - gBattleMons[gBattlerAttacker].status2 -= STATUS2_BIDE_TURN(1); - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) + if (--gBattleMons[gBattlerAttacker].volatiles.bideTurns) { gBattlescriptCurrInstr = BattleScript_BideStoringEnergy; } else { // This is removed in FRLG and Emerald for some reason - //gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_MULTIPLETURNS; + //gBattleMons[gBattlerAttacker].volatiles.multipleTurns = FALSE; if (gBideDmg[gBattlerAttacker]) { gCurrentMove = MOVE_BIDE; @@ -2978,7 +2977,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a case ABILITY_SOUNDPROOF: if (IsSoundMove(move) && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER)) { - if (gBattleMons[battlerAtk].status2 & STATUS2_MULTIPLETURNS) + if (gBattleMons[battlerAtk].volatiles.multipleTurns) gHitMarker |= HITMARKER_NO_PPDEDUCT; battleScriptBlocksMove = BattleScript_SoundproofProtected; } @@ -2986,7 +2985,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a case ABILITY_BULLETPROOF: if (IsBallisticMove(move)) { - if (gBattleMons[battlerAtk].status2 & STATUS2_MULTIPLETURNS) + if (gBattleMons[battlerAtk].volatiles.multipleTurns) gHitMarker |= HITMARKER_NO_PPDEDUCT; battleScriptBlocksMove = BattleScript_SoundproofProtected; } @@ -2996,7 +2995,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a case ABILITY_ARMOR_TAIL: if (atkPriority > 0 && !IsBattlerAlly(battlerAtk, battlerDef)) { - if (gBattleMons[battlerAtk].status2 & STATUS2_MULTIPLETURNS) + if (gBattleMons[battlerAtk].volatiles.multipleTurns) gHitMarker |= HITMARKER_NO_PPDEDUCT; battleScriptBlocksMove = BattleScript_DazzlingProtected; } @@ -3041,7 +3040,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a case ABILITY_DAZZLING: case ABILITY_QUEENLY_MAJESTY: case ABILITY_ARMOR_TAIL: - if (gBattleMons[battlerAtk].status2 & STATUS2_MULTIPLETURNS) + if (gBattleMons[battlerAtk].volatiles.multipleTurns) gHitMarker |= HITMARKER_NO_PPDEDUCT; battlerAbility = partnerDef; battleScriptBlocksMove = BattleScript_DazzlingProtected; @@ -3549,8 +3548,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (gDisableStructs[battler].isFirstTurn == 2 && !gDisableStructs[battler].overwrittenAbility && IsBattlerAlive(diagonalBattler) - && !(gBattleMons[diagonalBattler].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE)) - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + && !gBattleMons[diagonalBattler].volatiles.substitute + && !gBattleMons[diagonalBattler].volatiles.transformed + && !gBattleMons[battler].volatiles.transformed && gBattleStruct->illusion[diagonalBattler].state != ILLUSION_ON && !(gStatuses3[diagonalBattler] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER)) { @@ -4124,7 +4124,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_ICE_FACE: if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW) && gBattleMons[battler].species == SPECIES_EISCUE_NOICE - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[battler].volatiles.transformed)) { // TODO: Convert this to a proper FORM_CHANGE type. gBattleMons[battler].species = SPECIES_EISCUE_ICE; @@ -4147,9 +4147,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gBattleStruct->battlerState[battler].commandingDondozo = TRUE; gBattleStruct->commanderActive[partner] = gBattleMons[battler].species; gStatuses3[battler] |= STATUS3_COMMANDER; - if (gBattleMons[battler].status2 & STATUS2_CONFUSION + if (gBattleMons[battler].volatiles.confusionTurns > 0 && !(gStatuses4[battler] & STATUS4_INFINITE_CONFUSION)) - gBattleMons[battler].status2 -= STATUS2_CONFUSION_TURN(1); + gBattleMons[battler].volatiles.confusionTurns--; BtlController_EmitSpriteInvisibility(battler, B_COMM_TO_CONTROLLER, TRUE); MarkBattlerForControllerExec(battler); BattleScriptPushCursorAndCallback(BattleScript_CommanderActivates); @@ -4245,7 +4245,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); gBattleMons[battler].status1 = 0; - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; gBattleScripting.battler = battler; BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates); BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1); @@ -4363,7 +4363,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_HUNGER_SWITCH: - if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (!gBattleMons[battler].volatiles.transformed && GetActiveGimmick(battler) != GIMMICK_TERA && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_TURN_END)) { @@ -4728,13 +4728,13 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerTarget) && (B_ABILITY_TRIGGER_CHANCE >= GEN_4 ? RandomPercentage(RNG_CUTE_CHARM, 30) : RandomChance(RNG_CUTE_CHARM, 1, 3)) - && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) + && !(gBattleMons[gBattlerAttacker].volatiles.infatuation) && AreBattlersOfOppositeGender(gBattlerAttacker, gBattlerTarget) && !IsAbilityAndRecord(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), ABILITY_OBLIVIOUS) && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move) && !IsAbilityOnSide(gBattlerAttacker, ABILITY_AROMA_VEIL)) { - gBattleMons[gBattlerAttacker].status2 |= STATUS2_INFATUATED_WITH(gBattlerTarget); + gBattleMons[gBattlerAttacker].volatiles.infatuation = INFATUATED_WITH(gBattlerTarget); BattleScriptCall(BattleScript_CuteCharmActivates); effect++; } @@ -5034,7 +5034,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_OWN_TEMPO: - if (gBattleMons[battler].status2 & STATUS2_CONFUSION) + if (gBattleMons[battler].volatiles.confusionTurns > 0) { StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); effect = 2; @@ -5052,7 +5052,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (gBattleMons[battler].status1 & STATUS1_SLEEP) { TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); effect = 1; } @@ -5074,7 +5074,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_OBLIVIOUS: - if (gBattleMons[battler].status2 & STATUS2_INFATUATION) + if (gBattleMons[battler].volatiles.infatuation) effect = 3; else if (gDisableStructs[battler].tauntTimer != 0) effect = 4; @@ -5094,7 +5094,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 BattleScriptCall(BattleScript_AbilityCuredStatus); break; case 3: // get rid of infatuation - gBattleMons[battler].status2 &= ~STATUS2_INFATUATION; + gBattleMons[battler].volatiles.infatuation = 0; BattleScriptCall(BattleScript_BattlerGotOverItsInfatuation); break; case 4: // get rid of taunt @@ -5215,7 +5215,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!gDisableStructs[battler].weatherAbilityDone && battlerWeatherAffected && gBattleMons[battler].species == SPECIES_EISCUE_NOICE - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[battler].volatiles.transformed)) { // TODO: Convert this to a proper FORM_CHANGE type. gBattleScripting.battler = battler; @@ -5229,7 +5229,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_PROTOSYNTHESIS: if (!gDisableStructs[battler].weatherAbilityDone && (gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect() - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + && !gBattleMons[battler].volatiles.transformed && !gDisableStructs[battler].boosterEnergyActivated) { gDisableStructs[battler].weatherAbilityDone = TRUE; @@ -5258,7 +5258,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_QUARK_DRIVE: if (!gDisableStructs[battler].terrainAbilityDone && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + && !gBattleMons[battler].volatiles.transformed && !gDisableStructs[battler].boosterEnergyActivated) { gDisableStructs[battler].terrainAbilityDone = TRUE; @@ -5358,7 +5358,7 @@ u32 GetBattlerAbilityInternal(u32 battler, u32 ignoreMoldBreaker, u32 noAbilityS if (abilityCantBeSuppressed) { // Edge case: pokemon under the effect of gastro acid transforms into a pokemon with Comatose (Todo: verify how other unsuppressable abilities behave) - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED + if (gBattleMons[battler].volatiles.transformed && gStatuses3[battler] & STATUS3_GASTRO_ACID && gBattleMons[battler].ability == ABILITY_COMATOSE) return ABILITY_NONE; @@ -5457,7 +5457,9 @@ bool32 CanBattlerEscape(u32 battler) // no ability check return TRUE; else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; - else if (gBattleMons[battler].status2 & (STATUS2_ESCAPE_PREVENTION | STATUS2_WRAPPED)) + else if (gBattleMons[battler].volatiles.escapePrevention) + return FALSE; + else if (gBattleMons[battler].volatiles.wrapped) return FALSE; else if (gStatuses3[battler] & STATUS3_ROOTED) return FALSE; @@ -5793,7 +5795,7 @@ static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum Func bool32 CanBeConfused(u32 battler) { - if (gBattleMons[battler].status2 & STATUS2_CONFUSION + if (gBattleMons[battler].volatiles.confusionTurns > 0 || IsBattlerTerrainAffected(battler, STATUS_FIELD_MISTY_TERRAIN) || IsAbilityAndRecord(battler, GetBattlerAbility(battler),ABILITY_OWN_TEMPO)) return FALSE; @@ -6137,9 +6139,9 @@ static bool32 GetMentalHerbEffect(u32 battler) bool32 ret = FALSE; // Check infatuation - if (gBattleMons[battler].status2 & STATUS2_INFATUATION) + if (gBattleMons[battler].volatiles.infatuation) { - gBattleMons[battler].status2 &= ~STATUS2_INFATUATION; + gBattleMons[battler].volatiles.infatuation = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); ret = TRUE; @@ -6163,9 +6165,9 @@ static bool32 GetMentalHerbEffect(u32 battler) ret = TRUE; } // Check torment - if (gBattleMons[battler].status2 & STATUS2_TORMENT) + if (gBattleMons[battler].volatiles.torment == TRUE) { - gBattleMons[battler].status2 &= ~STATUS2_TORMENT; + gBattleMons[battler].volatiles.torment = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT; ret = TRUE; } @@ -6209,7 +6211,7 @@ static u32 TryConsumeMirrorHerb(u32 battler, enum ItemCaseId caseID) u32 TryBoosterEnergy(u32 battler, u32 ability, enum ItemCaseId caseID) { - if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gDisableStructs[battler].boosterEnergyActivated || gBattleMons[battler].volatiles.transformed) return ITEM_NO_EFFECT; if (((ability == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && HasWeatherEffect())) @@ -6368,14 +6370,14 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect) if (gBattleMons[battler].status1 & STATUS1_SLEEP && !UnnerveOn(battler, gLastUsedItem)) { gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; BattleScriptCall(BattleScript_BerryCureSlpRet); effect = ITEM_STATUS_CHANGE; TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); } break; case HOLD_EFFECT_CURE_CONFUSION: - if (gBattleMons[battler].status2 & STATUS2_CONFUSION && !UnnerveOn(battler, gLastUsedItem)) + if (gBattleMons[battler].volatiles.confusionTurns > 0 && !UnnerveOn(battler, gLastUsedItem)) { RemoveConfusionStatus(battler); BattleScriptCall(BattleScript_BerryCureConfusionRet); @@ -6392,14 +6394,14 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect) } break; case HOLD_EFFECT_CURE_STATUS: - if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].status2 & STATUS2_CONFUSION) && !UnnerveOn(battler, gLastUsedItem)) + if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0) && !UnnerveOn(battler, gLastUsedItem)) { if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); if (gBattleMons[battler].status1 & STATUS1_SLEEP) { - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); } @@ -6413,7 +6415,7 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect) if (gBattleMons[battler].status1 & STATUS1_FREEZE || gBattleMons[battler].status1 & STATUS1_FROSTBITE) StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); - if (gBattleMons[battler].status2 & STATUS2_CONFUSION) + if (gBattleMons[battler].volatiles.confusionTurns > 0) StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); gBattleMons[battler].status1 = 0; @@ -6425,10 +6427,10 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect) break; case HOLD_EFFECT_CRITICAL_UP: // lansat berry if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) + && !(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) { - gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; + gBattleMons[battler].volatiles.focusEnergy = TRUE; gBattleScripting.battler = battler; gPotentialItemEffectBattler = battler; BattleScriptCall(BattleScript_BerryFocusEnergyRet); @@ -6453,7 +6455,7 @@ static inline bool32 TryCureStatus(u32 battler, enum ItemCaseId caseId) u32 effect = ITEM_NO_EFFECT; u32 string = 0; - if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].status2 & STATUS2_CONFUSION) && !UnnerveOn(battler, gLastUsedItem)) + if ((gBattleMons[battler].status1 & STATUS1_ANY || gBattleMons[battler].volatiles.confusionTurns > 0) && !UnnerveOn(battler, gLastUsedItem)) { if (gBattleMons[battler].status1 & STATUS1_PSN_ANY) { @@ -6462,7 +6464,7 @@ static inline bool32 TryCureStatus(u32 battler, enum ItemCaseId caseId) } if (gBattleMons[battler].status1 & STATUS1_SLEEP) { - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); string++; TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); @@ -6482,7 +6484,7 @@ static inline bool32 TryCureStatus(u32 battler, enum ItemCaseId caseId) StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); string++; } - if (gBattleMons[battler].status2 & STATUS2_CONFUSION) + if (gBattleMons[battler].volatiles.confusionTurns > 0) { StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); string++; @@ -6585,10 +6587,10 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) break; case HOLD_EFFECT_CRITICAL_UP: if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) + && !(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) { - gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; + gBattleMons[battler].volatiles.focusEnergy = TRUE; gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); effect = ITEM_EFFECT_OTHER; @@ -6652,7 +6654,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) && !UnnerveOn(battler, gLastUsedItem)) { gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; BattleScriptExecute(BattleScript_BerryCureSlpEnd2); effect = ITEM_STATUS_CHANGE; TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); @@ -6808,10 +6810,10 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, caseID); break; case HOLD_EFFECT_CRITICAL_UP: - if (!(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) + if (!(gBattleMons[battler].volatiles.dragonCheer || gBattleMons[battler].volatiles.focusEnergy) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) { - gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; + gBattleMons[battler].volatiles.focusEnergy = TRUE; gBattleScripting.battler = battler; BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); effect = ITEM_EFFECT_OTHER; @@ -6862,14 +6864,14 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) if (gBattleMons[battler].status1 & STATUS1_SLEEP && !UnnerveOn(battler, gLastUsedItem)) { gBattleMons[battler].status1 &= ~STATUS1_SLEEP; - gBattleMons[battler].status2 &= ~STATUS2_NIGHTMARE; + gBattleMons[battler].volatiles.nightmare = FALSE; BattleScriptExecute(BattleScript_BerryCureSlpEnd2); effect = ITEM_STATUS_CHANGE; TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]); } break; case HOLD_EFFECT_CURE_CONFUSION: - if (gBattleMons[battler].status2 & STATUS2_CONFUSION && !UnnerveOn(battler, gLastUsedItem)) + if (gBattleMons[battler].volatiles.confusionTurns > 0 && !UnnerveOn(battler, gLastUsedItem)) { RemoveConfusionStatus(battler); BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); @@ -7270,7 +7272,7 @@ u32 ItemBattleEffects(enum ItemCaseId caseID, u32 battler) void ClearVariousBattlerFlags(u32 battler) { gDisableStructs[battler].furyCutterCounter = 0; - gBattleMons[battler].status2 &= ~STATUS2_DESTINY_BOND; + gBattleMons[battler].volatiles.destinyBond = FALSE; gStatuses3[battler] &= ~STATUS3_GRUDGE; gStatuses4[battler] &= ~ STATUS4_GLAIVE_RUSH; } @@ -7459,7 +7461,7 @@ u8 GetAttackerObedienceForAction() // is not obedient enum BattleMoveEffects moveEffect = GetMoveEffect(gCurrentMove); if (moveEffect == EFFECT_RAGE) - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RAGE; + gBattleMons[gBattlerAttacker].volatiles.rage = FALSE; if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (moveEffect == EFFECT_SNORE || moveEffect == EFFECT_SLEEP_TALK)) return DISOBEYS_WHILE_ASLEEP; @@ -7485,7 +7487,7 @@ u8 GetAttackerObedienceForAction() // try putting asleep int i; for (i = 0; i < gBattlersCount; i++) - if (gBattleMons[i].status2 & STATUS2_UPROAR) + if (gBattleMons[i].volatiles.uproarTurns) break; if (i == gBattlersCount) return DISOBEYS_FALL_ASLEEP; @@ -7895,7 +7897,7 @@ u32 CalcRolloutBasePower(u32 battlerAtk, u32 basePower, u32 rolloutTimer) u32 i; for (i = 1; i < (5 - rolloutTimer); i++) basePower *= 2; - if (gBattleMons[battlerAtk].status2 & STATUS2_DEFENSE_CURL) + if (gBattleMons[battlerAtk].volatiles.defenseCurl) basePower *= 2; return basePower; } @@ -8431,7 +8433,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) u8 defHighestStat = GetHighestStatId(battlerDef); if (((ctx->weather & B_WEATHER_SUN && HasWeatherEffect()) || gDisableStructs[battlerDef].boosterEnergyActivated) && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) - && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[battlerDef].volatiles.transformed)) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } break; @@ -8440,7 +8442,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) u8 defHighestStat = GetHighestStatId(battlerDef); if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerDef].boosterEnergyActivated) && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) - && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) + && !(gBattleMons[battlerDef].volatiles.transformed)) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } break; @@ -8683,7 +8685,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_PROTOSYNTHESIS: - if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED)) + if (!(gBattleMons[battlerAtk].volatiles.transformed)) { u32 atkHighestStat = GetHighestStatId(battlerAtk); if (((ctx->weather & B_WEATHER_SUN) && HasWeatherEffect()) || gDisableStructs[battlerAtk].boosterEnergyActivated) @@ -8694,7 +8696,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) } break; case ABILITY_QUARK_DRIVE: - if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED)) + if (!(gBattleMons[battlerAtk].volatiles.transformed)) { u32 atkHighestStat = GetHighestStatId(battlerAtk); if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerAtk].boosterEnergyActivated) @@ -8919,7 +8921,7 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case HOLD_EFFECT_METAL_POWDER: - if (gBattleMons[battlerDef].species == SPECIES_DITTO && usesDefStat && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) + if (gBattleMons[battlerDef].species == SPECIES_DITTO && usesDefStat && !(gBattleMons[battlerDef].volatiles.transformed)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case HOLD_EFFECT_EVIOLITE: @@ -9521,7 +9523,7 @@ static inline void MulByTypeEffectiveness(struct DamageContext *ctx, uq4_12_t *m if (ctx->updateFlags) RecordItemEffectBattle(ctx->battlerDef, HOLD_EFFECT_RING_TARGET); } - else if ((ctx->moveType == TYPE_FIGHTING || ctx->moveType == TYPE_NORMAL) && defType == TYPE_GHOST && gBattleMons[ctx->battlerDef].status2 & STATUS2_FORESIGHT && mod == UQ_4_12(0.0)) + else if ((ctx->moveType == TYPE_FIGHTING || ctx->moveType == TYPE_NORMAL) && defType == TYPE_GHOST && gBattleMons[ctx->battlerDef].volatiles.foresight && mod == UQ_4_12(0.0)) { mod = UQ_4_12(1.0); } @@ -9964,7 +9966,7 @@ void ActivateUltraBurst(u32 battler) bool32 IsBattlerMegaEvolved(u32 battler) { // While Transform does copy stats and visuals, it shouldn't be counted as true Mega Evolution. - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gBattleMons[battler].volatiles.transformed) return FALSE; return (gSpeciesInfo[gBattleMons[battler].species].isMegaEvolution); } @@ -9972,7 +9974,7 @@ bool32 IsBattlerMegaEvolved(u32 battler) bool32 IsBattlerPrimalReverted(u32 battler) { // While Transform does copy stats and visuals, it shouldn't be counted as true Primal Revesion. - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gBattleMons[battler].volatiles.transformed) return FALSE; return (gSpeciesInfo[gBattleMons[battler].species].isPrimalReversion); } @@ -9980,7 +9982,7 @@ bool32 IsBattlerPrimalReverted(u32 battler) bool32 IsBattlerUltraBursted(u32 battler) { // While Transform does copy stats and visuals, it shouldn't be counted as true Ultra Burst. - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gBattleMons[battler].volatiles.transformed) return FALSE; return (gSpeciesInfo[gBattleMons[battler].species].isUltraBurst); } @@ -9988,7 +9990,7 @@ bool32 IsBattlerUltraBursted(u32 battler) bool32 IsBattlerInTeraForm(u32 battler) { // While Transform does copy stats and visuals, it shouldn't be counted as a true Tera Form. - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gBattleMons[battler].volatiles.transformed) return FALSE; return (gSpeciesInfo[gBattleMons[battler].species].isTeraForm); } @@ -10106,7 +10108,7 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, enum FormChanges method) bool32 CanBattlerFormChange(u32 battler, enum FormChanges method) { // Can't change form if transformed. - if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED + if (gBattleMons[battler].volatiles.transformed && B_TRANSFORM_FORM_CHANGES >= GEN_5) return FALSE; // Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle. @@ -10856,7 +10858,7 @@ void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing) void RemoveConfusionStatus(u32 battler) { - gBattleMons[battler].status2 &= ~STATUS2_CONFUSION; + gBattleMons[battler].volatiles.confusionTurns = 0; gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION; } @@ -11415,7 +11417,7 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID) return FALSE; } -#define UNPACK_VOLATILE_GETTERS(_enum, _fieldName, _typeBitSize, ...) case _enum: return gBattleMons[battler].volatiles._fieldName; +#define UNPACK_VOLATILE_GETTERS(_enum, _fieldName, _typeMaxValue, ...) case _enum: return gBattleMons[battler].volatiles._fieldName; // 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 @@ -11433,7 +11435,7 @@ u32 GetMonVolatile(u32 battler, enum Volatile _volatile) } } -#define UNPACK_VOLATILE_SETTERS(_enum, _fieldName, _typeBitSize, ...) case _enum: gBattleMons[battler].volatiles._fieldName = min(GET_VOLATILE_MAXIMUM(_typeBitSize), newValue); break; +#define UNPACK_VOLATILE_SETTERS(_enum, _fieldName, _typeMaxValue, ...) case _enum: gBattleMons[battler].volatiles._fieldName = min(GET_VOLATILE_MAXIMUM(_typeMaxValue), newValue); break; // Sets 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 @@ -11452,6 +11454,30 @@ void SetMonVolatile(u32 battler, enum Volatile _volatile, u32 newValue) } } +bool32 ItemHealMonVolatile(u32 battler, u16 itemId) +{ + bool32 statusChanged = FALSE; + const u8 *effect = GetItemEffect(itemId); + if (effect[3] & ITEM3_STATUS_ALL) + { + statusChanged = (gBattleMons[battler].volatiles.infatuation || gBattleMons[battler].volatiles.confusionTurns > 0); + gBattleMons[battler].volatiles.infatuation = 0; + gBattleMons[battler].volatiles.confusionTurns = 0; + } + else if (effect[0] & ITEM0_INFATUATION) + { + statusChanged = !!gBattleMons[battler].volatiles.infatuation; + gBattleMons[battler].volatiles.infatuation = 0; + } + else if (effect[3] & ITEM3_CONFUSION) + { + statusChanged = gBattleMons[battler].volatiles.confusionTurns > 0; + gBattleMons[battler].volatiles.confusionTurns = 0; + } + + return statusChanged; +} + // Hazards are added to a queue and applied based in order (FIFO) void PushHazardTypeToQueue(u32 side, enum Hazards hazardType) { @@ -11634,7 +11660,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (defAbility == ABILITY_UNAWARE) accStage = DEFAULT_STAT_STAGE; - if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) + if (gBattleMons[battlerDef].volatiles.foresight || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED) buff = accStage; else buff = accStage + DEFAULT_STAT_STAGE - evasionStage; diff --git a/src/battle_util2.c b/src/battle_util2.c index ba8db66f5d..3a05e5ac13 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -133,7 +133,7 @@ u32 BattlePalace_TryEscapeStatus(u8 battler) { // Wake up from Uproar gBattleMons[battler].status1 &= ~(STATUS1_SLEEP); - gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); + gBattleMons[battler].volatiles.nightmare = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR; BattleScriptCall(BattleScript_MoveUsedWokeUp); effect = 2; @@ -162,7 +162,7 @@ u32 BattlePalace_TryEscapeStatus(u8 battler) else { // Wake up - gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE); + gBattleMons[battler].volatiles.nightmare = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP; BattleScriptCall(BattleScript_MoveUsedWokeUp); effect = 2; diff --git a/src/battle_z_move.c b/src/battle_z_move.c index 4f33ff5a17..638e9ef901 100644 --- a/src/battle_z_move.c +++ b/src/battle_z_move.c @@ -486,9 +486,9 @@ void SetZEffect(void) break; } case Z_EFFECT_BOOST_CRITS: - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY_ANY)) + if (!(gBattleMons[gBattlerAttacker].volatiles.dragonCheer || gBattleMons[gBattlerAttacker].volatiles.focusEnergy)) { - gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY; + gBattleMons[gBattlerAttacker].volatiles.focusEnergy = TRUE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_BOOST_CRITS; BattleScriptPush(gBattlescriptCurrInstr + Z_EFFECT_BS_LENGTH); gBattlescriptCurrInstr = BattleScript_ZEffectPrintString; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 465d3c0153..5dba4cb657 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -3108,7 +3108,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, - .argument = { .status = STATUS2_FOCUS_ENERGY }, + .argument = { .status = VOLATILE_FOCUS_ENERGY }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, diff --git a/src/item.c b/src/item.c index 45a3dfe421..52d52923ca 100644 --- a/src/item.c +++ b/src/item.c @@ -958,17 +958,18 @@ u32 GetItemStatus1Mask(u16 itemId) return 0; } -u32 GetItemStatus2Mask(u16 itemId) +bool32 ItemHasVolatileFlag(u16 itemId, enum Volatile _volatile) { const u8 *effect = GetItemEffect(itemId); - if (effect[3] & ITEM3_STATUS_ALL) - return STATUS2_INFATUATION | STATUS2_CONFUSION; - else if (effect[0] & ITEM0_INFATUATION) - return STATUS2_INFATUATION; - else if (effect[3] & ITEM3_CONFUSION) - return STATUS2_CONFUSION; - else - return 0; + switch (_volatile) + { + case VOLATILE_CONFUSION: + return (effect[3] & ITEM3_STATUS_ALL) || (effect[3] & ITEM3_CONFUSION); + case VOLATILE_INFATUATION: + return (effect[3] & ITEM3_STATUS_ALL) || (effect[0] & ITEM0_INFATUATION); + default: + return FALSE; + } } u32 GetItemSellPrice(u32 itemId) diff --git a/src/item_use.c b/src/item_use.c index 9df366e595..ace6aaccf6 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -1191,12 +1191,25 @@ void ItemUseInBattle_PartyMenuChooseMove(u8 taskId) ItemUseInBattle_ShowPartyMenu(taskId); } -static bool32 SelectedMonHasStatus2(u16 itemId) +static bool32 IteamHealsMonVolatile(u32 battler, u16 itemId) +{ + const u8 *effect = GetItemEffect(itemId); + if (effect[3] & ITEM3_STATUS_ALL) + return (gBattleMons[battler].volatiles.infatuation || gBattleMons[battler].volatiles.confusionTurns > 0); + else if (effect[0] & ITEM0_INFATUATION) + return gBattleMons[battler].volatiles.infatuation; + else if (effect[3] & ITEM3_CONFUSION) + return gBattleMons[battler].volatiles.confusionTurns > 0; + + return FALSE; +} + +static bool32 SelectedMonHasVolatile(u16 itemId) { if (gPartyMenu.slotId == 0) - return gBattleMons[0].status2 & GetItemStatus2Mask(itemId); + return IteamHealsMonVolatile(0, itemId); else if (gBattleTypeFlags & (BATTLE_TYPE_DOUBLE | BATTLE_TYPE_MULTI) && gPartyMenu.slotId == 1) - return gBattleMons[2].status2 & GetItemStatus2Mask(itemId); + return IteamHealsMonVolatile(2, itemId); return FALSE; } @@ -1224,7 +1237,7 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon) cannotUse = TRUE; break; case EFFECT_ITEM_SET_FOCUS_ENERGY: - if (gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY_ANY) + if (gBattleMons[gBattlerInMenuId].volatiles.dragonCheer || gBattleMons[gBattlerInMenuId].volatiles.focusEnergy) cannotUse = TRUE; break; case EFFECT_ITEM_SET_MIST: @@ -1272,13 +1285,13 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon) break; case EFFECT_ITEM_CURE_STATUS: if (!((GetMonData(mon, MON_DATA_STATUS) & GetItemStatus1Mask(itemId)) - || SelectedMonHasStatus2(itemId))) + || SelectedMonHasVolatile(itemId))) cannotUse = TRUE; break; case EFFECT_ITEM_HEAL_AND_CURE_STATUS: if ((hp == 0 || hp == GetMonData(mon, MON_DATA_MAX_HP)) && !((GetMonData(mon, MON_DATA_STATUS) & GetItemStatus1Mask(itemId)) - || SelectedMonHasStatus2(itemId))) + || SelectedMonHasVolatile(itemId))) cannotUse = TRUE; break; case EFFECT_ITEM_REVIVE: diff --git a/src/pokemon.c b/src/pokemon.c index 91524ae97d..85ef8a2fc9 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -3693,7 +3693,7 @@ void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst) for (i = 0; i < NUM_BATTLE_STATS; i++) dst->statStages[i] = DEFAULT_STAT_STAGE; - dst->status2 = 0; + memset(&dst->volatiles, 0, sizeof(struct Volatiles)); } void CopyPartyMonToBattleData(u32 battler, u32 partyIndex) diff --git a/src/recorded_battle.c b/src/recorded_battle.c index 2d9556311f..500a83e888 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -756,7 +756,7 @@ void RecordedBattle_CheckMovesetChanges(u8 mode) gDisableStructs[battler].mimickedMoves |= mimickedMoveSlots[j] << j; } - if (!(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) + if (!(gBattleMons[battler].volatiles.transformed)) { struct Pokemon *mon = GetBattlerMon(battler); for (j = 0; j < MAX_MON_MOVES; j++) diff --git a/test/battle/ability/shield_dust.c b/test/battle/ability/shield_dust.c index da6bbf87df..828e596525 100644 --- a/test/battle/ability/shield_dust.c +++ b/test/battle/ability/shield_dust.c @@ -36,7 +36,7 @@ SINGLE_BATTLE_TEST("Shield Dust blocks secondary effects") MESSAGE("The opposing Vivillon was prevented from healing!"); } } THEN { // Can't find good way to test trapping - EXPECT(!(opponent->status2 & STATUS2_ESCAPE_PREVENTION)); + EXPECT(!opponent->volatiles.escapePrevention); } } @@ -78,8 +78,8 @@ SINGLE_BATTLE_TEST("Shield Dust does not block primary effects") } } THEN { // Can't find good way to test trapping if (move == MOVE_JAW_LOCK) { - EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION); - EXPECT(player->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(opponent->volatiles.escapePrevention); + EXPECT(player->volatiles.escapePrevention); } } } diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index 220eaa362c..f9fb2e0081 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -1221,7 +1221,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Terror traps both opponents") MESSAGE("The opposing Wobbuffet can no longer escape!"); MESSAGE("The opposing Wobbuffet can no longer escape!"); } THEN { // Can't find good way to test trapping - EXPECT(opponentLeft->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(opponentLeft->volatiles.escapePrevention); } } @@ -1238,7 +1238,7 @@ SINGLE_BATTLE_TEST("Dynamax: Baton Pass passes G-Max Terror's escape prevention ANIMATION(ANIM_TYPE_MOVE, MOVE_G_MAX_TERROR, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_BATON_PASS, opponent); } THEN { - EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(opponent->volatiles.escapePrevention); } } diff --git a/test/battle/hold_effect/berserk_gene.c b/test/battle/hold_effect/berserk_gene.c index 640198c992..bbeb356701 100644 --- a/test/battle/hold_effect/berserk_gene.c +++ b/test/battle/hold_effect/berserk_gene.c @@ -217,7 +217,7 @@ SINGLE_BATTLE_TEST("Berserk Gene causes infinite confusion") // check if bit is } } -SINGLE_BATTLE_TEST("Berserk Gene causes confusion timer to not tick down", u32 status2) +SINGLE_BATTLE_TEST("Berserk Gene causes confusion timer to not tick down", u32 confusionTurns) { u32 turns; PARAMETRIZE { turns = 1; } @@ -231,9 +231,9 @@ SINGLE_BATTLE_TEST("Berserk Gene causes confusion timer to not tick down", u32 s TURN {} } } THEN { - results[i].status2 = player->status2; + results[i].confusionTurns = player->volatiles.confusionTurns; } FINALLY { - EXPECT_EQ(results[0].status2, results[1].status2); + EXPECT_EQ(results[0].confusionTurns, results[1].confusionTurns); } } diff --git a/test/battle/hold_effect/covert_cloak.c b/test/battle/hold_effect/covert_cloak.c index 90593e7cc5..0b3d0c2ed6 100644 --- a/test/battle/hold_effect/covert_cloak.c +++ b/test/battle/hold_effect/covert_cloak.c @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Covert Cloak blocks secondary effects") MESSAGE("The opposing Wobbuffet was prevented from healing!"); } } THEN { // Can't find good way to test trapping - EXPECT(!(opponent->status2 & STATUS2_ESCAPE_PREVENTION)); + EXPECT(!opponent->volatiles.escapePrevention); } } @@ -82,8 +82,8 @@ SINGLE_BATTLE_TEST("Covert Cloak does not block primary effects") } } THEN { // Can't find good way to test trapping if (move == MOVE_JAW_LOCK) { - EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION); - EXPECT(player->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(opponent->volatiles.escapePrevention); + EXPECT(player->volatiles.escapePrevention); } } } diff --git a/test/battle/item_effect/cure_status.c b/test/battle/item_effect/cure_status.c index 6f7d403c43..919b4539af 100644 --- a/test/battle/item_effect/cure_status.c +++ b/test/battle/item_effect/cure_status.c @@ -389,6 +389,6 @@ SINGLE_BATTLE_TEST("Full Heal, Heal Powder and Local Specialties heal a battler } SCENE { MESSAGE("Wobbuffet had its status healed!"); } THEN { - EXPECT_EQ(player->status2, STATUS1_NONE); // because we dont have STATUS2_NONE + EXPECT(player->volatiles.confusionTurns == 0); } } diff --git a/test/battle/move_effect/attract.c b/test/battle/move_effect/attract.c index be30483358..2964b7b611 100644 --- a/test/battle/move_effect/attract.c +++ b/test/battle/move_effect/attract.c @@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Attract causes the target to become infatuated with the user ANIMATION(ANIM_TYPE_MOVE, MOVE_ATTRACT, player); MESSAGE("The opposing Nidoking fell in love!"); } THEN { - EXPECT(opponent->status2 & STATUS2_INFATUATION); + EXPECT(opponent->volatiles.infatuation); } } @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Attract ignores type immunity") ANIMATION(ANIM_TYPE_MOVE, MOVE_ATTRACT, player); MESSAGE("The opposing Misdreavus fell in love!"); } THEN { - EXPECT(opponent->status2 & STATUS2_INFATUATION); + EXPECT(opponent->volatiles.infatuation); } } @@ -51,7 +51,7 @@ SINGLE_BATTLE_TEST("Attract bypasses Substitute") ANIMATION(ANIM_TYPE_MOVE, MOVE_ATTRACT, player); MESSAGE("The opposing Nidoking fell in love!"); } THEN { - EXPECT(opponent->status2 & STATUS2_INFATUATION); + EXPECT(opponent->volatiles.infatuation); } } @@ -69,7 +69,7 @@ SINGLE_BATTLE_TEST("Attract fails if the target is already infatuated") MESSAGE("Nidoqueen used Attract!"); MESSAGE("But it failed!"); } THEN { - EXPECT(opponent->status2 & STATUS2_INFATUATION); + EXPECT(opponent->volatiles.infatuation); } } @@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Attract fails when used on a Pokémon of the same gender") MESSAGE("Nidoqueen used Attract!"); MESSAGE("But it failed!"); } THEN { - EXPECT(!(opponent->status2 & STATUS2_INFATUATION)); + EXPECT(!(opponent->volatiles.infatuation)); } } @@ -100,6 +100,6 @@ SINGLE_BATTLE_TEST("Attract fails when used on a genderless Pokémon") MESSAGE("Nidoqueen used Attract!"); MESSAGE("But it failed!"); } THEN { - EXPECT(!(opponent->status2 & STATUS2_INFATUATION)); + EXPECT(!(opponent->volatiles.infatuation)); } } diff --git a/test/battle/move_effect/baton_pass.c b/test/battle/move_effect/baton_pass.c index cb6530ae89..5cb1ac4c05 100644 --- a/test/battle/move_effect/baton_pass.c +++ b/test/battle/move_effect/baton_pass.c @@ -37,7 +37,7 @@ TO_DO_BATTLE_TEST("Baton Pass doesn't pass ability changes"); // // Move these to the corresponding effect files. // -TO_DO_BATTLE_TEST("Baton Pass passes confusion status"); // test/battle/status2/confusion.c +TO_DO_BATTLE_TEST("Baton Pass passes confusion status"); // test/battle/volatiles/confusion.c TO_DO_BATTLE_TEST("Baton Pass passes Fairy lock's escape prevention effect"); // test/battle/move_effect/fairy_lock.c TO_DO_BATTLE_TEST("Baton Pass passes Focus Energy's effect"); // test/battle/move_effect/focus_energy.c diff --git a/test/battle/move_effect/captivate.c b/test/battle/move_effect/captivate.c index 224e6bef07..27790b8461 100644 --- a/test/battle/move_effect/captivate.c +++ b/test/battle/move_effect/captivate.c @@ -92,7 +92,7 @@ SINGLE_BATTLE_TEST("Attract fails when used by a genderless Pokémon") MESSAGE("Starmie used Attract!"); MESSAGE("But it failed!"); } THEN { - EXPECT(!(opponent->status2 & STATUS2_INFATUATION)); + EXPECT(!(opponent->volatiles.infatuation)); } } @@ -107,6 +107,6 @@ SINGLE_BATTLE_TEST("Attract fails if both the user and the target are genderless MESSAGE("Starmie used Attract!"); MESSAGE("But it failed!"); } THEN { - EXPECT(!(opponent->status2 & STATUS2_INFATUATION)); + EXPECT(!(opponent->volatiles.infatuation)); } } diff --git a/test/battle/move_effect_secondary/thrash.c b/test/battle/move_effect_secondary/thrash.c index 83a49554d7..e7f573d1ed 100644 --- a/test/battle/move_effect_secondary/thrash.c +++ b/test/battle/move_effect_secondary/thrash.c @@ -114,6 +114,6 @@ SINGLE_BATTLE_TEST("Petal Dance does not lock mons that copy the move with Dance ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_PETAL_DANCE, opponent); // How do you actually test locking? - EXPECT(!(opponent->status2 & STATUS2_MULTIPLETURNS)); + EXPECT(!(opponent->volatiles.multipleTurns)); } } diff --git a/test/battle/move_effect_secondary/trap_both.c b/test/battle/move_effect_secondary/trap_both.c index ec06b25c30..76d572dad9 100644 --- a/test/battle/move_effect_secondary/trap_both.c +++ b/test/battle/move_effect_secondary/trap_both.c @@ -17,7 +17,7 @@ SINGLE_BATTLE_TEST("Jaw Lock traps both opponents") ANIMATION(ANIM_TYPE_MOVE, MOVE_JAW_LOCK, player); MESSAGE("Neither Pokémon can run away!"); } THEN { // Can't find good way to test trapping - EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION); - EXPECT(player->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(opponent->volatiles.escapePrevention); + EXPECT(player->volatiles.escapePrevention); } } diff --git a/test/battle/status2/confusion.c b/test/battle/volatiles/confusion.c similarity index 100% rename from test/battle/status2/confusion.c rename to test/battle/volatiles/confusion.c