Convert Status4 to volatiles (#7411)

Co-authored-by: hedara90 <90hedara@gmail.com>
This commit is contained in:
Alex 2025-08-05 19:28:33 +02:00 committed by GitHub
parent 1fb895ad48
commit acc82e7d79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 230 additions and 317 deletions

View File

@ -416,8 +416,11 @@
.4byte \argPtr
.endm
.macro unused_0x47
.macro jumpfifsemiinvulnerable battler:req, state:req, jumpInstr:req
.byte 0x47
.byte \battler
.byte \state
.4byte \jumpInstr
.endm
.macro unused_0x48

View File

@ -2613,7 +2613,8 @@ BattleScript_EffectGravitySuccess::
selectfirstvalidtarget
BattleScript_GravityLoop:
movevaluescleanup
jumpifstatus3 BS_TARGET, STATUS3_ON_AIR | STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS, BattleScript_GravityLoopDrop
jumpfifsemiinvulnerable BS_TARGET, STATE_ON_AIR, BattleScript_GravityLoopDrop
jumpifstatus3 BS_TARGET, STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS, BattleScript_GravityLoopDrop
goto BattleScript_GravityLoopEnd
BattleScript_GravityLoopDrop:
gravityonairbornemons
@ -6982,7 +6983,7 @@ BattleScript_YawnMakesAsleep::
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_EFFECT_BATTLER
waitstate
jumpifstatus3 BS_EFFECT_BATTLER, STATUS3_SKY_DROPPED, BattleScript_YawnEnd
jumpfifsemiinvulnerable BS_EFFECT_BATTLER, STATE_SKY_DROP, BattleScript_YawnEnd
makevisible BS_EFFECT_BATTLER
skydropyawn
BattleScript_YawnEnd:

View File

@ -1074,7 +1074,6 @@ extern u8 gBideTarget[MAX_BATTLERS_COUNT];
extern u32 gSideStatuses[NUM_BATTLE_SIDES];
extern struct SideTimer gSideTimers[NUM_BATTLE_SIDES];
extern u32 gStatuses3[MAX_BATTLERS_COUNT];
extern u32 gStatuses4[MAX_BATTLERS_COUNT];
extern struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT];
extern u16 gPauseCounterBattle;
extern u16 gPaydayMoney;

View File

@ -184,7 +184,6 @@ bool32 HasAnyKnownMove(u32 battlerId);
bool32 IsAromaVeilProtectedEffect(enum BattleMoveEffects moveEffect);
bool32 IsNonVolatileStatusMove(u32 moveEffect);
bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsHazardMove(u32 move);
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move);
bool32 IsBattlerDamagedByStatus(u32 battler);
@ -208,7 +207,6 @@ bool32 IsSwitchOutEffect(enum BattleMoveEffects effect);
bool32 IsChaseEffect(enum BattleMoveEffects effect);
bool32 IsAttackBoostMoveEffect(enum BattleMoveEffects effect);
bool32 IsUngroundingEffect(enum BattleMoveEffects effect);
bool32 IsSemiInvulnerable(u32 battlerDef, u32 move);
bool32 HasMoveWithFlag(u32 battler, MoveFlag getFlag);
bool32 IsHazardClearingMove(u32 move);
bool32 IsSubstituteEffect(enum BattleMoveEffects effect);

View File

@ -406,5 +406,7 @@ bool32 IsHazardOnSideAndClear(u32 side, enum Hazards hazardType);
void RemoveHazardFromField(u32 side, enum Hazards hazardType);
bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 abilityDef, u32 move, enum FunctionCallOption option);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander);
bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move);
#endif // GUARD_BATTLE_UTIL_H

View File

@ -169,8 +169,14 @@ enum VolatileFlags
F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \
F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, 5)) \
F(VOLATILE_ELECTRIFIED, electrified, (u32, 1)) \
F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE)
F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE) \
F(VOLATILE_INFINITE_CONFUSION, infiniteConfusion, (u32, 1)) \
F(VOLATILE_SALT_CURE, saltCure, (u32, 1)) \
F(VOLATILE_SYRUP_BOMB, syrupBomb, (u32, 1)) \
F(VOLATILE_GLAIVE_RUSH, glaiveRush, (u32, 1))
/* 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)
@ -188,44 +194,13 @@ enum Volatile
// 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)
#define STATUS2_FLINCHED (1 << 3)
#define STATUS2_UPROAR (1 << 4 | 1 << 5 | 1 << 6)
#define STATUS2_UPROAR_TURN(num) ((num) << 4)
#define STATUS2_TORMENT (1 << 7)
#define STATUS2_BIDE (1 << 8 | 1 << 9)
#define STATUS2_BIDE_TURN(num) (((num) << 8) & STATUS2_BIDE)
#define STATUS2_LOCK_CONFUSE (1 << 10 | 1 << 11) // e.g. Thrash
#define STATUS2_LOCK_CONFUSE_TURN(num)((num) << 10)
#define STATUS2_MULTIPLETURNS (1 << 12)
#define STATUS2_WRAPPED (1 << 13)
#define STATUS2_POWDER (1 << 14)
//#define STATUS2_UNUSED (1 << 15)
#define STATUS2_INFATUATION (1 << 16 | 1 << 17 | 1 << 18 | 1 << 19) // 4 bits, one for every battler
#define STATUS2_INFATUATED_WITH(battler) (1u << (battler + 16))
#define STATUS2_DEFENSE_CURL (1 << 20)
#define STATUS2_TRANSFORMED (1 << 21)
#define STATUS2_RECHARGE (1 << 22)
#define STATUS2_RAGE (1 << 23)
#define STATUS2_SUBSTITUTE (1 << 24)
#define STATUS2_DESTINY_BOND (1 << 25)
#define STATUS2_ESCAPE_PREVENTION (1 << 26)
#define STATUS2_NIGHTMARE (1 << 27)
#define STATUS2_CURSED (1 << 28)
#define STATUS2_FORESIGHT (1 << 29)
#define STATUS2_DRAGON_CHEER (1 << 30)
#define STATUS2_FOCUS_ENERGY (1 << 31)
#define STATUS2_FOCUS_ENERGY_ANY (STATUS2_DRAGON_CHEER | STATUS2_FOCUS_ENERGY)
#define STATUS3_LEECHSEED_BATTLER (1 << 0 | 1 << 1) // The battler to receive HP from Leech Seed
#define STATUS3_LEECHSEED (1 << 2)
#define STATUS3_ALWAYS_HITS (1 << 3 | 1 << 4)
#define STATUS3_ALWAYS_HITS_TURN(num) (((num) << 3) & STATUS3_ALWAYS_HITS) // "Always Hits" is set as a 2 turn timer, i.e. next turn is the last turn when it's active
#define STATUS3_PERISH_SONG (1 << 5)
#define STATUS3_ON_AIR (1 << 6)
#define STATUS3_UNDERGROUND (1 << 7)
#define STATUS3_UNUSED_6 (1 << 6)
#define STATUS3_UNUSED_7 (1 << 7)
#define STATUS3_MINIMIZED (1 << 8)
#define STATUS3_CHARGED_UP (1 << 9)
#define STATUS3_ROOTED (1 << 10)
@ -233,33 +208,39 @@ enum Volatile
#define STATUS3_YAWN_TURN(num) (((num) << 11) & STATUS3_YAWN)
#define STATUS3_IMPRISONED_OTHERS (1 << 13)
#define STATUS3_GRUDGE (1 << 14)
#define STATUS3_COMMANDER (1 << 15)
#define STATUS3_UNUSED_15 (1 << 15)
#define STATUS3_GASTRO_ACID (1 << 16)
#define STATUS3_EMBARGO (1 << 17)
#define STATUS3_UNDERWATER (1 << 18)
#define STATUS3_UNUSED_18 (1 << 18)
#define STATUS3_UNUSED_19 (1 << 19)
#define STATUS3_UNUSED_20 (1 << 20)
#define STATUS3_SMACKED_DOWN (1 << 21)
#define STATUS3_UNUSED_22 (1 << 22)
#define STATUS3_TELEKINESIS (1 << 23)
#define STATUS3_PHANTOM_FORCE (1 << 24)
#define STATUS3_UNUSED_24 (1 << 24)
#define STATUS3_MIRACLE_EYED (1 << 25)
#define STATUS3_MAGNET_RISE (1 << 26)
#define STATUS3_HEAL_BLOCK (1 << 27)
#define STATUS3_AQUA_RING (1 << 28)
#define STATUS3_LASER_FOCUS (1 << 29)
#define STATUS3_POWER_TRICK (1 << 30)
#define STATUS3_SKY_DROPPED (1 << 31) // Target of Sky Drop
#define STATUS3_SEMI_INVULNERABLE_NO_COMMANDER (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER | STATUS3_PHANTOM_FORCE) // Exception for Transform / Imposter
#define STATUS3_SEMI_INVULNERABLE (STATUS3_SEMI_INVULNERABLE_NO_COMMANDER | STATUS3_COMMANDER)
#define STATUS4_ELECTRIFIED (1 << 0)
#define STATUS4_MUD_SPORT (1 << 1) // Only used if B_SPORT_TURNS < GEN_6
#define STATUS4_WATER_SPORT (1 << 2) // Only used if B_SPORT_TURNS < GEN_6
#define STATUS4_INFINITE_CONFUSION (1 << 3) // Used for Berserk Gene
#define STATUS4_SALT_CURE (1 << 4)
#define STATUS4_SYRUP_BOMB (1 << 5)
#define STATUS4_GLAIVE_RUSH (1 << 6)
enum SemiInvulnerableState
{
STATE_NONE,
STATE_UNDERGROUND,
STATE_UNDERWATER,
STATE_ON_AIR,
STATE_PHANTOM_FORCE,
STATE_SKY_DROP,
STATE_COMMANDER,
};
enum SemiInvulnerableExclusion
{
CHECK_ALL,
EXCLUDE_COMMANDER,
};
#define HITMARKER_STRING_PRINTED (1 << 4)
#define HITMARKER_IGNORE_BIDE (1 << 5)

View File

@ -489,7 +489,7 @@ static inline u32 GetMoveTwoTurnAttackStringId(u32 moveId)
static inline u32 GetMoveTwoTurnAttackStatus(u32 moveId)
{
return UNCOMPRESS_BITS(gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.status);
return gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.status;
}
static inline u32 GetMoveTwoTurnAttackWeather(u32 moveId)

View File

@ -381,12 +381,7 @@ struct BattlePokemon
/*0x45*/ u32 experience;
/*0x49*/ u32 personality;
/*0x4D*/ u32 status1;
/*0x51*/ union {
struct {
u32 status2; // To be expanded to include Status3/4
};
struct Volatiles volatiles;
};
/*0x51*/ struct Volatiles volatiles;
/*0x5D*/ u32 otId;
/*0x61*/ u8 metLevel;
/*0x62*/ bool8 isShiny;

