diff --git a/include/battle_util.h b/include/battle_util.h index 819b4a5b65..aed03afae1 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -173,8 +173,9 @@ struct BattleContext u32 battlerAtk:3; u32 battlerDef:3; u32 currentMove:16; - enum BattleMoveEffects moveEffect:10; - enum Ability ability[MAX_BATTLERS_COUNT]; + u32 padding:10; + enum Ability abilities[MAX_BATTLERS_COUNT]; + enum HoldEffect holdEffects[MAX_BATTLERS_COUNT]; }; enum SleepClauseBlock diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2f05de63d0..f99fafcf3f 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1065,7 +1065,7 @@ bool32 IsMovePowderBlocked(struct BattleContext *ctx) if (IsPowderMove(ctx->currentMove) && (ctx->battlerAtk != ctx->battlerDef)) { if (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 - && (IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GRASS) || ctx->ability[ctx->battlerDef] == ABILITY_OVERCOAT)) + && (IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GRASS) || ctx->abilities[ctx->battlerDef] == ABILITY_OVERCOAT)) { gBattlerAbility = ctx->battlerDef; RecordAbilityBattle(ctx->battlerDef, ABILITY_OVERCOAT); @@ -1125,11 +1125,12 @@ static void Cmd_attackcanceler(void) ctx.battlerAtk = gBattlerAttacker; ctx.battlerDef = gBattlerTarget; ctx.currentMove = gCurrentMove; - ctx.moveEffect = GetMoveEffect(ctx.currentMove); + + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx.currentMove); if (!IsBattlerAlive(gBattlerAttacker) - && ctx.moveEffect != EFFECT_EXPLOSION - && ctx.moveEffect != EFFECT_MISTY_EXPLOSION) + && moveEffect != EFFECT_EXPLOSION + && moveEffect != EFFECT_MISTY_EXPLOSION) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; @@ -1137,14 +1138,14 @@ static void Cmd_attackcanceler(void) } // With how attackcanceller works right now we only need attacker and target abilities. Might change in the future - ctx.ability[ctx.battlerAtk] = GetBattlerAbility(ctx.battlerAtk); - ctx.ability[ctx.battlerDef] = GetBattlerAbility(ctx.battlerDef); + ctx.abilities[ctx.battlerAtk] = GetBattlerAbility(ctx.battlerAtk); + ctx.abilities[ctx.battlerDef] = GetBattlerAbility(ctx.battlerDef); if (AtkCanceller_MoveSuccessOrder(&ctx) != MOVE_STEP_SUCCESS) return; if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF - && ctx.ability[ctx.battlerAtk] == ABILITY_PARENTAL_BOND + && ctx.abilities[ctx.battlerAtk] == ABILITY_PARENTAL_BOND && IsMoveAffectedByParentalBond(gCurrentMove, gBattlerAttacker) && !(gAbsentBattlerFlags & (1u << gBattlerTarget)) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE) @@ -1158,8 +1159,8 @@ static void Cmd_attackcanceler(void) if (CanAbilityBlockMove( ctx.battlerAtk, ctx.battlerDef, - ctx.ability[ctx.battlerAtk], - ctx.ability[ctx.battlerDef], + ctx.abilities[ctx.battlerAtk], + ctx.abilities[ctx.battlerDef], ctx.currentMove, RUN_SCRIPT)) return; @@ -1169,7 +1170,7 @@ static void Cmd_attackcanceler(void) if (CanAbilityAbsorbMove( ctx.battlerAtk, ctx.battlerDef, - ctx.ability[ctx.battlerDef], + ctx.abilities[ctx.battlerDef], ctx.currentMove, GetBattleMoveType(ctx.currentMove), RUN_SCRIPT)) @@ -1181,17 +1182,17 @@ 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[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) + && (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns))) || (IsMoveNotAllowedInSkyBattles(gCurrentMove))) { gBattleStruct->noTargetPresent = TRUE; - if (ctx.moveEffect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. + if (moveEffect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem; else gBattlescriptCurrInstr = BattleScript_ButItFailed; - if (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) + if (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); return; } @@ -1222,7 +1223,7 @@ static void Cmd_attackcanceler(void) { u32 battler = gBattlerTarget; - if (ctx.ability[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE) + if (ctx.abilities[ctx.battlerDef] == ABILITY_MAGIC_BOUNCE) { battler = gBattlerTarget; gBattleStruct->bouncedMoveIsUsed = TRUE; @@ -1273,11 +1274,11 @@ static void Cmd_attackcanceler(void) BattleScriptCall(BattleScript_TookAttack); } else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) - && (ctx.moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) - && (!gBattleMoveEffects[ctx.moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) - && ctx.moveEffect != EFFECT_SUCKER_PUNCH - && ctx.moveEffect != EFFECT_COUNTER - && ctx.moveEffect != EFFECT_UPPER_HAND) + && (moveEffect != EFFECT_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) + && (!gBattleMoveEffects[moveEffect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) + && moveEffect != EFFECT_SUCKER_PUNCH + && moveEffect != EFFECT_COUNTER + && moveEffect != EFFECT_UPPER_HAND) { if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker), gCurrentMove)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; diff --git a/src/battle_util.c b/src/battle_util.c index b95fdd3a28..3c83a80cab 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2010,7 +2010,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(struct BattleContext *ctx) else { u8 toSub; - if (IsAbilityAndRecord(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ABILITY_EARLY_BIRD)) + if (IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_EARLY_BIRD)) toSub = 2; else toSub = 1; @@ -2018,9 +2018,11 @@ static enum MoveCanceller CancellerAsleepOrFrozen(struct BattleContext *ctx) gBattleMons[ctx->battlerAtk].status1 &= ~STATUS1_SLEEP; else gBattleMons[ctx->battlerAtk].status1 -= toSub; + + enum BattleMoveEffects moveEffect = GetMoveEffect(ctx->currentMove); if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) { - if (ctx->moveEffect != EFFECT_SNORE && ctx->moveEffect != EFFECT_SLEEP_TALK) + if (moveEffect != EFFECT_SNORE && moveEffect != EFFECT_SLEEP_TALK) { gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; @@ -2273,7 +2275,7 @@ static enum MoveCanceller CancellerConfused(struct BattleContext *ctx) static enum MoveCanceller CancellerParalysed(struct BattleContext *ctx) { if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_PARALYSIS - && !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) + && !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) && !RandomPercentage(RNG_PARALYSIS, 75)) { gProtectStructs[ctx->battlerAtk].nonVolatileStatusImmobility = TRUE; @@ -2366,7 +2368,7 @@ static enum MoveCanceller CancellerChoiceLock(struct BattleContext *ctx) if (gChosenMove != MOVE_STRUGGLE && (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE) - && (IsHoldEffectChoice(holdEffect) || ctx->ability[ctx->battlerAtk] == ABILITY_GORILLA_TACTICS)) + && (IsHoldEffectChoice(holdEffect) || ctx->abilities[ctx->battlerAtk] == ABILITY_GORILLA_TACTICS)) *choicedMoveAtk = gChosenMove; u32 moveIndex; @@ -2389,7 +2391,7 @@ static enum MoveCanceller CancellerCallSubmove(struct BattleContext *ctx) const u8 *battleScript = NULL; battleScript = BattleScript_SubmoveAttackstring; - switch(ctx->moveEffect) + switch(GetMoveEffect(ctx->currentMove)) { case EFFECT_MIRROR_MOVE: calledMove = GetMirrorMoveMove(); @@ -2430,7 +2432,7 @@ static enum MoveCanceller CancellerCallSubmove(struct BattleContext *ctx) { if (GetActiveGimmick(ctx->battlerAtk) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(calledMove)) calledMove = GetTypeBasedZMove(calledMove); - if (ctx->moveEffect == EFFECT_COPYCAT && IsMaxMove(calledMove)) + if (GetMoveEffect(ctx->currentMove) == EFFECT_COPYCAT && IsMaxMove(calledMove)) calledMove = gBattleStruct->dynamax.lastUsedBaseMove; gBattleStruct->submoveAnnouncement = SUBMOVE_SUCCESS; @@ -2509,7 +2511,7 @@ static enum MoveCanceller CancellerPPDeduction(struct BattleContext *ctx) } else if (moveTarget != MOVE_TARGET_OPPONENTS_FIELD) { - if (ctx->battlerAtk != ctx->battlerDef && ctx->ability[ctx->battlerDef] == ABILITY_PRESSURE) + if (ctx->battlerAtk != ctx->battlerDef && ctx->abilities[ctx->battlerDef] == ABILITY_PRESSURE) ppToDeduct++; } @@ -2597,7 +2599,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) { const u8 *battleScript = NULL; - switch (ctx->moveEffect) + switch (GetMoveEffect(ctx->currentMove)) { case EFFECT_FAIL_IF_NOT_ARG_TYPE: if (!IS_BATTLER_OF_TYPE(ctx->battlerAtk, GetMoveArgType(ctx->currentMove))) @@ -2656,7 +2658,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) case EFFECT_POLTERGEIST: if (gBattleMons[ctx->battlerDef].item == ITEM_NONE || gFieldStatuses & STATUS_FIELD_MAGIC_ROOM - || ctx->ability[ctx->battlerDef] == ABILITY_KLUTZ) + || ctx->abilities[ctx->battlerDef] == ABILITY_KLUTZ) battleScript = BattleScript_ButItFailed; break; case EFFECT_PROTECT: @@ -2664,13 +2666,13 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) break; case EFFECT_REST: if (gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP - || ctx->ability[ctx->battlerAtk] == ABILITY_COMATOSE) + || ctx->abilities[ctx->battlerAtk] == ABILITY_COMATOSE) battleScript = BattleScript_RestIsAlreadyAsleep; else if (gBattleMons[ctx->battlerAtk].hp == gBattleMons[ctx->battlerAtk].maxHP) battleScript = BattleScript_AlreadyAtFullHp; - else if (ctx->ability[ctx->battlerAtk] == ABILITY_INSOMNIA - || ctx->ability[ctx->battlerAtk] == ABILITY_VITAL_SPIRIT - || ctx->ability[ctx->battlerAtk] == ABILITY_PURIFYING_SALT) + else if (ctx->abilities[ctx->battlerAtk] == ABILITY_INSOMNIA + || ctx->abilities[ctx->battlerAtk] == ABILITY_VITAL_SPIRIT + || ctx->abilities[ctx->battlerAtk] == ABILITY_PURIFYING_SALT) battleScript = BattleScript_InsomniaProtects; break; case EFFECT_SUCKER_PUNCH: @@ -2680,7 +2682,7 @@ static enum MoveCanceller CancellerMoveFailure(struct BattleContext *ctx) break; case EFFECT_SNORE: if (!(gBattleMons[ctx->battlerAtk].status1 & STATUS1_SLEEP) - && ctx->ability[ctx->battlerAtk] != ABILITY_COMATOSE) + && ctx->abilities[ctx->battlerAtk] != ABILITY_COMATOSE) battleScript = BattleScript_ButItFailed; break; case EFFECT_STEEL_ROLLER: @@ -2726,7 +2728,7 @@ static enum MoveCanceller CancellerPowderStatus(struct BattleContext *ctx) { if (TryActivatePowderStatus(ctx->currentMove)) { - if (!IsAbilityAndRecord(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) + if (!IsAbilityAndRecord(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ABILITY_MAGIC_GUARD)) gBattleStruct->moveDamage[ctx->battlerAtk] = GetNonDynamaxMaxHP(ctx->battlerAtk) / 4; // This might be incorrect @@ -2754,16 +2756,16 @@ bool32 IsDazzlingAbility(enum Ability ability) static enum MoveCanceller CancellerPriorityBlock(struct BattleContext *ctx) { bool32 effect = FALSE; - s32 priority = GetChosenMovePriority(ctx->battlerAtk, ctx->ability[ctx->battlerAtk]); + s32 priority = GetChosenMovePriority(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk]); u32 blockAbility = ABILITY_NONE; // ability of battler who is blocking u32 blockedByBattler = ctx->battlerDef; if (priority <= 0 || IsBattlerAlly(ctx->battlerAtk, ctx->battlerDef)) return MOVE_STEP_SUCCESS; - if (IsDazzlingAbility(ctx->ability[ctx->battlerDef])) + if (IsDazzlingAbility(ctx->abilities[ctx->battlerDef])) { - blockAbility = ctx->ability[ctx->battlerDef]; + blockAbility = ctx->abilities[ctx->battlerDef]; effect = TRUE; } else if (IsDoubleBattle() && IsBattlerAlive(BATTLE_PARTNER(ctx->battlerDef))) @@ -2793,7 +2795,7 @@ static enum MoveCanceller CancellerPriorityBlock(struct BattleContext *ctx) static enum MoveCanceller CancellerProtean(struct BattleContext *ctx) { u32 moveType = GetBattleMoveType(ctx->currentMove); - if (ProteanTryChangeType(ctx->battlerAtk, ctx->ability[ctx->battlerAtk], ctx->currentMove, moveType)) + if (ProteanTryChangeType(ctx->battlerAtk, ctx->abilities[ctx->battlerAtk], ctx->currentMove, moveType)) { if (GetGenConfig(GEN_PROTEAN_LIBERO) >= GEN_9) gDisableStructs[ctx->battlerAtk].usedProteanLibero = TRUE; @@ -2824,7 +2826,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) { if (GetMoveEffect(ctx->currentMove) == EFFECT_MULTI_HIT) { - enum Ability ability = ctx->ability[ctx->battlerAtk]; + enum Ability ability = ctx->abilities[ctx->battlerAtk]; if (ability == ABILITY_SKILL_LINK) { @@ -2845,7 +2847,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) } else if (GetMoveStrikeCount(ctx->currentMove) > 1) { - if (ctx->moveEffect == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(ctx->battlerAtk) == HOLD_EFFECT_LOADED_DICE) + if (GetMoveEffect(ctx->currentMove) == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(ctx->battlerAtk) == HOLD_EFFECT_LOADED_DICE) { gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10); } @@ -2853,7 +2855,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) { gMultiHitCounter = GetMoveStrikeCount(ctx->currentMove); - if (ctx->moveEffect == EFFECT_DRAGON_DARTS + if (GetMoveEffect(ctx->currentMove) == EFFECT_DRAGON_DARTS && !IsAffectedByFollowMe(ctx->battlerAtk, GetBattlerSide(ctx->battlerDef), ctx->currentMove) && CanTargetPartner(ctx->battlerAtk, ctx->battlerDef) && TargetFullyImmuneToCurrMove(ctx->battlerAtk, ctx->battlerDef)) @@ -2862,7 +2864,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0) } - else if (B_BEAT_UP >= GEN_5 && ctx->moveEffect == EFFECT_BEAT_UP) + else if (B_BEAT_UP >= GEN_5 && GetMoveEffect(ctx->currentMove) == EFFECT_BEAT_UP) { struct Pokemon* party = GetBattlerParty(ctx->battlerAtk); int i; @@ -2895,7 +2897,7 @@ static enum MoveCanceller CancellerMultihitMoves(struct BattleContext *ctx) static enum MoveCanceller CancellerMultiTargetMoves(struct BattleContext *ctx) { u32 moveTarget = GetBattlerMoveTargetType(ctx->battlerAtk, ctx->currentMove); - enum Ability abilityAtk = ctx->ability[ctx->battlerAtk]; + enum Ability abilityAtk = ctx->abilities[ctx->battlerAtk]; if (IsSpreadMove(moveTarget)) { @@ -2908,7 +2910,7 @@ static enum MoveCanceller CancellerMultiTargetMoves(struct BattleContext *ctx) if (ctx->battlerAtk == battlerDef || !IsBattlerAlive(battlerDef) - || (ctx->moveEffect == EFFECT_SYNCHRONOISE && !DoBattlersShareType(ctx->battlerAtk, battlerDef)) + || (GetMoveEffect(ctx->currentMove) == EFFECT_SYNCHRONOISE && !DoBattlersShareType(ctx->battlerAtk, battlerDef)) || (moveTarget == MOVE_TARGET_BOTH && ctx->battlerAtk == BATTLE_PARTNER(battlerDef)) || IsBattlerProtected(ctx->battlerAtk, battlerDef, ctx->currentMove)) // Missing Invulnerable check {