View File

@ -1083,7 +1083,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IsPowderMove(move) && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))
RETURN_SCORE_MINUS(10);
if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move, predictedMove, CONSIDER_PRIORITY))
if (!BreaksThroughSemiInvulnerablity(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move, predictedMove, CONSIDER_PRIORITY))
RETURN_SCORE_MINUS(10);
if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk))
@ -2363,7 +2363,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10); // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you
if (BattlerWillFaintFromWeather(battlerAtk, aiData->abilities[battlerAtk])
&& GetMoveTwoTurnAttackStatus(move) == STATUS3_ON_AIR)
&& GetMoveTwoTurnAttackStatus(move) == STATE_ON_AIR)
ADJUST_SCORE(-10); // Attacker will faint while in the air
break;
case EFFECT_HEALING_WISH: //healing wish, lunar dance
@ -4524,7 +4524,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|| predictedEffect == EFFECT_MISTY_EXPLOSION
|| predictedEffect == EFFECT_PROTECT))
ADJUST_SCORE(GOOD_EFFECT);
else if (predictedEffect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
else if (predictedEffect == EFFECT_SEMI_INVULNERABLE && !IsSemiInvulnerable(battlerDef, CHECK_ALL))
ADJUST_SCORE(GOOD_EFFECT);
}
break;

View File

@ -482,7 +482,7 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
u32 opposingBattler = GetOppositeBattler(battler);
u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData);
u32 incomingType = CheckDynamicMoveType(GetBattlerMon(opposingBattler), incomingMove, opposingBattler, MON_IN_BATTLE);
bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove));
bool32 isOpposingBattlerChargingOrInvulnerable = !BreaksThroughSemiInvulnerablity(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove);
s32 i, j;
if (!(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
@ -615,7 +615,7 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler)
u32 opposingBattler = GetOppositeBattler(battler);
u32 incomingMove = GetIncomingMove(battler, opposingBattler, gAiLogicData);
bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove));
bool32 isOpposingBattlerChargingOrInvulnerable = !BreaksThroughSemiInvulnerablity(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove);
if (IsDoubleBattle() || !(gAiThinkingStruct->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING))
return FALSE;
@ -2436,7 +2436,7 @@ static bool32 ShouldUseItem(u32 battler)
// If teaming up with player and Pokemon is on the right, or Pokemon is currently held by Sky Drop
if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT)
|| gStatuses3[battler] & STATUS3_SKY_DROPPED)
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
return FALSE;
if (gStatuses3[battler] & STATUS3_EMBARGO)

View File

@ -457,7 +457,9 @@ bool32 IsBattlerTrapped(u32 battlerAtk, u32 battlerDef)
return TRUE;
if (gBattleMons[battlerDef].volatiles.escapePrevention)
return TRUE;
if (gStatuses3[battlerDef] & (STATUS3_ROOTED | STATUS3_SKY_DROPPED))
if (gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_SKY_DROP)
return TRUE;
if (gStatuses3[battlerDef] & STATUS3_ROOTED)
return TRUE;
if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)
return TRUE;
@ -1860,60 +1862,6 @@ bool32 IsMoveRedirectionPrevented(u32 battlerAtk, u32 move, u32 atkAbility)
return FALSE;
}
bool32 IsSemiInvulnerable(u32 battlerDef, u32 move)
{
if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE)
return TRUE;
else if (gBattleStruct->battlerState[battlerDef].commandingDondozo)
return TRUE;
else if (!MoveDamagesAirborne(move) && gStatuses3[battlerDef] & STATUS3_ON_AIR)
return TRUE;
else if (!MoveDamagesUnderWater(move) && gStatuses3[battlerDef] & STATUS3_UNDERWATER)
return TRUE;
else if (!MoveDamagesUnderground(move) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND)
return TRUE;
else
return FALSE;
}
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move)
{
u32 weather;
if (IsSemiInvulnerable(battlerDef, move))
return FALSE;
//TODO - anticipate protect move?
// always hits
if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
return TRUE;
if (gAiLogicData->abilities[battlerDef] == ABILITY_NO_GUARD || gAiLogicData->abilities[battlerAtk] == ABILITY_NO_GUARD)
return TRUE;
u32 nonVolatileStatus = GetMoveNonVolatileStatus(move);
if (B_TOXIC_NEVER_MISS >= GEN_6
&& nonVolatileStatus == MOVE_EFFECT_TOXIC
&& IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
return TRUE;
// discouraged from hitting
weather = AI_GetWeather();
if ((weather & B_WEATHER_SUN) && MoveHas50AccuracyInSun(move))
return FALSE;
if ((weather & B_WEATHER_RAIN) && MoveAlwaysHitsInRain(move))
return TRUE;
if ((weather & B_WEATHER_ICY_ANY) && MoveAlwaysHitsInHailSnow(move))
return TRUE;
if (B_MINIMIZE_DMG_ACC >= GEN_6 && (gStatuses3[battlerDef] & STATUS3_MINIMIZED) && MoveIncreasesPowerToMinimizedTargets(move))
return TRUE;
if (GetMoveAccuracy(move) == 0)
return TRUE;
return FALSE;
}
bool32 ShouldTryOHKO(u32 battlerAtk, u32 battlerDef, u32 atkAbility, u32 defAbility, u32 move)
{
enum ItemHoldEffect holdEffect = gAiLogicData->holdEffects[battlerDef];
@ -1972,8 +1920,8 @@ bool32 IsBattlerDamagedByStatus(u32 battler)
|| gBattleMons[battler].volatiles.wrapped
|| gBattleMons[battler].volatiles.nightmare
|| gBattleMons[battler].volatiles.cursed
|| gBattleMons[battler].volatiles.saltCure
|| 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);
}
@ -2980,7 +2928,8 @@ static u32 GetWeatherDamage(u32 battlerId)
if (weather & B_WEATHER_SANDSTORM)
{
if (BattlerAffectedBySandstorm(battlerId, ability)
&& !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& gBattleMons[battlerId].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battlerId].volatiles.semiInvulnerable != STATE_UNDERWATER
&& holdEffect != HOLD_EFFECT_SAFETY_GOGGLES)
{
damage = GetNonDynamaxMaxHP(battlerId) / 16;
@ -2991,7 +2940,8 @@ static u32 GetWeatherDamage(u32 battlerId)
if ((weather & B_WEATHER_HAIL) && ability != ABILITY_ICE_BODY)
{
if (BattlerAffectedByHail(battlerId, ability)
&& !(gStatuses3[battlerId] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& gBattleMons[battlerId].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battlerId].volatiles.semiInvulnerable != STATE_UNDERWATER
&& holdEffect != HOLD_EFFECT_SAFETY_GOGGLES)
{
damage = GetNonDynamaxMaxHP(battlerId) / 16;

View File

@ -6871,7 +6871,7 @@ static void SwapBattlerMoveData(u32 battler1, u32 battler2)
SWAP(gBattleStruct->moveTarget[battler1], gBattleStruct->moveTarget[battler2], temp);
SWAP(gMoveSelectionCursor[battler1], gMoveSelectionCursor[battler2], temp);
SWAP(gLockedMoves[battler1], gLockedMoves[battler2], temp);
// update last moves
SWAP(gLastPrintedMoves[battler1], gLastPrintedMoves[battler2], temp);
SWAP(gLastMoves[battler1], gLastMoves[battler2], temp);
@ -6907,10 +6907,9 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp);
SWAP(gTransformedShininess[battlerAtk], gTransformedShininess[battlerPartner], temp);
SWAP(gStatuses3[battlerAtk], gStatuses3[battlerPartner], temp);
SWAP(gStatuses4[battlerAtk], gStatuses4[battlerPartner], temp);
SwapBattlerMoveData(battlerAtk, battlerPartner);
// Swap turn order, so that all the battlers take action
SWAP(gChosenActionByBattler[battlerAtk], gChosenActionByBattler[battlerPartner], temp);
for (i = 0; i < gBattlersCount; i++)

View File

@ -106,7 +106,6 @@ enum
LIST_ITEM_STATUS1,
LIST_ITEM_VOLATILE,
LIST_ITEM_STATUS3,
LIST_ITEM_STATUS4,
LIST_ITEM_HAZARDS,
LIST_ITEM_SIDE_STATUS,
LIST_ITEM_AI,
@ -147,8 +146,6 @@ enum
LIST_STATUS3_LEECH_SEEDED,
LIST_STATUS3_ALWAYS_HITS,
LIST_STATUS3_PERISH_SONG,
LIST_STATUS3_ON_AIR,
LIST_STATUS3_UNDERGROUND,
LIST_STATUS3_MINIMIZED,
LIST_STATUS3_CHARGED_UP,
LIST_STATUS3_ROOTED,
@ -157,7 +154,6 @@ enum
LIST_STATUS3_GRUDGE,
LIST_STATUS3_GASTRO_ACID,
LIST_STATUS3_EMBARGO,
LIST_STATUS3_UNDERWATER,
LIST_STATUS3_SMACKED_DOWN,
LIST_STATUS3_TELEKINESIS,
LIST_STATUS3_MIRACLE_EYED,
@ -168,14 +164,6 @@ enum
LIST_STATUS3_POWER_TRICK,
};
enum
{
LIST_STATUS4_ELECTRIFIED,
LIST_STATUS4_SALT_CURE,
LIST_STATUS4_SYRUP_BOMB,
LIST_STATUS4_GLAIVE_RUSH,
};
enum
{
LIST_SIDE_STICKY_WEB,
@ -314,16 +302,6 @@ static const struct BitfieldInfo sStatus3Bitfield[] =
{/*Power Trick*/ 1, 30},
};
static const struct BitfieldInfo sStatus4Bitfield[] =
{
{/*Electrified*/ 1, 0},
{/*Mud Sport*/ 1, 1},
{/*Water Sport*/ 1, 2},
{/*Salt Cure*/ 1, 4},
{/*Syrup Bomb*/ 1, 5},
{/*Glaive Rush*/ 1, 6},
};
static const struct BitfieldInfo sAIBitfield[] =
{
{/*Check Bad Move*/ 1, 0},
@ -369,7 +347,6 @@ static const struct ListMenuItem sMainListItems[] =
{COMPOUND_STRING("Status1"), LIST_ITEM_STATUS1},
{COMPOUND_STRING("Volatiles"), LIST_ITEM_VOLATILE},
{COMPOUND_STRING("Status3"), LIST_ITEM_STATUS3},
{COMPOUND_STRING("Status4"), LIST_ITEM_STATUS4},
{COMPOUND_STRING("Hazards"), LIST_ITEM_HAZARDS},
{COMPOUND_STRING("Side Status"), LIST_ITEM_SIDE_STATUS},
{COMPOUND_STRING("AI"), LIST_ITEM_AI},
@ -405,21 +382,26 @@ static const struct ListMenuItem sStatus1ListItems[] =
static const struct ListMenuItem sVolatileStatusListItems[] =
{
{COMPOUND_STRING("Confusion"), VOLATILE_CONFUSION},
{COMPOUND_STRING("Flinched"), VOLATILE_FLINCHED},
{COMPOUND_STRING("Torment"), VOLATILE_TORMENT},
{COMPOUND_STRING("Powder"), VOLATILE_POWDER},
{COMPOUND_STRING("DefenseCurl"), VOLATILE_DEFENSE_CURL},
{COMPOUND_STRING("Recharge"), VOLATILE_RECHARGE},
{COMPOUND_STRING("Rage"), VOLATILE_RAGE},
{COMPOUND_STRING("DestinyBond"), VOLATILE_DESTINY_BOND},
{COMPOUND_STRING("EscapePrevention"), VOLATILE_ESCAPE_PREVENTION},
{COMPOUND_STRING("Cursed"), VOLATILE_CURSED},
{COMPOUND_STRING("Foresight"), VOLATILE_FORESIGHT},
{COMPOUND_STRING("DragonCheer"), VOLATILE_DRAGON_CHEER},
{COMPOUND_STRING("FocusEnergy"), VOLATILE_FOCUS_ENERGY},
{COMPOUND_STRING("MudSport"), VOLATILE_MUD_SPORT},
{COMPOUND_STRING("WaterSport"), VOLATILE_WATER_SPORT},
{COMPOUND_STRING("Confusion"), VOLATILE_CONFUSION},
{COMPOUND_STRING("Flinched"), VOLATILE_FLINCHED},
{COMPOUND_STRING("Torment"), VOLATILE_TORMENT},
{COMPOUND_STRING("Powder"), VOLATILE_POWDER},
{COMPOUND_STRING("DefenseCurl"), VOLATILE_DEFENSE_CURL},
{COMPOUND_STRING("Recharge"), VOLATILE_RECHARGE},
{COMPOUND_STRING("Rage"), VOLATILE_RAGE},
{COMPOUND_STRING("DestinyBond"), VOLATILE_DESTINY_BOND},
{COMPOUND_STRING("EscapePrevention"), VOLATILE_ESCAPE_PREVENTION},
{COMPOUND_STRING("Cursed"), VOLATILE_CURSED},
{COMPOUND_STRING("Foresight"), VOLATILE_FORESIGHT},
{COMPOUND_STRING("DragonCheer"), VOLATILE_DRAGON_CHEER},
{COMPOUND_STRING("FocusEnergy"), VOLATILE_FOCUS_ENERGY},
{COMPOUND_STRING("Electrified"), VOLATILE_ELECTRIFIED},
{COMPOUND_STRING("MudSport"), VOLATILE_MUD_SPORT},
{COMPOUND_STRING("WaterSport"), VOLATILE_WATER_SPORT},
{COMPOUND_STRING("Infinite Confusion"), VOLATILE_INFINITE_CONFUSION},
{COMPOUND_STRING("Salt Cure"), VOLATILE_SALT_CURE},
{COMPOUND_STRING("Syrup Bomb"), VOLATILE_SYRUP_BOMB},
{COMPOUND_STRING("Glaive Rush"), VOLATILE_GLAIVE_RUSH},
};
static const struct ListMenuItem sStatus3ListItems[] =
@ -428,8 +410,6 @@ static const struct ListMenuItem sStatus3ListItems[] =
{COMPOUND_STRING("Leech Seeded"), LIST_STATUS3_LEECH_SEEDED},
{COMPOUND_STRING("Always Hits"), LIST_STATUS3_ALWAYS_HITS},
{COMPOUND_STRING("Perish Song"), LIST_STATUS3_PERISH_SONG},
{COMPOUND_STRING("On Air"), LIST_STATUS3_ON_AIR},
{COMPOUND_STRING("Underground"), LIST_STATUS3_UNDERGROUND},
{COMPOUND_STRING("Minimized"), LIST_STATUS3_MINIMIZED},
{COMPOUND_STRING("Charged Up"), LIST_STATUS3_CHARGED_UP},
{COMPOUND_STRING("Rooted"), LIST_STATUS3_ROOTED},
@ -438,7 +418,6 @@ static const struct ListMenuItem sStatus3ListItems[] =
{COMPOUND_STRING("Grudge"), LIST_STATUS3_GRUDGE},
{COMPOUND_STRING("Gastro Acid"), LIST_STATUS3_GASTRO_ACID},
{COMPOUND_STRING("Embargo"), LIST_STATUS3_EMBARGO},
{COMPOUND_STRING("Underwater"), LIST_STATUS3_UNDERWATER},
{COMPOUND_STRING("Smacked Down"), LIST_STATUS3_SMACKED_DOWN},
{COMPOUND_STRING("Telekinesis"), LIST_STATUS3_TELEKINESIS},
{COMPOUND_STRING("Miracle Eyed"), LIST_STATUS3_MIRACLE_EYED},
@ -449,14 +428,6 @@ static const struct ListMenuItem sStatus3ListItems[] =
{COMPOUND_STRING("Power Trick"), LIST_STATUS3_POWER_TRICK},
};
static const struct ListMenuItem sStatus4ListItems[] =
{
{COMPOUND_STRING("Electrified"), LIST_STATUS4_ELECTRIFIED},
{COMPOUND_STRING("Salt Cure"), LIST_STATUS4_SALT_CURE},
{COMPOUND_STRING("Syrup Bomb"), LIST_STATUS4_SYRUP_BOMB},
{COMPOUND_STRING("Glaive Rush"), LIST_STATUS4_GLAIVE_RUSH},
};
static const struct ListMenuItem sHazardsListItems[] =
{
{COMPOUND_STRING("Spikes"), LIST_SIDE_SPIKES},
@ -822,7 +793,7 @@ static void PutMovesPointsText(struct BattleDebugMenu *data)
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, COMPOUND_STRING("Chosen move: "), 74, 64, 0, NULL);
AddTextPrinterParameterized(data->aiMovesWindowId, FONT_NORMAL, GetMoveName(gBattleMons[data->aiBattlerId].moves[chosenMoveIndex]), 74 + 68, 64, 0, NULL);
}
CopyWindowToVram(data->aiMovesWindowId, COPYWIN_FULL);
Free(text);
}
@ -1437,11 +1408,6 @@ static void CreateSecondaryListMenu(struct BattleDebugMenu *data)
itemsCount = ARRAY_COUNT(sStatus3ListItems);
data->bitfield = sStatus3Bitfield;
break;
case LIST_ITEM_STATUS4:
listTemplate.items = sStatus4ListItems;
itemsCount = ARRAY_COUNT(sStatus4ListItems);
data->bitfield = sStatus4Bitfield;
break;
case LIST_ITEM_AI:
listTemplate.items = sAIListItems;
itemsCount = ARRAY_COUNT(sAIListItems);
@ -2084,11 +2050,6 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data)
data->modifyArrows.currValue = GetBitfieldValue(gStatuses3[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
goto CASE_ITEM_STATUS;
case LIST_ITEM_STATUS4:
data->modifyArrows.modifiedValPtr = &gStatuses4[data->battlerId];
data->modifyArrows.currValue = GetBitfieldValue(gStatuses4[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);
data->modifyArrows.typeOfVal = VAL_BITFIELD_32;
goto CASE_ITEM_STATUS;
case LIST_ITEM_AI:
data->modifyArrows.modifiedValPtr = &gAiThinkingStruct->aiFlags[data->battlerId];
data->modifyArrows.currValue = GetBitfieldValue(gAiThinkingStruct->aiFlags[data->battlerId], data->bitfield[data->currentSecondaryListItemId].currBit, data->bitfield[data->currentSecondaryListItemId].bitsCount);

View File

@ -232,9 +232,10 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler)
&& ability != ABILITY_SAND_FORCE
&& ability != ABILITY_SAND_RUSH
&& ability != ABILITY_OVERCOAT
&& !IS_BATTLER_ANY_TYPE(gBattlerAttacker, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)
&& !(gStatuses3[gBattlerAttacker] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES
&& !IS_BATTLER_ANY_TYPE(battler, TYPE_ROCK, TYPE_GROUND, TYPE_STEEL)
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER
&& GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES
&& !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD))
{
gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16;
@ -257,7 +258,8 @@ static bool32 HandleEndTurnWeatherDamage(u32 battler)
if (ability != ABILITY_SNOW_CLOAK
&& ability != ABILITY_OVERCOAT
&& !IS_BATTLER_OF_TYPE(battler, TYPE_ICE)
&& !(gStatuses3[battler] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER
&& GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES
&& !IsAbilityAndRecord(battler, ability, ABILITY_MAGIC_GUARD))
{
@ -306,7 +308,7 @@ static bool32 HandleEndTurnEmergencyExit(u32 battler)
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
&& CountUsablePartyMons(battler) > 0
&& !(gStatuses3[battler] & STATUS3_SKY_DROPPED)) // Not currently held by Sky Drop
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP) // Not currently held by Sky Drop
{
gBattlerAbility = battler;
gLastUsedAbility = ability;
@ -458,7 +460,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
gBattleStruct->eventBlockCounter++;
break;
case FIRST_EVENT_BLOCK_THRASH:
if (gBattleMons[battler].volatiles.lockConfusionTurns && !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
if (gBattleMons[battler].volatiles.lockConfusionTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
{
gBattleMons[battler].volatiles.lockConfusionTurns--;
if (WasUnableToUseMove(battler))
@ -484,7 +486,8 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN
&& IsBattlerAlive(battler)
&& !IsBattlerAtMaxHp(battler)
&& !(gStatuses3[battler] & (STATUS3_SEMI_INVULNERABLE | STATUS3_HEAL_BLOCK))
&& !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)
&& !IsSemiInvulnerable(battler, CHECK_ALL)
&& IsBattlerGrounded(battler))
{
gBattlerAttacker = battler;
@ -795,7 +798,7 @@ static bool32 HandleEndTurnSaltCure(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if (gStatuses4[battler] & STATUS4_SALT_CURE
if (gBattleMons[battler].volatiles.saltCure
&& IsBattlerAlive(battler)
&& !IsAbilityAndRecord(battler, GetBattlerAbility(battler), ABILITY_MAGIC_GUARD))
{
@ -836,10 +839,10 @@ static bool32 HandleEndTurnSyrupBomb(u32 battler)
gBattleStruct->turnEffectsBattlerId++;
if ((gStatuses4[battler] & STATUS4_SYRUP_BOMB) && (IsBattlerAlive(battler)))
if (gBattleMons[battler].volatiles.syrupBomb && (IsBattlerAlive(battler)))
{
if (gDisableStructs[battler].syrupBombTimer > 0 && --gDisableStructs[battler].syrupBombTimer == 0)
gStatuses4[battler] &= ~STATUS4_SYRUP_BOMB;
gBattleMons[battler].volatiles.syrupBomb = FALSE;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SYRUP_BOMB);
gBattlescriptCurrInstr = BattleScript_SyrupBombEndTurn;
BattleScriptExecute(gBattlescriptCurrInstr);

View File

@ -194,7 +194,6 @@ EWRAM_DATA u8 gBideTarget[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u32 gSideStatuses[NUM_BATTLE_SIDES] = {0};
EWRAM_DATA struct SideTimer gSideTimers[NUM_BATTLE_SIDES] = {0};
EWRAM_DATA u32 gStatuses3[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u32 gStatuses4[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT] = {0};
EWRAM_DATA u16 gPauseCounterBattle = 0;
EWRAM_DATA u16 gPaydayMoney = 0;
@ -3028,7 +3027,6 @@ static void BattleStartClearSetData(void)
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
gStatuses3[i] = 0;
gStatuses4[i] = 0;
gDisableStructs[i].isFirstTurn = 2;
gLastMoves[i] = MOVE_NONE;
gLastLandedMoves[i] = MOVE_NONE;
@ -3174,7 +3172,6 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED
| STATUS3_GASTRO_ACID | STATUS3_EMBARGO | STATUS3_TELEKINESIS | STATUS3_MAGNET_RISE | STATUS3_HEAL_BLOCK
| STATUS3_AQUA_RING | STATUS3_POWER_TRICK);
gStatuses4[battler] &= STATUS4_INFINITE_CONFUSION;
for (i = 0; i < gBattlersCount; i++)
{
if (!IsBattlerAlly(battler, i)
@ -3191,7 +3188,6 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
else
{
gStatuses3[battler] = 0;
gStatuses4[battler] = 0;
}
for (i = 0; i < gBattlersCount; i++)
@ -3200,8 +3196,8 @@ void SwitchInClearSetData(u32 battler, struct Volatiles *volatilesCopy)
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;
if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler)
gBattleMons[i].volatiles.syrupBomb = FALSE;
}
gActionSelectionCursor[battler] = 0;
@ -3308,7 +3304,6 @@ const u8* FaintClearSetData(u32 battler)
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++)
{
@ -3318,8 +3313,8 @@ const u8* FaintClearSetData(u32 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;
if (gBattleMons[i].volatiles.syrupBomb && gBattleStruct->stickySyrupdBy[i] == battler)
gBattleMons[i].volatiles.syrupBomb = FALSE;
}
gActionSelectionCursor[battler] = 0;
@ -3410,10 +3405,10 @@ const u8* FaintClearSetData(u32 battler)
gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET;
// If the other Pokemon involved in this Sky Drop was the target, not the attacker
if (gStatuses3[otherSkyDropper] & STATUS3_SKY_DROPPED)
if (gBattleMons[otherSkyDropper].volatiles.semiInvulnerable == STATE_SKY_DROP)
{
// Release the target and take them out of the semi-invulnerable state
gStatuses3[otherSkyDropper] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
gBattleMons[otherSkyDropper].volatiles.semiInvulnerable = STATE_NONE;
// Make the target's sprite visible
gSprites[gBattlerSpriteIds[otherSkyDropper]].invisible = FALSE;
@ -4019,7 +4014,7 @@ void BattleTurnPassed(void)
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
gBattleStruct->monToSwitchIntoId[i] = PARTY_SIZE;
gStatuses4[i] &= ~STATUS4_ELECTRIFIED;
gBattleMons[i].volatiles.electrified = FALSE;
gBattleMons[i].volatiles.flinched = FALSE;
gBattleMons[i].volatiles.powder = FALSE;
@ -4308,7 +4303,7 @@ static void HandleTurnActionSelectionState(void)
| BATTLE_TYPE_RECORDED_LINK))
&& !gTestRunnerEnabled)
// Or if currently held by Sky Drop
|| gStatuses3[battler] & STATUS3_SKY_DROPPED)
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
{
RecordedBattle_ClearBattlerAction(battler, 1);
gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed;
@ -5133,7 +5128,7 @@ static void TurnValuesCleanUp(bool8 var0)
if (gDisableStructs[i].substituteHP == 0)
gBattleMons[i].volatiles.substitute = FALSE;
if (!(gStatuses3[i] & STATUS3_COMMANDER))
if (gBattleMons[i].volatiles.semiInvulnerable != STATE_COMMANDER)
gBattleStruct->battlerState[i].commandingDondozo = FALSE;
gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF;
@ -6083,7 +6078,8 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler)
gBattleStruct->dynamicMoveType = moveType | F_DYNAMIC_TYPE_SET;
moveType = GetBattleMoveType(move);
if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL) || gStatuses4[battler] & STATUS4_ELECTRIFIED)
if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL)
|| gBattleMons[battler].volatiles.electrified)
gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | F_DYNAMIC_TYPE_SET;
// Check if a gem should activate.

View File

@ -407,7 +407,7 @@ static void Cmd_jumpifabilitypresent(void);
static void Cmd_endselectionscript(void);
static void Cmd_playanimation(void);
static void Cmd_playanimation_var(void);
static void Cmd_unused_0x47(void);
static void Cmd_jumpfifsemiinvulnerable(void);
static void Cmd_unused_0x48(void);
static void Cmd_moveend(void);
static void Cmd_sethealblock(void);
@ -666,7 +666,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
Cmd_endselectionscript, //0x44
Cmd_playanimation, //0x45
Cmd_playanimation_var, //0x46
Cmd_unused_0x47, //0x47
Cmd_jumpfifsemiinvulnerable, //0x47
Cmd_unused_0x48, //0x48
Cmd_moveend, //0x49
Cmd_sethealblock, //0x4A
@ -1079,7 +1079,7 @@ bool32 EmergencyExitCanBeTriggered(u32 battler)
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
&& CountUsablePartyMons(battler) > 0
&& !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
return TRUE;
return FALSE;
@ -1366,7 +1366,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
{
if (gStatuses3[gBattlerTarget] & STATUS3_ALWAYS_HITS && gDisableStructs[gBattlerTarget].battlerWithSureHit == gBattlerAttacker)
gBattlescriptCurrInstr = nextInstr;
else if (gStatuses3[gBattlerTarget] & (STATUS3_SEMI_INVULNERABLE))
else if (IsSemiInvulnerable(gBattlerTarget, CHECK_ALL))
gBattlescriptCurrInstr = failInstr;
else if (!JumpIfMoveAffectedByProtect(gCurrentMove, gBattlerTarget, TRUE, failInstr))
gBattlescriptCurrInstr = nextInstr;
@ -3372,7 +3372,7 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
break;
case MOVE_EFFECT_FLAME_BURST:
if (IsBattlerAlive(BATTLE_PARTNER(gBattlerTarget))
&& !(gStatuses3[BATTLE_PARTNER(gBattlerTarget)] & STATUS3_SEMI_INVULNERABLE)
&& !IsSemiInvulnerable(BATTLE_PARTNER(gBattlerTarget), CHECK_ALL)
&& GetBattlerAbility(BATTLE_PARTNER(gBattlerTarget)) != ABILITY_MAGIC_GUARD)
{
gBattleScripting.battler = i = BATTLE_PARTNER(gBattlerTarget);
@ -3513,11 +3513,11 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
}
break;
case MOVE_EFFECT_SYRUP_BOMB:
if (!(gStatuses4[gEffectBattler] & STATUS4_SYRUP_BOMB))
if (!gBattleMons[gEffectBattler].volatiles.syrupBomb)
{
struct Pokemon *mon = GetBattlerMon(gBattlerAttacker);
gStatuses4[gEffectBattler] |= STATUS4_SYRUP_BOMB;
gBattleMons[gEffectBattler].volatiles.syrupBomb = TRUE;
gDisableStructs[gEffectBattler].syrupBombTimer = 3;
gDisableStructs[gEffectBattler].syrupBombIsShiny = IsMonShiny(mon);
gBattleStruct->stickySyrupdBy[gEffectBattler] = gBattlerAttacker;
@ -3655,9 +3655,9 @@ void SetMoveEffect(u32 battler, u32 effectBattler, bool32 primary, bool32 certai
}
break;
case MOVE_EFFECT_SALT_CURE:
if (!(gStatuses4[gBattlerTarget] & STATUS4_SALT_CURE))
if (!gBattleMons[gBattlerTarget].volatiles.saltCure)
{
gStatuses4[gBattlerTarget] |= STATUS4_SALT_CURE;
gBattleMons[gBattlerTarget].volatiles.saltCure = TRUE;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_MoveEffectSaltCure;
}
@ -5455,7 +5455,7 @@ static void PlayAnimation(u32 battler, u8 animId, const u16 *argPtr, const u8 *n
MarkBattlerForControllerExec(battler);
gBattlescriptCurrInstr = nextInstr;
}
else if (gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE)
else if (IsSemiInvulnerable(battler, CHECK_ALL))
{
gBattlescriptCurrInstr = nextInstr;
}
@ -5484,8 +5484,15 @@ static void Cmd_playanimation_var(void)
PlayAnimation(battler, *(cmd->animIdPtr), cmd->argPtr, cmd->nextInstr);
}
static void Cmd_unused_0x47(void)
static void Cmd_jumpfifsemiinvulnerable(void)
{
CMD_ARGS(u8 battler, u8 state, const u8 *jumpInstr);
u32 battler = GetBattlerForBattleScript(cmd->battler);
if (gBattleMons[battler].volatiles.semiInvulnerable == cmd->state)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
}
static void Cmd_unused_0x48(void)
@ -5764,7 +5771,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
if (IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerTarget)
&& IsBattlerAlive(gBattlerAttacker)
&& !(gStatuses3[BATTLE_PARTNER(gBattlerTarget)] & STATUS3_COMMANDER))
&& gBattleMons[BATTLE_PARTNER(gBattlerTarget)].volatiles.semiInvulnerable != STATE_COMMANDER)
{
u32 targetAbility = GetBattlerAbility(gBattlerTarget);
if (targetAbility == ABILITY_GUARD_DOG)
@ -5796,8 +5803,9 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
&& IsBattlerAlive(gBattlerTarget)
&& !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove))
{
gBattleMons[gBattlerTarget].volatiles.semiInvulnerable = STATE_NONE;
gStatuses3[gBattlerTarget] |= STATUS3_SMACKED_DOWN;
gStatuses3[gBattlerTarget] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS | STATUS3_ON_AIR);
gStatuses3[gBattlerTarget] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS);
BattleScriptCall(BattleScript_MoveEffectSmackDown);
effect = TRUE;
}
@ -6156,7 +6164,7 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++;
break;
case MOVEEND_ATTACKER_INVISIBLE: // make attacker sprite invisible
if (gStatuses3[gBattlerAttacker] & (STATUS3_SEMI_INVULNERABLE)
if (IsSemiInvulnerable(gBattlerAttacker, CHECK_ALL)
&& gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION))
{
BtlController_EmitSpriteInvisibility(gBattlerAttacker, B_COMM_TO_CONTROLLER, TRUE);
@ -6168,12 +6176,12 @@ static void Cmd_moveend(void)
break;
case MOVEEND_ATTACKER_VISIBLE: // make attacker sprite visible
if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT
|| !(gStatuses3[gBattlerAttacker] & (STATUS3_SEMI_INVULNERABLE))
|| !IsSemiInvulnerable(gBattlerAttacker, CHECK_ALL)
|| WasUnableToUseMove(gBattlerAttacker))
{
BtlController_EmitSpriteInvisibility(gBattlerAttacker, B_COMM_TO_CONTROLLER, FALSE);
MarkBattlerForControllerExec(gBattlerAttacker);
gStatuses3[gBattlerAttacker] &= ~STATUS3_SEMI_INVULNERABLE;
gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable = STATE_NONE;
gSpecialStatuses[gBattlerAttacker].restoredBattlerSprite = TRUE;
gBattleScripting.moveendState++;
return;
@ -6182,11 +6190,11 @@ static void Cmd_moveend(void)
break;
case MOVEEND_TARGET_VISIBLE: // make target sprite visible
if (!gSpecialStatuses[gBattlerTarget].restoredBattlerSprite && gBattlerTarget < gBattlersCount
&& !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE))
&& !IsSemiInvulnerable(gBattlerTarget, CHECK_ALL))
{
BtlController_EmitSpriteInvisibility(gBattlerTarget, B_COMM_TO_CONTROLLER, FALSE);
MarkBattlerForControllerExec(gBattlerTarget);
gStatuses3[gBattlerTarget] &= ~STATUS3_SEMI_INVULNERABLE;
gBattleMons[gBattlerTarget].volatiles.semiInvulnerable = STATE_NONE;
gBattleScripting.moveendState++;
return;
}
@ -6927,7 +6935,7 @@ static void Cmd_moveend(void)
u32 partner = BATTLE_PARTNER(i);
gBattleStruct->battlerState[i].commanderSpecies = SPECIES_NONE;
if (IsBattlerAlive(partner))
gStatuses3[partner] &= ~STATUS3_COMMANDER;
gBattleMons[partner].volatiles.semiInvulnerable = STATE_NONE;
}
}
@ -8468,7 +8476,7 @@ static void Cmd_statusanimation(void)
{
u32 battler = GetBattlerForBattleScript(cmd->battler),
statusFlag = (cmd->isVolatile || cmd->status) ? cmd->status : gBattleMons[battler].status1;
if (!(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE)
if (!IsSemiInvulnerable(battler, CHECK_ALL)
&& gDisableStructs[battler].substituteHP == 0
&& !(gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION)))
{
@ -9322,7 +9330,7 @@ static bool32 IsRototillerAffected(u32 battler)
return FALSE; // Only grounded battlers affected
if (!IS_BATTLER_OF_TYPE(battler, TYPE_GRASS))
return FALSE; // Only grass types affected
if (gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE)
if (IsSemiInvulnerable(battler, CHECK_ALL))
return FALSE; // Rototiller doesn't affected semi-invulnerable battlers
if (BlocksPrankster(MOVE_ROTOTILLER, gBattlerAttacker, battler, FALSE))
return FALSE;
@ -9352,7 +9360,7 @@ static bool32 IsTeatimeAffected(u32 battler)
{
if (GetItemPocket(gBattleMons[battler].item) != POCKET_BERRIES)
return FALSE; // Only berries
if (gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE)
if (IsSemiInvulnerable(battler, CHECK_ALL))
return FALSE; // Teatime doesn't affected semi-invulnerable battlers
return TRUE;
}
@ -11151,7 +11159,7 @@ static void Cmd_transformdataexecution(void)
gBattlescriptCurrInstr = cmd->nextInstr;
if (gBattleMons[gBattlerTarget].volatiles.transformed
|| gBattleStruct->illusion[gBattlerTarget].state == ILLUSION_ON
|| gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER)
|| IsSemiInvulnerable(gBattlerTarget, EXCLUDE_COMMANDER))
{
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_FAILED;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TRANSFORM_FAILED;
@ -11552,7 +11560,7 @@ static void Cmd_settypetorandomresistance(void)
{
gBattlescriptCurrInstr = cmd->failInstr;
}
else if (IsSemiInvulnerable(gBattlerTarget, gCurrentMove))
else if (!BreaksThroughSemiInvulnerablity(gBattlerTarget, gCurrentMove))
{
gBattlescriptCurrInstr = cmd->failInstr;
}
@ -11705,7 +11713,7 @@ static void Cmd_trychoosesleeptalkmove(void)
gCalledMove = gBattleMons[gBattlerAttacker].moves[movePosition];
}
gCurrMovePos = movePosition;
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED;
gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE);
gBattlescriptCurrInstr = cmd->failInstr;
}
@ -12005,7 +12013,7 @@ static void Cmd_trysetperishsong(void)
if (gStatuses3[i] & STATUS3_PERISH_SONG
|| GetBattlerAbility(i) == ABILITY_SOUNDPROOF
|| BlocksPrankster(gCurrentMove, gBattlerAttacker, i, TRUE)
|| gStatuses3[i] & STATUS3_COMMANDER)
|| gBattleMons[i].volatiles.semiInvulnerable == STATE_COMMANDER)
{
notAffectedCount++;
}
@ -12557,9 +12565,9 @@ static void Cmd_setsemiinvulnerablebit(void)
{
u32 semiInvulnerableEffect = GetMoveTwoTurnAttackStatus(gCurrentMove);
if (cmd->clear)
gStatuses3[gBattlerAttacker] &= ~semiInvulnerableEffect;
gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable = STATE_NONE;
else
gStatuses3[gBattlerAttacker] |= semiInvulnerableEffect;
gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable = semiInvulnerableEffect;
}
gBattlescriptCurrInstr = cmd->nextInstr;
@ -12618,7 +12626,7 @@ static void Cmd_trymemento(void)
if (B_MEMENTO_FAIL >= GEN_4
&& (gBattleCommunication[MISS_TYPE] == B_MSG_PROTECTED
|| gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE
|| IsSemiInvulnerable(gBattlerTarget, CHECK_ALL)
|| IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove)
|| DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)))
{
@ -15094,7 +15102,7 @@ void BS_ItemCureStatus(void)
if (GetItemStatus1Mask(gLastUsedItem) & STATUS1_SLEEP)
gBattleMons[battler].volatiles.nightmare = FALSE;
if (ItemHasVolatileFlag(gLastUsedItem, VOLATILE_CONFUSION))
gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION;
gBattleMons[battler].volatiles.infiniteConfusion = FALSE;
}
if (statusChanged)
@ -15234,15 +15242,6 @@ void BS_JumpIfElectricAbilityAffected(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_ApplySaltCure(void)
{
NATIVE_ARGS(u8 battler);
u8 battler = GetBattlerForBattleScript(cmd->battler);
gStatuses4[battler] |= STATUS4_SALT_CURE;
gBattlescriptCurrInstr = cmd->nextInstr;
}
void BS_SetTerrain(void)
{
NATIVE_ARGS(const u8 *jumpInstr);
@ -15362,7 +15361,7 @@ void BS_TrySetOctolock(void)
void BS_SetGlaiveRush(void)
{
NATIVE_ARGS();
gStatuses4[gBattlerAttacker] |= STATUS4_GLAIVE_RUSH;
gBattleMons[gBattlerAttacker].volatiles.glaiveRush = TRUE;
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -15985,7 +15984,7 @@ void BS_TeatimeInvul(void)
NATIVE_ARGS(u8 battler, const u8 *jumpInstr);
u32 battler = GetBattlerForBattleScript(cmd->battler);
if (GetItemPocket(gBattleMons[battler].item) == POCKET_BERRIES && !(gStatuses3[gBattlerTarget] & (STATUS3_SEMI_INVULNERABLE)))
if (GetItemPocket(gBattleMons[battler].item) == POCKET_BERRIES && !IsSemiInvulnerable(gBattlerTarget, CHECK_ALL))
gBattlescriptCurrInstr = cmd->nextInstr;
else
gBattlescriptCurrInstr = cmd->jumpInstr;
@ -16107,7 +16106,7 @@ void BS_JumpIfCommanderActive(void)
if (gBattleStruct->battlerState[gBattlerTarget].commanderSpecies != SPECIES_NONE)
gBattlescriptCurrInstr = cmd->jumpInstr;
else if (gStatuses3[gBattlerTarget] & STATUS3_COMMANDER)
else if (gBattleMons[gBattlerTarget].volatiles.semiInvulnerable == STATE_COMMANDER)
gBattlescriptCurrInstr = cmd->jumpInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;
@ -16887,10 +16886,11 @@ void BS_GravityOnAirborneMons(void)
{
NATIVE_ARGS();
// Cancel all multiturn moves of IN_AIR Pokemon except those being targeted by Sky Drop.
if (gStatuses3[gBattlerTarget] & STATUS3_ON_AIR && !(gStatuses3[gBattlerTarget] & STATUS3_SKY_DROPPED))
if (gBattleMons[gBattlerTarget].volatiles.semiInvulnerable == STATE_ON_AIR)
CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_GRAVITY_ON_AIRBORNE);
gStatuses3[gBattlerTarget] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS | STATUS3_ON_AIR | STATUS3_SKY_DROPPED);
gBattleMons[gBattlerTarget].volatiles.semiInvulnerable = STATE_NONE;
gStatuses3[gBattlerTarget] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS);
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -17460,7 +17460,7 @@ void BS_TryElectrify(void)
}
else
{
gStatuses4[gBattlerTarget] |= STATUS4_ELECTRIFIED;
gBattleMons[gBattlerTarget].volatiles.electrified = TRUE;
gBattlescriptCurrInstr = cmd->nextInstr;
}
}
@ -17964,7 +17964,7 @@ void BS_JumpIfUnder200(void)
void BS_SetSkyDrop(void)
{
NATIVE_ARGS();
gStatuses3[gBattlerTarget] |= (STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
gBattleMons[gBattlerTarget].volatiles.semiInvulnerable = STATE_SKY_DROP;
/* skyDropTargets holds the information of who is in a particular instance of Sky Drop.
This is needed in the case that multiple Pokemon use Sky Drop in the same turn or if
the target of a Sky Drop faints while in the air.*/
@ -17998,7 +17998,7 @@ void BS_ClearSkyDrop(void)
{
gBattleStruct->skyDropTargets[gBattlerAttacker] = SKY_DROP_NO_TARGET;
gBattleStruct->skyDropTargets[gBattlerTarget] = SKY_DROP_NO_TARGET;
gStatuses3[gBattlerTarget] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
gBattleMons[gBattlerTarget].volatiles.semiInvulnerable = STATE_NONE;
gBattlescriptCurrInstr = cmd->nextInstr;
}
@ -18010,7 +18010,7 @@ void BS_ClearSkyDrop(void)
void BS_SkyDropYawn(void)
{
NATIVE_ARGS();
if (gBattleStruct->skyDropTargets[gEffectBattler] != SKY_DROP_NO_TARGET && !(gStatuses3[gEffectBattler] & STATUS3_SKY_DROPPED))
if (gBattleStruct->skyDropTargets[gEffectBattler] != SKY_DROP_NO_TARGET && gBattleMons[gEffectBattler].volatiles.semiInvulnerable != STATE_SKY_DROP)
{
// Set the target of Sky Drop as gEffectBattler
gEffectBattler = gBattleStruct->skyDropTargets[gEffectBattler];

View File

@ -1047,7 +1047,7 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState)
const u8 *result = NULL;
u8 otherSkyDropper = gBattleStruct->skyDropTargets[battler];
gStatuses3[otherSkyDropper] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
gBattleMons[battler].volatiles.semiInvulnerable = STATE_NONE;
// Makes both attacker and target's sprites visible
gSprites[gBattlerSpriteIds[battler]].invisible = FALSE;
@ -1075,9 +1075,9 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState)
}
else if (skyDropState == SKY_DROP_GRAVITY_ON_AIRBORNE)
{
// Reapplying STATUS3_SKY_DROPPED allows for avoiding unecessary messages when Gravity is applied to the target.
// Reapplying STATE_SKY_DROPPED allows for avoiding unecessary messages when Gravity is applied to the target.
gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET;
gStatuses3[otherSkyDropper] |= STATUS3_SKY_DROPPED;
gBattleMons[otherSkyDropper].volatiles.semiInvulnerable = STATE_SKY_DROP;
}
else if (skyDropState == SKY_DROP_CANCEL_MULTI_TURN_MOVES)
{
@ -1121,10 +1121,10 @@ const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState)
}
// Clear battler's semi-invulnerable bits if they are not held by Sky Drop.
if (!(gStatuses3[battler] & STATUS3_SKY_DROPPED))
gStatuses3[battler] &= ~(STATUS3_SEMI_INVULNERABLE);
if (gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
gBattleMons[battler].volatiles.semiInvulnerable = STATE_NONE;
if (gBattleStruct->skyDropTargets[battler] != SKY_DROP_NO_TARGET && !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
if (gBattleStruct->skyDropTargets[battler] != SKY_DROP_NO_TARGET && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
result = CheckSkyDropState(battler, skyDropState);
gDisableStructs[battler].rolloutTimer = 0;
@ -1893,7 +1893,7 @@ static enum MoveCanceller CancellerFlags(void)
{
gBattleMons[gBattlerAttacker].volatiles.destinyBond = FALSE;
gStatuses3[gBattlerAttacker] &= ~STATUS3_GRUDGE;
gStatuses4[gBattlerAttacker] &= ~STATUS4_GLAIVE_RUSH;
gBattleMons[gBattlerAttacker].volatiles.glaiveRush = FALSE;
return MOVE_STEP_SUCCESS;
}
@ -1907,7 +1907,7 @@ static enum MoveCanceller CancellerStanceChangeOne(void)
static enum MoveCanceller CancellerSkyDrop(void)
{
// If Pokemon is being held in Sky Drop
if (gStatuses3[gBattlerAttacker] & STATUS3_SKY_DROPPED)
if (gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable == STATE_SKY_DROP)
{
gBattlescriptCurrInstr = BattleScript_MoveEnd;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
@ -2157,7 +2157,7 @@ static enum MoveCanceller CancellerConfused(void)
if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns)
{
if (!(gStatuses4[gBattlerAttacker] & STATUS4_INFINITE_CONFUSION))
if (!gBattleMons[gBattlerAttacker].volatiles.infiniteConfusion)
gBattleMons[gBattlerAttacker].volatiles.confusionTurns--;
if (gBattleMons[gBattlerAttacker].volatiles.confusionTurns)
{
@ -3577,7 +3577,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
&& !gBattleMons[diagonalBattler].volatiles.transformed
&& !gBattleMons[battler].volatiles.transformed
&& gBattleStruct->illusion[diagonalBattler].state != ILLUSION_ON
&& !(gStatuses3[diagonalBattler] & STATUS3_SEMI_INVULNERABLE_NO_COMMANDER))
&& !IsSemiInvulnerable(diagonalBattler, EXCLUDE_COMMANDER))
{
SaveBattlerAttacker(gBattlerAttacker);
SaveBattlerTarget(gBattlerTarget);
@ -4169,9 +4169,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
gBattlerAttacker = partner;
gBattleStruct->battlerState[battler].commandingDondozo = TRUE;
gBattleStruct->battlerState[partner].commanderSpecies = gBattleMons[battler].species;
gStatuses3[battler] |= STATUS3_COMMANDER;
if (gBattleMons[battler].volatiles.confusionTurns > 0
&& !(gStatuses4[battler] & STATUS4_INFINITE_CONFUSION))
gBattleMons[battler].volatiles.semiInvulnerable = STATE_COMMANDER;
if (gBattleMons[battler].volatiles.confusionTurns > 0 && !gBattleMons[battler].volatiles.infiniteConfusion)
gBattleMons[battler].volatiles.confusionTurns--;
BtlController_EmitSpriteInvisibility(battler, B_COMM_TO_CONTROLLER, TRUE);
MarkBattlerForControllerExec(battler);
@ -4212,7 +4211,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
case ABILITY_ICE_BODY:
if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW)
&& !IsBattlerAtMaxHp(battler)
&& !(gStatuses3[battler] & (STATUS3_UNDERGROUND | STATUS3_UNDERWATER))
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERGROUND
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_UNDERWATER
&& !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
{
BattleScriptPushCursorAndCallback(BattleScript_IceBodyHeal);
@ -4985,7 +4985,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
case ABILITY_GULP_MISSILE:
if ((gBattleMons[gBattlerAttacker].species == SPECIES_CRAMORANT)
&& ((gCurrentMove == MOVE_SURF && IsBattlerTurnDamaged(gBattlerTarget)) || gStatuses3[gBattlerAttacker] & STATUS3_UNDERWATER)
&& ((gCurrentMove == MOVE_SURF && IsBattlerTurnDamaged(gBattlerTarget)) || gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable == STATE_UNDERWATER)
&& TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_HP_PERCENT))
{
gBattleScripting.battler = gBattlerAttacker;
@ -5506,7 +5506,7 @@ bool32 CanBattlerEscape(u32 battler) // no ability check
return FALSE;
else if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)
return FALSE;
else if (gStatuses3[battler] & STATUS3_SKY_DROPPED)
else if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
return FALSE;
else
return TRUE;
@ -5531,7 +5531,7 @@ bool32 IsBattlerTerrainAffected(u32 battler, u32 terrainFlag)
{
if (!(gFieldStatuses & terrainFlag))
return FALSE;
else if (gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE)
if (IsSemiInvulnerable(battler, CHECK_ALL))
return FALSE;
return IsBattlerGrounded(battler);
@ -6066,7 +6066,7 @@ enum ItemEffect TryHandleSeed(u32 battler, u32 terrainFlag, u32 statId, u32 item
static enum ItemEffect ConsumeBerserkGene(u32 battler, enum ItemCaseId caseID)
{
if (CanBeInfinitelyConfused(battler))
gStatuses4[battler] |= STATUS4_INFINITE_CONFUSION;
gBattleMons[battler].volatiles.infiniteConfusion = TRUE;
BufferStatChange(battler, STAT_ATK, STRINGID_STATROSE);
gBattlerAttacker = gEffectBattler = battler;
@ -7300,8 +7300,8 @@ void ClearVariousBattlerFlags(u32 battler)
{
gDisableStructs[battler].furyCutterCounter = 0;
gBattleMons[battler].volatiles.destinyBond = FALSE;
gBattleMons[battler].volatiles.glaiveRush = FALSE;
gStatuses3[battler] &= ~STATUS3_GRUDGE;
gStatuses4[battler] &= ~ STATUS4_GLAIVE_RUSH;
}
void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands
@ -8286,7 +8286,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx)
break;
case EFFECT_MAGNITUDE:
case EFFECT_EARTHQUAKE:
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && !IsSemiInvulnerable(battlerDef, CHECK_ALL))
modifier = uq4_12_multiply(modifier, UQ_4_12(0.5));
break;
case EFFECT_KNOCK_OFF:
@ -9077,7 +9077,7 @@ static inline uq4_12_t GetCriticalModifier(bool32 isCrit)
static inline uq4_12_t GetGlaiveRushModifier(u32 battlerDef)
{
if (gStatuses4[battlerDef] & STATUS4_GLAIVE_RUSH)
if (gBattleMons[battlerDef].volatiles.glaiveRush)
return UQ_4_12(2.0);
return UQ_4_12(1.0);
}
@ -9102,21 +9102,21 @@ static inline uq4_12_t GetMinimizeModifier(u32 move, u32 battlerDef)
static inline uq4_12_t GetUndergroundModifier(u32 move, u32 battlerDef)
{
if (MoveDamagesUnderground(move) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND)
if (MoveDamagesUnderground(move) && gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_UNDERGROUND)
return UQ_4_12(2.0);
return UQ_4_12(1.0);
}
static inline uq4_12_t GetDiveModifier(u32 move, u32 battlerDef)
{
if (MoveDamagesUnderWater(move) && gStatuses3[battlerDef] & STATUS3_UNDERWATER)
if (MoveDamagesUnderWater(move) && gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_UNDERWATER)
return UQ_4_12(2.0);
return UQ_4_12(1.0);
}
static inline uq4_12_t GetAirborneModifier(u32 move, u32 battlerDef)
{
if (MoveDamagesAirborneDoubleDamage(move) && gStatuses3[battlerDef] & STATUS3_ON_AIR)
if (MoveDamagesAirborneDoubleDamage(move) && gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_ON_AIR)
return UQ_4_12(2.0);
return UQ_4_12(1.0);
}
@ -9934,7 +9934,7 @@ bool32 CanMegaEvolve(u32 battler)
return FALSE;
// Check if battler is currently held by Sky Drop.
if (gStatuses3[battler] & STATUS3_SKY_DROPPED)
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
return FALSE;
// Check if battler is holding a Z-Crystal.
@ -9972,7 +9972,7 @@ bool32 CanUltraBurst(u32 battler)
return FALSE;
// Check if mon is currently held by Sky Drop
if (gStatuses3[battler] & STATUS3_SKY_DROPPED)
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
return FALSE;
// Check if there is an entry in the form change table for Ultra Burst and battler is holding a Z-Crystal.
@ -10784,7 +10784,7 @@ bool32 BlocksPrankster(u16 move, u32 battlerPrankster, u32 battlerDef, bool32 ch
return FALSE;
if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK))
return FALSE;
if (gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)
if (IsSemiInvulnerable(battlerDef, CHECK_ALL))
return FALSE;
return TRUE;
@ -10915,7 +10915,7 @@ void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing)
void RemoveConfusionStatus(u32 battler)
{
gBattleMons[battler].volatiles.confusionTurns = 0;
gStatuses4[battler] &= ~STATUS4_INFINITE_CONFUSION;
gBattleMons[battler].volatiles.infiniteConfusion = FALSE;
}
static bool32 CanBeInfinitelyConfused(u32 battler)
@ -11226,7 +11226,7 @@ bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef)
u32 moveType = GetBattleMoveType(gCurrentMove);
return ((CalcTypeEffectivenessMultiplierHelper(gCurrentMove, moveType, battlerAtk, battlerDef, GetBattlerAbility(battlerAtk), GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0))
|| IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove)
|| IsSemiInvulnerable(battlerDef, gCurrentMove)
|| !BreaksThroughSemiInvulnerablity(battlerDef, gCurrentMove)
|| DoesBattlerHaveAbilityImmunity(battlerAtk, battlerDef, moveType));
}
@ -11614,13 +11614,13 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u
if ((gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
|| (B_TOXIC_NEVER_MISS >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|| gStatuses4[battlerDef] & STATUS4_GLAIVE_RUSH)
|| gBattleMons[battlerDef].volatiles.glaiveRush)
{
effect = TRUE;
}
// If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits.
else if (abilityAtk == ABILITY_NO_GUARD
&& !(gStatuses3[battlerDef] & STATUS3_COMMANDER)
&& gBattleMons[battlerDef].volatiles.semiInvulnerable != STATE_COMMANDER
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battlerDef] == SKY_DROP_NO_TARGET))
{
effect = TRUE;
@ -11635,7 +11635,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u
}
// If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits.
else if (gStatuses3[battlerDef] & STATUS3_TELEKINESIS
&& !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE)
&& !IsSemiInvulnerable(battlerDef, CHECK_ALL)
&& moveEffect != EFFECT_OHKO
&& moveEffect != EFFECT_SHEER_COLD)
{
@ -11645,15 +11645,11 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u
{
effect = TRUE;
}
else if (GetActiveGimmick(battlerAtk) == GIMMICK_Z_MOVE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
else if (GetActiveGimmick(battlerAtk) == GIMMICK_Z_MOVE && !IsSemiInvulnerable(battlerDef, CHECK_ALL))
{
effect = TRUE;
}
else if ((gStatuses3[battlerDef] & STATUS3_COMMANDER)
|| (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE)
|| ((gStatuses3[battlerDef] & STATUS3_ON_AIR) && !(MoveDamagesAirborne(move) || MoveDamagesAirborneDoubleDamage(move)))
|| ((gStatuses3[battlerDef] & STATUS3_UNDERGROUND) && !MoveDamagesUnderground(move))
|| ((gStatuses3[battlerDef] & STATUS3_UNDERWATER) && !MoveDamagesUnderWater(move)))
else if (!BreaksThroughSemiInvulnerablity(battlerDef, move))
{
if (option == RUN_SCRIPT)
{
@ -11813,3 +11809,32 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u
return calc;
}
bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander)
{
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_COMMANDER)
return excludeCommander != EXCLUDE_COMMANDER;
return gBattleMons[battler].volatiles.semiInvulnerable != STATE_NONE;
}
bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move)
{
switch (gBattleMons[battler].volatiles.semiInvulnerable)
{
case STATE_UNDERGROUND:
return MoveDamagesUnderground(move);
case STATE_UNDERWATER:
return MoveDamagesUnderWater(move);
case STATE_ON_AIR:
case STATE_SKY_DROP:
return MoveDamagesAirborne(move) || MoveDamagesAirborneDoubleDamage(move);
case STATE_PHANTOM_FORCE:
return FALSE;
case STATE_COMMANDER:
return FALSE;
case STATE_NONE:
return TRUE;
}
return FALSE;
}

View File

@ -604,7 +604,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.sleepTalkBanned = TRUE,
.instructBanned = TRUE,
.assistBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNFLEWHIGH, .status = COMPRESS_BITS(STATUS3_ON_AIR) },
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNFLEWHIGH, .status = STATE_ON_AIR },
.contestEffect = CONTEST_EFFECT_AVOID_STARTLE,
.contestCategory = CONTEST_CATEGORY_SMART,
.contestComboStarterId = 0,
@ -2461,7 +2461,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.instructBanned = TRUE,
.assistBanned = TRUE,
.skyBattleBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNDUGHOLE, .status = COMPRESS_BITS(STATUS3_UNDERGROUND) },
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNDUGHOLE, .status = STATE_UNDERGROUND },
.contestEffect = CONTEST_EFFECT_AVOID_STARTLE,
.contestCategory = CONTEST_CATEGORY_SMART,
.contestComboStarterId = 0,
@ -7715,7 +7715,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.instructBanned = TRUE,
.assistBanned = TRUE,
.skyBattleBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNHIDUNDERWATER, .status = COMPRESS_BITS(STATUS3_UNDERWATER) },
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNHIDUNDERWATER, .status = STATE_UNDERWATER },
.contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE,
.contestCategory = CONTEST_CATEGORY_BEAUTY,
.contestComboStarterId = COMBO_STARTER_DIVE,
@ -8974,7 +8974,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.sleepTalkBanned = TRUE,
.instructBanned = TRUE,
.assistBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNSPRANGUP, .status = COMPRESS_BITS(STATUS3_ON_AIR) },
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNSPRANGUP, .status = STATE_ON_AIR },
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_PARALYSIS,
.chance = 30,
@ -12100,7 +12100,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.sleepTalkBanned = TRUE,
.instructBanned = TRUE,
.assistBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_VANISHEDINSTANTLY, .status = COMPRESS_BITS(STATUS3_PHANTOM_FORCE) },
.argument.twoTurnAttack = { .stringId = STRINGID_VANISHEDINSTANTLY, .status = STATE_PHANTOM_FORCE },
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_FEINT,
}),
@ -13065,7 +13065,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.sleepTalkBanned = TRUE,
.instructBanned = TRUE,
.assistBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKTARGETHIGH, .status = COMPRESS_BITS(STATUS3_ON_AIR) },
.argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKTARGETHIGH, .status = STATE_ON_AIR },
.contestEffect = CONTEST_EFFECT_AVOID_STARTLE,
.contestCategory = CONTEST_CATEGORY_SMART,
.contestComboStarterId = 0,
@ -14505,7 +14505,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_ALL] =
.sleepTalkBanned = TRUE,
.instructBanned = TRUE,
.assistBanned = TRUE,
.argument.twoTurnAttack = { .stringId = STRINGID_VANISHEDINSTANTLY, .status = COMPRESS_BITS(STATUS3_PHANTOM_FORCE) },
.argument.twoTurnAttack = { .stringId = STRINGID_VANISHEDINSTANTLY, .status = STATE_PHANTOM_FORCE },
.additionalEffects = ADDITIONAL_EFFECTS({
.moveEffect = MOVE_EFFECT_FEINT,
}),

View File

@ -1110,7 +1110,7 @@ static u32 GetBallThrowableState(void)
return BALL_THROW_UNABLE_TWO_MONS;
else if (IsPlayerPartyAndPokemonStorageFull() == TRUE)
return BALL_THROW_UNABLE_NO_ROOM;
else if (B_SEMI_INVULNERABLE_CATCH >= GEN_4 && (gStatuses3[GetCatchingBattler()] & STATUS3_SEMI_INVULNERABLE))
else if (B_SEMI_INVULNERABLE_CATCH >= GEN_4 && IsSemiInvulnerable(GetCatchingBattler(), CHECK_ALL))
return BALL_THROW_UNABLE_SEMI_INVULNERABLE;
else if (FlagGet(B_FLAG_NO_CATCHING))
return BALL_THROW_UNABLE_DISABLED_FLAG;

View File

@ -213,7 +213,7 @@ SINGLE_BATTLE_TEST("Berserk Gene causes infinite confusion") // check if bit is
TURN {}
} SCENE {
} THEN {
EXPECT(gStatuses4[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] & STATUS4_INFINITE_CONFUSION);
EXPECT(gBattleMons[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)].volatiles.infiniteConfusion);
}
}

View File

@ -4,17 +4,17 @@
ASSUMPTIONS
{
ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_FLY) == STATUS3_ON_AIR);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_FLY) == STATE_ON_AIR);
ASSUME(GetMoveEffect(MOVE_DIG) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_DIG) == STATUS3_UNDERGROUND);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_DIG) == STATE_UNDERGROUND);
ASSUME(GetMoveEffect(MOVE_BOUNCE) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_BOUNCE) == STATUS3_ON_AIR);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_BOUNCE) == STATE_ON_AIR);
ASSUME(GetMoveEffect(MOVE_DIVE) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_DIVE) == STATUS3_UNDERWATER);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_DIVE) == STATE_UNDERWATER);
ASSUME(GetMoveEffect(MOVE_PHANTOM_FORCE) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_PHANTOM_FORCE) == STATUS3_PHANTOM_FORCE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_PHANTOM_FORCE) == STATE_PHANTOM_FORCE);
ASSUME(GetMoveEffect(MOVE_SHADOW_FORCE) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_SHADOW_FORCE) == STATUS3_PHANTOM_FORCE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_SHADOW_FORCE) == STATE_PHANTOM_FORCE);
}
SINGLE_BATTLE_TEST("Semi-invulnerable moves make the user semi-invulnerable turn 1, then strike turn 2")

View File

@ -41,9 +41,9 @@ SINGLE_BATTLE_TEST("Hurricane can hit airborne targets (Fly, Bounce)")
PARAMETRIZE { move = MOVE_BOUNCE; }
GIVEN {
ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_FLY) == STATUS3_ON_AIR);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_FLY) == STATE_ON_AIR);
ASSUME(GetMoveEffect(MOVE_BOUNCE) == EFFECT_SEMI_INVULNERABLE);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_BOUNCE) == STATUS3_ON_AIR);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_BOUNCE) == STATE_ON_AIR);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Moves(move); }
} WHEN {
@ -59,7 +59,7 @@ DOUBLE_BATTLE_TEST("Hurricane can hit airborne targets (Sky Drop)")
{
GIVEN {
ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_SKY_DROP) == STATUS3_ON_AIR);
ASSUME(GetMoveTwoTurnAttackStatus(MOVE_SKY_DROP) == STATE_ON_AIR);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);