From db2ab0a43780323757024daa225bf96686f7e1cd Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 10 Nov 2023 10:51:33 -0800 Subject: [PATCH 1/3] Document TriggerHeldItemOnPivotMove --- include/overlay016/ov16_0225177C.h | 16 +++++- src/overlay016/ov16_0225177C.c | 83 +++++++++++++++++------------- 2 files changed, 62 insertions(+), 37 deletions(-) diff --git a/include/overlay016/ov16_0225177C.h b/include/overlay016/ov16_0225177C.h index 5a60dde8a4..336d3d60b5 100644 --- a/include/overlay016/ov16_0225177C.h +++ b/include/overlay016/ov16_0225177C.h @@ -1134,7 +1134,21 @@ void BattleSystem_SortMonsInTrickRoom(BattleSystem * param0, BattleContext * par * @return TRUE if the status effect should be shown, FALSE otherwise. */ BOOL BattleSystem_ShouldShowStatusEffect(BattleContext *battleCtx, int battler, int status); -BOOL BattleSystem_TriggerHeldItemOnPivotMove(BattleSystem * param0, BattleContext * param1, int * param2); + +/** + * @brief Trigger a held item's effect after a pivoting move has been used. + * + * This is meant to support triggering effects such as Shell Bell, Life Orb, + * and Sticky Barb transferral before the user of a pivoting move switches out. + * + * @param battleSys + * @param battleCtx + * @param[out] subscript Return param for the subscript to load for a + * triggered effect. + * @return TRUE if a subscript should be loaded for a triggered effect, + * FALSE otherwise. + */ +BOOL BattleSystem_TriggerHeldItemOnPivotMove(BattleSystem *battleSys, BattleContext *battleCtx, int *subscript); void BattleSystem_DecPPForPressure(BattleContext * param0, int param1, int param2); BOOL BattleSystem_RecordingStopped(BattleSystem * param0, BattleContext * param1); diff --git a/src/overlay016/ov16_0225177C.c b/src/overlay016/ov16_0225177C.c index d962cd495d..e6aa786c21 100644 --- a/src/overlay016/ov16_0225177C.c +++ b/src/overlay016/ov16_0225177C.c @@ -4164,7 +4164,7 @@ int BattleSystem_TriggerEffectOnSwitch(BattleSystem *battleSys, BattleContext *b for (i = 0; i < maxBattlers; i++) { battler = battleCtx->monSpeedOrder[i]; - if (BattleSystem_TriggerHeldItemOnStatus(battleSys, battleCtx, battler, &subscript) == TRUE) { // document + if (BattleSystem_TriggerHeldItemOnStatus(battleSys, battleCtx, battler, &subscript) == TRUE) { battleCtx->msgBattlerTemp = battler; result = SWITCH_IN_CHECK_RESULT_BREAK; break; @@ -4779,7 +4779,9 @@ BOOL BattleSystem_TriggerHeldItem(BattleSystem *battleSys, BattleContext *battle result = TRUE; } - break;case HOLD_EFFECT_PINCH_ATK_UP: + break; + + case HOLD_EFFECT_PINCH_ATK_UP: if (Battler_Ability(battleCtx, battler) == ABILITY_GLUTTONY) { itemPower /= 2; } @@ -7342,49 +7344,58 @@ BOOL BattleSystem_ShouldShowStatusEffect(BattleContext *battleCtx, int battler, return result; } -BOOL BattleSystem_TriggerHeldItemOnPivotMove (BattleSystem * param0, BattleContext * param1, int * param2) +BOOL BattleSystem_TriggerHeldItemOnPivotMove(BattleSystem *battleSys, BattleContext *battleCtx, int *subscript) { - BOOL v0; - int v1; - int v2; - int v3; - int v4; - int v5; - int v6; - - v0 = 0; - v2 = Battler_HeldItemEffect(param1, param1->attacker); - v3 = Battler_HeldItemPower(param1, param1->attacker, 0); - v4 = Battler_HeldItemEffect(param1, param1->defender); - v5 = Battler_HeldItemPower(param1, param1->defender, 0); - v6 = Battler_Side(param0, param1->attacker); - - if ((v2 == 88) && (param1->battleStatusMask & 0x2000) && (param1->selfTurnFlags[param1->attacker].shellBellDamageDealt) && (param1->attacker != param1->defender) && (param1->battleMons[param1->attacker].curHP < param1->battleMons[param1->attacker].maxHP) && (param1->battleMons[param1->attacker].curHP)) { - param1->hpCalcTemp = BattleSystem_Divide(param1->selfTurnFlags[param1->attacker].shellBellDamageDealt * -1, v3); - param1->msgBattlerTemp = param1->attacker; - param2[0] = (0 + 213); - v0 = 1; + BOOL result = FALSE; + int attackerItemEffect = Battler_HeldItemEffect(battleCtx, battleCtx->attacker); + int attackerItemPower = Battler_HeldItemPower(battleCtx, battleCtx->attacker, ITEM_POWER_CHECK_ALL); + int defenderItemEffect = Battler_HeldItemEffect(battleCtx, battleCtx->defender); + int defenderItemPower = Battler_HeldItemPower(battleCtx, battleCtx->defender, ITEM_POWER_CHECK_ALL); + int attackingSide = Battler_Side(battleSys, battleCtx->attacker); + + if (attackerItemEffect == HOLD_EFFECT_HP_RESTORE_ON_DMG + && (battleCtx->battleStatusMask & SYSCTL_MOVE_HIT) + && ATTACKER_SELF_TURN_FLAGS.shellBellDamageDealt + && battleCtx->attacker != battleCtx->defender + && ATTACKING_MON.curHP < ATTACKING_MON.maxHP + && ATTACKING_MON.curHP) { + battleCtx->hpCalcTemp = BattleSystem_Divide(ATTACKER_SELF_TURN_FLAGS.shellBellDamageDealt * -1, attackerItemPower); + battleCtx->msgBattlerTemp = battleCtx->attacker; + *subscript = BATTLE_SUBSEQ_RESTORE_A_LITTLE_HP; + result = TRUE; } - if ((v2 == 98) && (Battler_Ability(param1, param1->attacker) != 98) && (param1->battleStatusMask & 0x2000) && (param1->aiContext.moveTable[param1->moveCur].class != 2) && (param1->battleMons[param1->attacker].curHP)) { - param1->hpCalcTemp = BattleSystem_Divide(param1->battleMons[param1->attacker].maxHP * -1, 10); - param1->msgBattlerTemp = param1->attacker; - param2[0] = (0 + 214); - v0 = 1; + if (attackerItemEffect == HOLD_EFFECT_HP_DRAIN_ON_ATK + && Battler_Ability(battleCtx, battleCtx->attacker) != ABILITY_MAGIC_GUARD + && (battleCtx->battleStatusMask & SYSCTL_MOVE_HIT) + && CURRENT_MOVE_DATA.class != CLASS_STATUS + && ATTACKING_MON.curHP) { + battleCtx->hpCalcTemp = BattleSystem_Divide(ATTACKING_MON.maxHP * -1, 10); + battleCtx->msgBattlerTemp = battleCtx->attacker; + *subscript = BATTLE_SUBSEQ_LOSE_HP_FROM_ITEM; + result = TRUE; } - if ((v4 == 46) && (param1->battleMons[param1->attacker].curHP) && (Battler_Ability(param1, param1->attacker) != 98) && (param1->selfTurnFlags[param1->defender].physicalDamageTaken)) { - param1->hpCalcTemp = BattleSystem_Divide(param1->battleMons[param1->attacker].maxHP * -1, v5); - param2[0] = (0 + 266); - v0 = 1; + if (defenderItemEffect == HOLD_EFFECT_RECOIL_PHYSICAL + && battleCtx->battleMons[battleCtx->attacker].curHP + && Battler_Ability(battleCtx, battleCtx->attacker) != ABILITY_MAGIC_GUARD + && DEFENDER_SELF_TURN_FLAGS.physicalDamageTaken) { + battleCtx->hpCalcTemp = BattleSystem_Divide(ATTACKING_MON.maxHP * -1, defenderItemPower); + *subscript = BATTLE_SUBSEQ_HELD_ITEM_RECOIL_WHEN_HIT; + result = TRUE; } - if ((v4 == 116) && (param1->battleMons[param1->attacker].curHP) && (param1->battleMons[param1->attacker].heldItem == 0) && ((param1->sideConditions[v6].knockedOffItemsMask & FlagIndex(param1->selectedPartySlot[param1->attacker])) == 0) && ((param1->selfTurnFlags[param1->defender].physicalDamageTaken) || (param1->selfTurnFlags[param1->defender].specialDamageTaken)) && (param1->aiContext.moveTable[param1->moveCur].flags & 0x1)) { - param2[0] = (0 + 216); - v0 = 1; + if (defenderItemEffect == HOLD_EFFECT_DMG_USER_CONTACT_XFR + && ATTACKING_MON.curHP + && ATTACKING_MON.heldItem == ITEM_NONE + && (battleCtx->sideConditions[attackingSide].knockedOffItemsMask & FlagIndex(battleCtx->selectedPartySlot[battleCtx->attacker])) == FALSE + && (DEFENDER_SELF_TURN_FLAGS.physicalDamageTaken || DEFENDER_SELF_TURN_FLAGS.specialDamageTaken) + && (CURRENT_MOVE_DATA.flags & MOVE_FLAG_MAKES_CONTACT)) { + *subscript = BATTLE_SUBSEQ_TRANSFER_STICKY_BARB; + result = TRUE; } - return v0; + return result; } void BattleSystem_DecPPForPressure (BattleContext * param0, int param1, int param2) From 66369bb811e9e7ec4911aac91aa7c883f954dc0b Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 10 Nov 2023 22:05:42 -0800 Subject: [PATCH 2/3] Document BattleSystem_CanUseMove and associated sub-functions --- include/constants/battle.h | 21 +-- include/overlay016/ov16_0225177C.h | 90 +++++++++- src/overlay014/ov14_0221FC20.c | 2 +- src/overlay016/battle_controller.c | 12 +- src/overlay016/battle_script.c | 2 +- src/overlay016/ov16_0225177C.c | 277 +++++++++++++++-------------- src/overlay016/ov16_0226485C.c | 2 +- 7 files changed, 244 insertions(+), 162 deletions(-) diff --git a/include/constants/battle.h b/include/constants/battle.h index a476683f40..8490dbea93 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -106,16 +106,17 @@ #define BATTLE_STATUS_GIRATINA (1 << 6) #define BATTLE_STATUS_DISTORTION (1 << 7) -#define STRUGGLE_CHECK_NO_MOVES (1 << 0) -#define STRUGGLE_CHECK_NO_PP (1 << 1) -#define STRUGGLE_CHECK_DISABLED (1 << 2) -#define STRUGGLE_CHECK_TORMENTED (1 << 3) -#define STRUGGLE_CHECK_TAUNTED (1 << 4) -#define STRUGGLE_CHECK_IMPRISONED (1 << 5) -#define STRUGGLE_CHECK_GRAVITY (1 << 6) -#define STRUGGLE_CHECK_HEAL_BLOCKED (1 << 7) -#define STRUGGLE_CHECK_CHOICED (1 << 9) -#define STRUGGLE_CHECK_ALL ~0 +#define CHECK_INVALID_NO_MOVE (1 << 0) +#define CHECK_INVALID_NO_PP (1 << 1) +#define CHECK_INVALID_DISABLED (1 << 2) +#define CHECK_INVALID_TORMENTED (1 << 3) +#define CHECK_INVALID_TAUNTED (1 << 4) +#define CHECK_INVALID_IMPRISONED (1 << 5) +#define CHECK_INVALID_GRAVITY (1 << 6) +#define CHECK_INVALID_HEAL_BLOCK (1 << 7) +#define CHECK_INVALID_ENCORE (1 << 8) // this one is only implicit +#define CHECK_INVALID_CHOICE_ITEM (1 << 9) +#define CHECK_INVALID_ALL ~0 #define STRUGGLING_MOVE_1 (1 << 0) #define STRUGGLING_MOVE_2 (1 << 1) diff --git a/include/overlay016/ov16_0225177C.h b/include/overlay016/ov16_0225177C.h index 336d3d60b5..b60946f385 100644 --- a/include/overlay016/ov16_0225177C.h +++ b/include/overlay016/ov16_0225177C.h @@ -449,9 +449,54 @@ void BattleSystem_UpdateAfterSwitch(BattleSystem *battleSys, BattleContext *batt */ void BattleSystem_CleanupFaintedMon(BattleSystem *battleSys, BattleContext *battleCtx, int battler); void BattleSystem_SetupNextTurn(BattleSystem * param0, BattleContext * param1); -int BattleSystem_CheckStruggling(BattleSystem * param0, BattleContext * param1, int param2, int param3, int param4); + +/** + * @brief Compute which moves are invalid for the battler to use, performing + * checks according to the input opcode mask. + * + * The following op-codes are supported in the input mask: + * - CHECK_INVALID_NO_MOVE -> flag empty move-slots + * - CHECK_INVALID_NO_PP -> flag moves with no remaining PP + * - CHECK_INVALID_DISABLED -> flag the battler's Disabled move + * - CHECK_INVALID_TORMENTED -> flag the battler's last-used move + * - CHECK_INVALID_TAUNTED -> flag any of the battler's moves with 0 power + * - CHECK_INVALID_IMPRISONED -> flag any of the battler's Imprisoned moves + * - CHECK_INVALID_GRAVITY -> flag any of the battler's moves which fail in high gravity + * - CHECK_INVALID_HEAL_BLOCK -> flag any of the battler's healing moves + * - CHECK_INVALID_CHOICE_ITEM -> flag any of the battler's moves other than their choice-locked move + * + * @param battleSys + * @param battleCtx + * @param battler The battler choosing their move + * @param invalidMoves An initial mask of moves which should be deemed invalid + * @param opMask An input opcode mask determining which checks should be + * made for move validity + * @return A bitmask denoting which of the battler's move slots are invalid for + * selection + */ +int BattleSystem_CheckInvalidMoves(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int invalidMoves, int opMask); + +/** + * @brief Determine if a battler can use the move in the given slot, populating + * the input BattleMessage struct with a message to display if they cannot. + * + * @param battleSys + * @param battleCtx + * @param battler + * @param moveSlot The slot of the move that the battler is trying to use + * @param[out] msgOut An output message for display to the player + * @return TRUE if the move can be used, FALSE if it cannot + */ BOOL BattleSystem_CanUseMove(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int moveSlot, BattleMessage *msgOut); -int Battler_SlotForMove(BattleMon * param0, u16 param1); + +/** + * @brief Determine which slot of the Pokemon's moveset contains a given move. + * + * @param mon + * @param move + * @return The slot of the Pokemon's moveset containing the input move + */ +int Battler_SlotForMove(BattleMon *mon, u16 move); /** * @brief Apply type-chart effectiveness for a given move against its target. @@ -634,7 +679,19 @@ BOOL BattleSystem_AnyReplacementMons(BattleSystem *battleSys, BattleContext *bat BOOL BattleSystem_Trapped(BattleSystem * param0, BattleContext * param1, int param2, BattleMessage * param3); BOOL BattleSystem_TryEscape(BattleSystem * param0, BattleContext * param1, int param2); BOOL Battler_CheckTruant(BattleContext * param0, int param1); -BOOL BattleSystem_Imprisoned(BattleSystem * param0, BattleContext * param1, int param2, int param3); + +/** + * @brief Checks if a given move has been Imprisoned by one of the battler's + * opponents. + * + * @param battleSys + * @param battleCtx + * @param battler The battler trying to execute a move. + * @param move The move to be executed. + * @return TRUE if any of the battler's opponents has used Imprison and also + * knows the requested move; FALSE otherwise. + */ +BOOL Move_Imprisoned(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move); /** * @brief Check if any active battlers are flagged as having the given move @@ -649,8 +706,31 @@ BOOL BattleSystem_Imprisoned(BattleSystem * param0, BattleContext * param1, int BOOL BattleSystem_AnyBattlersWithMoveEffect(BattleSystem *battleSys, BattleContext *battleCtx, int effectMask); void BattleSystem_SetupLoop(BattleSystem *battleSys, BattleContext *battleCtx); void BattleSystem_SortMonsBySpeed(BattleSystem * param0, BattleContext * param1); -BOOL BattleSystem_FailsInHighGravity(BattleSystem * param0, BattleContext * param1, int param2, int param3); -BOOL BattleSystem_HealBlocked(BattleSystem * param0, BattleContext * param1, int param2, int param3); + +/** + * @brief Check if a given move should fail due to high gravity conditions. + * + * @param battleSys + * @param battleCtx + * @param battler + * @param move The move to be executed + * @return TRUE if the field is under high gravity conditions AND the move + * should fail in such conditions; FALSE otherwise + */ +BOOL Move_FailsInHighGravity(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move); + +/** + * @brief Check if a given move should fail due to the battler being afflicted + * by Heal Block. + * + * @param battleSys + * @param battleCtx + * @param battler The battler trying to execute a move + * @param move The move to be executed + * @return TRUE if the battler is afflicted with Heal Block AND the move should + * fail due to such afflicition; FALSE otherwise + */ +BOOL Move_HealBlocked(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move); void BattleSystem_UpdateLastResort(BattleSystem * param0, BattleContext * param1); /** diff --git a/src/overlay014/ov14_0221FC20.c b/src/overlay014/ov14_0221FC20.c index f2b341da03..908a0c3a28 100644 --- a/src/overlay014/ov14_0221FC20.c +++ b/src/overlay014/ov14_0221FC20.c @@ -325,7 +325,7 @@ void ov14_0221FC20 (BattleSystem * param0, BattleContext * param1, u8 param2, u8 param3 = param3 >> 1; } - v1 = BattleSystem_CheckStruggling(param0, param1, param2, 0, 0xffffffff); + v1 = BattleSystem_CheckInvalidMoves(param0, param1, param2, 0, CHECK_INVALID_ALL); for (v0 = 0; v0 < LEARNED_MOVES_MAX; v0++) { if (v1 & FlagIndex(v0)) { diff --git a/src/overlay016/battle_controller.c b/src/overlay016/battle_controller.c index eb052c32ba..b3c3b9c860 100644 --- a/src/overlay016/battle_controller.c +++ b/src/overlay016/battle_controller.c @@ -430,7 +430,7 @@ static void BattleController_CommandSelectionInput(BattleSystem *battleSys, Batt switch (BattleContext_IOBufferVal(battleCtx, i)) { case PLAYER_INPUT_FIGHT: - if (BattleSystem_CheckStruggling(battleSys, battleCtx, i, 0, STRUGGLE_CHECK_ALL) == STRUGGLING_ALL) { + if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, i, 0, CHECK_INVALID_ALL) == STRUGGLING_ALL) { // Don't let the player select a move if they are out of PP on all moves battleCtx->turnFlags[i].struggling = TRUE; @@ -2169,9 +2169,9 @@ static int BattleController_CheckObedience(BattleSystem *battleSys, BattleContex rand1 = ((BattleSystem_RandNext(battleSys) & 0xFF) * (ATTACKING_MON.level + maxLevel)) >> 8; if (rand1 < maxLevel) { - rand1 = BattleSystem_CheckStruggling(battleSys, battleCtx, battleCtx->attacker, FlagIndex(ATTACKER_MOVE_SLOT), STRUGGLE_CHECK_ALL); + rand1 = BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battleCtx->attacker, FlagIndex(ATTACKER_MOVE_SLOT), CHECK_INVALID_ALL); - if (rand1 == 0xF) { + if (rand1 == STRUGGLING_ALL) { *nextSeq = BATTLE_SUBSEQ_DISOBEY_DO_NOTHING; return OBEY_CHECK_DO_NOTHING; } @@ -2570,7 +2570,7 @@ static BOOL BattleController_CheckStatusDisruption(BattleSystem *battleSys, Batt break; case CHECK_STATUS_STATE_IMPRISON: - if (BattleSystem_Imprisoned(battleSys, battleCtx, battleCtx->attacker, battleCtx->moveCur)) { + if (Move_Imprisoned(battleSys, battleCtx, battleCtx->attacker, battleCtx->moveCur)) { battleCtx->moveFailFlags[battleCtx->attacker].imprisoned = TRUE; LOAD_SUBSEQ(BATTLE_SUBSEQ_MOVE_IS_IMPRISONED); @@ -2584,7 +2584,7 @@ static BOOL BattleController_CheckStatusDisruption(BattleSystem *battleSys, Batt break; case CHECK_STATUS_STATE_GRAVITY: - if (BattleSystem_FailsInHighGravity(battleSys, battleCtx, battleCtx->attacker, battleCtx->moveCur)) { + if (Move_FailsInHighGravity(battleSys, battleCtx, battleCtx->attacker, battleCtx->moveCur)) { battleCtx->moveFailFlags[battleCtx->attacker].gravity = TRUE; LOAD_SUBSEQ(BATTLE_SUBSEQ_MOVE_FAIL_GRAVITY); @@ -2598,7 +2598,7 @@ static BOOL BattleController_CheckStatusDisruption(BattleSystem *battleSys, Batt break; case CHECK_STATUS_STATE_HEAL_BLOCK: - if (BattleSystem_HealBlocked(battleSys, battleCtx, battleCtx->attacker, battleCtx->moveCur)) { + if (Move_HealBlocked(battleSys, battleCtx, battleCtx->attacker, battleCtx->moveCur)) { battleCtx->moveFailFlags[battleCtx->attacker].healBlocked = TRUE; LOAD_SUBSEQ(BATTLE_SUBSEQ_MOVE_IS_HEAL_BLOCKED); diff --git a/src/overlay016/battle_script.c b/src/overlay016/battle_script.c index a6239d36e5..7ddefe6e19 100644 --- a/src/overlay016/battle_script.c +++ b/src/overlay016/battle_script.c @@ -5160,7 +5160,7 @@ static BOOL BtlCmd_TrySleepTalk(BattleSystem *battleSys, BattleContext *battleCt } // Check for other invalid moves (only skip the PP check) - invalidMovesMask = BattleSystem_CheckStruggling(battleSys, battleCtx, battleCtx->attacker, invalidMovesMask, ~STRUGGLE_CHECK_NO_PP); + invalidMovesMask = BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battleCtx->attacker, invalidMovesMask, ~CHECK_INVALID_NO_PP); if (invalidMovesMask == STRUGGLING_ALL) { BattleScript_Iter(battleCtx, jumpOnFail); } else { diff --git a/src/overlay016/ov16_0225177C.c b/src/overlay016/ov16_0225177C.c index e6aa786c21..8ac8f2b1b5 100644 --- a/src/overlay016/ov16_0225177C.c +++ b/src/overlay016/ov16_0225177C.c @@ -2241,157 +2241,165 @@ void BattleSystem_CleanupFaintedMon(BattleSystem *battleSys, BattleContext *batt BattleAI_ClearKnownItem(battleCtx, battler); } -void BattleSystem_SetupNextTurn (BattleSystem * param0, BattleContext * param1) +void BattleSystem_SetupNextTurn(BattleSystem *battleSys, BattleContext *battleCtx) { - int v0; - - for (v0 = 0; v0 < 4; v0++) { - MI_CpuClearFast(¶m1->turnFlags[v0], sizeof(struct TurnFlags)); - MI_CpuClearFast(¶m1->moveFailFlags[v0], sizeof(struct MoveFailFlags)); + for (int i = 0; i < MAX_BATTLERS; i++) { + MI_CpuClearFast(&battleCtx->turnFlags[i], sizeof(struct TurnFlags)); + MI_CpuClearFast(&battleCtx->moveFailFlags[i], sizeof(struct MoveFailFlags)); - param1->battleMons[v0].statusVolatile &= (0x8 ^ 0xffffffff); + battleCtx->battleMons[i].statusVolatile &= ~VOLATILE_CONDITION_FLINCH; - if (param1->battleMons[v0].moveEffectsData.rechargeTurnNumber + 1 < param1->totalTurns) { - param1->battleMons[v0].statusVolatile &= (0x400000 ^ 0xffffffff); + if (battleCtx->battleMons[i].moveEffectsData.rechargeTurnNumber + 1 < battleCtx->totalTurns) { + battleCtx->battleMons[i].statusVolatile &= ~VOLATILE_CONDITION_RECHARGING; } - if ((param1->battleMons[v0].status & 0x7) && (param1->battleMons[v0].statusVolatile & 0x1000)) { - Battler_UnlockMoveChoice(param0, param1, v0); + if ((battleCtx->battleMons[i].status & MON_CONDITION_SLEEP) + && (battleCtx->battleMons[i].statusVolatile & VOLATILE_CONDITION_MOVE_LOCKED)) { + Battler_UnlockMoveChoice(battleSys, battleCtx, i); } - if ((param1->battleMons[v0].status & 0x7) && (param1->battleMons[v0].statusVolatile & 0xc00)) { - param1->battleMons[v0].statusVolatile &= (0xc00 ^ 0xffffffff); + if ((battleCtx->battleMons[i].status & MON_CONDITION_SLEEP) + && (battleCtx->battleMons[i].statusVolatile & VOLATILE_CONDITION_THRASH)) { + battleCtx->battleMons[i].statusVolatile &= ~VOLATILE_CONDITION_THRASH; } } - param1->sideConditions[0].followMe = 0; - param1->sideConditions[1].followMe = 0; + battleCtx->sideConditions[BATTLER_US].followMe = FALSE; + battleCtx->sideConditions[BATTLER_THEM].followMe = FALSE; } -int BattleSystem_CheckStruggling (BattleSystem *battleSys, BattleContext *battleCtx, int battler, int moveFlags, int struggleChecksMask) +int BattleSystem_CheckInvalidMoves(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int invalidMoves, int opMask) { - int v0; - int v1; - - v1 = Battler_HeldItemEffect(battleCtx, battler); + int itemEffect = Battler_HeldItemEffect(battleCtx, battler); - for (v0 = 0; v0 < 4; v0++) { - if ((battleCtx->battleMons[battler].moves[v0] == 0) && (struggleChecksMask & 0x1)) { - moveFlags |= FlagIndex(v0); + for (int i = 0; i < LEARNED_MOVES_MAX; i++) { + if (battleCtx->battleMons[battler].moves[i] == MOVE_NONE + && (opMask & CHECK_INVALID_NO_MOVE)) { + invalidMoves |= FlagIndex(i); } - if ((battleCtx->battleMons[battler].ppCur[v0] == 0) && (struggleChecksMask & 0x2)) { - moveFlags |= FlagIndex(v0); + if (battleCtx->battleMons[battler].ppCur[i] == 0 + && (opMask & CHECK_INVALID_NO_PP)) { + invalidMoves |= FlagIndex(i); } - if ((battleCtx->battleMons[battler].moves[v0] == battleCtx->battleMons[battler].moveEffectsData.disabledMove) && (struggleChecksMask & 0x4)) { - moveFlags |= FlagIndex(v0); + if (battleCtx->battleMons[battler].moves[i] == battleCtx->battleMons[battler].moveEffectsData.disabledMove + && (opMask & CHECK_INVALID_DISABLED)) { + invalidMoves |= FlagIndex(i); } - if ((battleCtx->battleMons[battler].moves[v0] == battleCtx->movePrevByBattler[battler]) && (struggleChecksMask & 0x8) && (battleCtx->battleMons[battler].statusVolatile & 0x80000000)) { - moveFlags |= FlagIndex(v0); + if (battleCtx->battleMons[battler].moves[i] == battleCtx->movePrevByBattler[battler] + && (opMask & CHECK_INVALID_TORMENTED) + && (battleCtx->battleMons[battler].statusVolatile & VOLATILE_CONDITION_TORMENT)) { + invalidMoves |= FlagIndex(i); } - if ((battleCtx->battleMons[battler].moveEffectsData.tauntedTurns) && (struggleChecksMask & 0x10) && (battleCtx->aiContext.moveTable[battleCtx->battleMons[battler].moves[v0]].power == 0)) { - moveFlags |= FlagIndex(v0); + if (battleCtx->battleMons[battler].moveEffectsData.tauntedTurns + && (opMask & CHECK_INVALID_TAUNTED) + && MOVE_DATA(battleCtx->battleMons[battler].moves[i]).power == 0) { + invalidMoves |= FlagIndex(i); } - if ((BattleSystem_Imprisoned(battleSys, battleCtx, battler, battleCtx->battleMons[battler].moves[v0])) && (struggleChecksMask & 0x20)) { - moveFlags |= FlagIndex(v0); + if (Move_Imprisoned(battleSys, battleCtx, battler, battleCtx->battleMons[battler].moves[i]) + && (opMask & CHECK_INVALID_IMPRISONED)) { + invalidMoves |= FlagIndex(i); } - if ((BattleSystem_FailsInHighGravity(battleSys, battleCtx, battler, battleCtx->battleMons[battler].moves[v0])) && (struggleChecksMask & 0x40)) { - moveFlags |= FlagIndex(v0); + if (Move_FailsInHighGravity(battleSys, battleCtx, battler, battleCtx->battleMons[battler].moves[i]) + && (opMask & CHECK_INVALID_GRAVITY)) { + invalidMoves |= FlagIndex(i); } - if ((BattleSystem_HealBlocked(battleSys, battleCtx, battler, battleCtx->battleMons[battler].moves[v0])) && (struggleChecksMask & 0x80)) { - moveFlags |= FlagIndex(v0); + if (Move_HealBlocked(battleSys, battleCtx, battler, battleCtx->battleMons[battler].moves[i]) + && (opMask & CHECK_INVALID_HEAL_BLOCK)) { + invalidMoves |= FlagIndex(i); } - if ((battleCtx->battleMons[battler].moveEffectsData.encoredMove) && (battleCtx->battleMons[battler].moveEffectsData.encoredMove != battleCtx->battleMons[battler].moves[v0])) { - moveFlags |= FlagIndex(v0); + if (battleCtx->battleMons[battler].moveEffectsData.encoredMove + && battleCtx->battleMons[battler].moveEffectsData.encoredMove != battleCtx->battleMons[battler].moves[i]) { + invalidMoves |= FlagIndex(i); } - if (((v1 == 55) || (v1 == 115) || (v1 == 125)) && (struggleChecksMask & 0x200)) { - if (Battler_SlotForMove(&battleCtx->battleMons[battler], battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove) == 4) { - battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove = 0; - } else { - if ((battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove) && (battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove != battleCtx->battleMons[battler].moves[v0])) { - moveFlags |= FlagIndex(v0); - } + if ((itemEffect == HOLD_EFFECT_CHOICE_ATK || itemEffect == HOLD_EFFECT_CHOICE_SPEED || itemEffect == HOLD_EFFECT_CHOICE_SPATK) + && (opMask & CHECK_INVALID_CHOICE_ITEM)) { + if (Battler_SlotForMove(&battleCtx->battleMons[battler], battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove) == LEARNED_MOVES_MAX) { + battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove = MOVE_NONE; + } else if (battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove + && battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove != battleCtx->battleMons[battler].moves[i]) { + invalidMoves |= FlagIndex(i); } } } - return moveFlags; + return invalidMoves; } -BOOL BattleSystem_CanUseMove (BattleSystem *battleSys, BattleContext *battleCtx, int battler, int moveSlot, BattleMessage *msgOut) +BOOL BattleSystem_CanUseMove(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int moveSlot, BattleMessage *msgOut) { BOOL result = TRUE; - if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x4) & FlagIndex(moveSlot)) { - msgOut->tags = 10; - msgOut->id = 609; + if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_DISABLED) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NICKNAME_MOVE; + msgOut->id = 609; // "{0}'s {1} is disabled!" msgOut->params[0] = BattleSystem_NicknameTag(battleCtx, battler); msgOut->params[1] = battleCtx->battleMons[battler].moves[moveSlot]; result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x8) & FlagIndex(moveSlot)) { - msgOut->tags = 2; - msgOut->id = 612; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_TORMENTED) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NICKNAME; + msgOut->id = 612; // "{0} can't use the same move twice in a row due to the torment!" msgOut->params[0] = BattleSystem_NicknameTag(battleCtx, battler); result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x10) & FlagIndex(moveSlot)) { - msgOut->tags = 10; - msgOut->id = 613; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_TAUNTED) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NICKNAME_MOVE; + msgOut->id = 613; // "{0} can't use {1} after the taunt!" msgOut->params[0] = BattleSystem_NicknameTag(battleCtx, battler); msgOut->params[1] = battleCtx->battleMons[battler].moves[moveSlot]; result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x20) & FlagIndex(moveSlot)) { - msgOut->tags = 10; - msgOut->id = 616; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_IMPRISONED) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NICKNAME_MOVE; + msgOut->id = 616; // "{0} can't use the sealed {1}!" msgOut->params[0] = BattleSystem_NicknameTag(battleCtx, battler); msgOut->params[1] = battleCtx->battleMons[battler].moves[moveSlot]; result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x40) & FlagIndex(moveSlot)) { - msgOut->tags = 10; - msgOut->id = 1001; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_GRAVITY) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NICKNAME_MOVE; + msgOut->id = 1001; // "{0} can't use {1} because of gravity!" msgOut->params[0] = BattleSystem_NicknameTag(battleCtx, battler); msgOut->params[1] = battleCtx->battleMons[battler].moves[moveSlot]; result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x80) & FlagIndex(moveSlot)) { - msgOut->tags = 34; - msgOut->id = 1057; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_HEAL_BLOCK) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NICKNAME_MOVE_MOVE; + msgOut->id = 1057; // "{0} can't use {2} because of {1}!" msgOut->params[0] = BattleSystem_NicknameTag(battleCtx, battler); - msgOut->params[1] = 377; + msgOut->params[1] = MOVE_HEAL_BLOCK; msgOut->params[2] = battleCtx->battleMons[battler].moves[moveSlot]; result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x200) & FlagIndex(moveSlot)) { - msgOut->tags = 24; - msgOut->id = 911; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_CHOICE_ITEM) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_ITEM_MOVE; + msgOut->id = 911; // "The {0} allows the use of only {1}!" msgOut->params[0] = battleCtx->battleMons[battler].heldItem; msgOut->params[1] = battleCtx->battleMons[battler].moveEffectsData.choiceLockedMove; result = FALSE; - } else if (BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, 0x2) & FlagIndex(moveSlot)) { - msgOut->tags = 0; - msgOut->id = 823; + } else if (BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_NO_PP) & FlagIndex(moveSlot)) { + msgOut->tags = TAG_NONE; + msgOut->id = 823; // "There's no PP left for this move!" result = FALSE; } return result; } -int Battler_SlotForMove (BattleMon * param0, u16 param1) +int Battler_SlotForMove(BattleMon *mon, u16 move) { - int v0; + int i; - for (v0 = 0; v0 < LEARNED_MOVES_MAX; v0++) { - if (param0->moves[v0] == param1) { + for (i = 0; i < LEARNED_MOVES_MAX; i++) { + if (mon->moves[i] == move) { break; } } - return v0; + return i; } /** @@ -3312,33 +3320,32 @@ BOOL Battler_CheckTruant (BattleContext * param0, int param1) return v0; } -BOOL BattleSystem_Imprisoned (BattleSystem * param0, BattleContext * param1, int param2, int param3) +BOOL Move_Imprisoned(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move) { - int v0; - int v1; - int v2; - int v3; - BOOL v4; + // must declare C89-style to match + int i, maxBattlers, side, j; + BOOL result; - v4 = 0; - v1 = BattleSystem_MaxBattlers(param0); - v2 = Battler_Side(param0, param2); + result = FALSE; + maxBattlers = BattleSystem_MaxBattlers(battleSys); + side = Battler_Side(battleSys, battler); - for (v0 = 0; v0 < v1; v0++) { - if ((v2 != Battler_Side(param0, v0)) && (param1->battleMons[v0].moveEffectsMask & 0x2000)) { - for (v3 = 0; v3 < 4; v3++) { - if (param3 == param1->battleMons[v0].moves[v3]) { + for (i = 0; i < maxBattlers; i++) { + if (side != Battler_Side(battleSys, i) + && (battleCtx->battleMons[i].moveEffectsMask & MOVE_EFFECT_IMPRISON)) { + for (j = 0; j < LEARNED_MOVES_MAX; j++) { + if (move == battleCtx->battleMons[i].moves[j]) { break; } } - if (v3 != 4) { - v4 = 1; + if (j != LEARNED_MOVES_MAX) { + result = TRUE; } } } - return v4; + return result; } BOOL BattleSystem_AnyBattlersWithMoveEffect(BattleSystem *battleSys, BattleContext *battleCtx, int effectMask) @@ -3389,68 +3396,62 @@ void BattleSystem_SortMonsBySpeed (BattleSystem *battleSys, BattleContext *battl } } -static const u16 Unk_ov16_0226EBD4[] = { - 0x13, - 0x154, - 0x1A, - 0x88, - 0x96, - 0x189 +static const u16 sMovesAffectedByGravity[] = { + MOVE_FLY, + MOVE_BOUNCE, + MOVE_JUMP_KICK, + MOVE_HI_JUMP_KICK, + MOVE_SPLASH, + MOVE_MAGNET_RISE, }; -BOOL BattleSystem_FailsInHighGravity (BattleSystem * param0, BattleContext * param1, int param2, int param3) +BOOL Move_FailsInHighGravity(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move) { - int v0; - BOOL v1; - - v1 = 0; + BOOL result = FALSE; - if (param1->fieldConditionsMask & 0x7000) { - for (v0 = 0; v0 < NELEMS(Unk_ov16_0226EBD4); v0++) { - if (Unk_ov16_0226EBD4[v0] == param3) { - v1 = 1; + if (battleCtx->fieldConditionsMask & FIELD_CONDITION_GRAVITY) { + for (int i = 0; i < NELEMS(sMovesAffectedByGravity); i++) { + if (sMovesAffectedByGravity[i] == move) { + result = TRUE; break; } } } - return v1; + return result; } -static const u16 Unk_ov16_0226EBFA[] = { - 0x69, - 0x87, - 0x9C, - 0xD0, - 0xEA, - 0xEB, - 0xEC, - 0x100, - 0x1C8, - 0x12F, - 0x163, - 0x1CD, - 0x169, - 0x111 +static const u16 sMovesAffectedByHealBlock[] = { + MOVE_RECOVER, + MOVE_SOFTBOILED, + MOVE_REST, + MOVE_MILK_DRINK, + MOVE_MORNING_SUN, + MOVE_SYNTHESIS, + MOVE_MOONLIGHT, + MOVE_SWALLOW, + MOVE_HEAL_ORDER, + MOVE_SLACK_OFF, + MOVE_ROOST, + MOVE_LUNAR_DANCE, + MOVE_HEALING_WISH, + MOVE_WISH, }; -BOOL BattleSystem_HealBlocked (BattleSystem * param0, BattleContext * param1, int param2, int param3) +BOOL Move_HealBlocked(BattleSystem *battleSys, BattleContext *battleCtx, int battler, int move) { - int v0; - BOOL v1; - - v1 = 0; + BOOL result = FALSE; - if (param1->battleMons[param2].moveEffectsData.healBlockTurns) { - for (v0 = 0; v0 < NELEMS(Unk_ov16_0226EBFA); v0++) { - if (Unk_ov16_0226EBFA[v0] == param3) { - v1 = 1; + if (battleCtx->battleMons[battler].moveEffectsData.healBlockTurns) { + for (int i = 0; i < NELEMS(sMovesAffectedByHealBlock); i++) { + if (sMovesAffectedByHealBlock[i] == move) { + result = TRUE; break; } } } - return v1; + return result; } void BattleSystem_UpdateLastResort (BattleSystem * param0, BattleContext * param1) @@ -7201,8 +7202,8 @@ BOOL Move_CanBeMetronomed(BattleSystem *battleSys, BattleContext *battleCtx, int { int i = 0; - if (BattleSystem_FailsInHighGravity(battleSys, battleCtx, battler, move) == TRUE - || BattleSystem_HealBlocked(battleSys, battleCtx, battler, move) == TRUE) { + if (Move_FailsInHighGravity(battleSys, battleCtx, battler, move) == TRUE + || Move_HealBlocked(battleSys, battleCtx, battler, move) == TRUE) { return FALSE; } diff --git a/src/overlay016/ov16_0226485C.c b/src/overlay016/ov16_0226485C.c index 85572dd699..4409b6b19e 100644 --- a/src/overlay016/ov16_0226485C.c +++ b/src/overlay016/ov16_0226485C.c @@ -763,7 +763,7 @@ void BattleIO_ShowMoveSelectScreen (BattleSystem *battleSys, BattleContext *batt v0.unk_10[i] = MoveTable_CalcMaxPP(battleCtx->battleMons[battler].moves[i], battleCtx->battleMons[battler].ppUps[i]); } - v0.unk_02 = BattleSystem_CheckStruggling(battleSys, battleCtx, battler, 0, STRUGGLE_CHECK_ALL); + v0.unk_02 = BattleSystem_CheckInvalidMoves(battleSys, battleCtx, battler, 0, CHECK_INVALID_ALL); ov16_02264A04(battleSys, 1, battler, &v0, sizeof(UnkStruct_ov16_022656F0)); } From bbbec7a357d24c4fe2ef092dee7c7aa067a6cd02 Mon Sep 17 00:00:00 2001 From: Rachel Date: Fri, 10 Nov 2023 22:19:41 -0800 Subject: [PATCH 3/3] Document Move_IsGhostCurse, Move_IsMultiTurn, and Battler_Ability --- include/battle/common.h | 4 +- include/overlay016/ov16_0225177C.h | 34 +++++++++++++++-- src/overlay014/ov14_0221FC20.c | 2 +- src/overlay016/battle_controller.c | 8 ++-- src/overlay016/battle_script.c | 4 +- src/overlay016/ov16_0225177C.c | 60 ++++++++++++++++-------------- 6 files changed, 73 insertions(+), 39 deletions(-) diff --git a/include/battle/common.h b/include/battle/common.h index cd8a46d427..271fe1c61e 100644 --- a/include/battle/common.h +++ b/include/battle/common.h @@ -51,9 +51,9 @@ #define MON_HAS_TYPE(mon, type) (BattleMon_Get(battleCtx, mon, BATTLEMON_TYPE_1, NULL) == type || BattleMon_Get(battleCtx, mon, BATTLEMON_TYPE_2, NULL) == type) #define MON_IS_NOT_TYPE(mon, type) (BattleMon_Get(battleCtx, mon, BATTLEMON_TYPE_1, NULL) != type && BattleMon_Get(battleCtx, mon, BATTLEMON_TYPE_2, NULL) != type) -#define NO_TARGET_SINGLE_TURN (battleCtx->defender == BATTLER_NONE && BattleMove_IsMultiTurn(battleCtx, battleCtx->moveCur) == FALSE) +#define NO_TARGET_SINGLE_TURN (battleCtx->defender == BATTLER_NONE && Move_IsMultiTurn(battleCtx, battleCtx->moveCur) == FALSE) #define NO_TARGET_MULTI_TURN (battleCtx->defender == BATTLER_NONE \ - && BattleMove_IsMultiTurn(battleCtx, battleCtx->moveCur) == TRUE \ + && Move_IsMultiTurn(battleCtx, battleCtx->moveCur) == TRUE \ && ( \ (ATTACKING_MON.statusVolatile & VOLATILE_CONDITION_MOVE_LOCKED) \ || (battleCtx->battleStatusMask & SYSCTL_LAST_OF_MULTI_TURN) \ diff --git a/include/overlay016/ov16_0225177C.h b/include/overlay016/ov16_0225177C.h index b60946f385..57719f079a 100644 --- a/include/overlay016/ov16_0225177C.h +++ b/include/overlay016/ov16_0225177C.h @@ -568,7 +568,16 @@ u16 Battler_SelectedMove(BattleContext * param0, int param1); * be a mask of the battlers matching the criteria. */ int BattleSystem_CountAbility(BattleSystem *battleSys, BattleContext *battleCtx, enum CountAbilityMode mode, int battler, int ability); -BOOL BattleMove_IsMultiTurn(BattleContext * param0, int param1); + +/** + * @brief Determine if a given move is a multi-turn move. + * + * @param battleCtx + * @param move + * @return TRUE if the move is a multi-turn move (one which has a charging + * turn); FALSE if not + */ +BOOL Move_IsMultiTurn(BattleContext *battleCtx, int move); /** * @brief Access a particular entry in the type-matchup table. @@ -616,7 +625,17 @@ int BattleSystem_TypeMatchupMultiplier(u8 attackingType, u8 defendingType1, u8 d * @return TRUE if the move is invoker-class, FALSE if not. */ BOOL Move_IsInvoker(u16 move); -BOOL BattleSystem_IsGhostCurse(BattleContext * param0, u16 param1, int param2); + +/** + * @brief Check if a given move is Curse being used by a Ghost-type Pokemon. + * + * @param battleCtx + * @param move + * @param battler + * @return TRUE if the move is Curse and the battler has the Ghost typing; + * FALSE otherwise + */ +BOOL Move_IsGhostCurse(BattleContext *battleCtx, u16 move, int battler); /** * @brief Determine if a battler's item can be stolen. @@ -645,7 +664,16 @@ BOOL BattleSystem_NotHoldingMail(BattleContext * param0, int param1); * @return TRUE if Whirlwind should succeed, FALSE if it should fail. */ BOOL BattleSystem_CanWhirlwind(BattleSystem *battleSys, BattleContext *battleCtx); -u8 Battler_Ability(BattleContext * param0, int param1); + +/** + * @brief Get the battler's ability, accounting for disrupting effects on itself, + * e.g. Gastro Acid, Gravity, and Ingrain. + * + * @param battleCtx + * @param battler + * @return The battler's ability + */ +u8 Battler_Ability(BattleContext *battleCtx, int battler); /** * @brief Check if the given defender has the specified ability, treating it as diff --git a/src/overlay014/ov14_0221FC20.c b/src/overlay014/ov14_0221FC20.c index 908a0c3a28..858bf5e73a 100644 --- a/src/overlay014/ov14_0221FC20.c +++ b/src/overlay014/ov14_0221FC20.c @@ -541,7 +541,7 @@ static u8 ov14_0221FE38 (BattleSystem * param0, BattleContext * param1) } if (v7 == 174) { - if (BattleSystem_IsGhostCurse(param1, v7, param1->aiContext.attacker) == 0) { + if (Move_IsGhostCurse(param1, v7, param1->aiContext.attacker) == 0) { param1->aiContext.selectedTarget[param1->aiContext.attacker] = param1->aiContext.attacker; } } diff --git a/src/overlay016/battle_controller.c b/src/overlay016/battle_controller.c index b3c3b9c860..184286492a 100644 --- a/src/overlay016/battle_controller.c +++ b/src/overlay016/battle_controller.c @@ -2325,7 +2325,7 @@ static BOOL BattleController_HasNoTarget(BattleSystem *battleSys, BattleContext // Don't alter the target for charge-turn moves that are just charging up this turn if (battleCtx->defender == BATTLER_NONE - && BattleMove_IsMultiTurn(battleCtx, battleCtx->moveCur) == TRUE + && Move_IsMultiTurn(battleCtx, battleCtx->moveCur) == TRUE && result == FALSE && solarMove == FALSE && Battler_HeldItemEffect(battleCtx, battleCtx->attacker) != HOLD_EFFECT_CHARGE_SKIP @@ -3007,8 +3007,8 @@ static int BattleController_CheckMoveHitOverrides(BattleSystem *battleSys, Battl if (battleCtx->turnFlags[defender].protecting && (MOVE_DATA(move).flags & MOVE_FLAG_CAN_PROTECT) - && (move != MOVE_CURSE || BattleSystem_IsGhostCurse(battleCtx, move, attacker) == TRUE) // Ghost-Curse can be Protected - && (BattleMove_IsMultiTurn(battleCtx, move) == FALSE || (battleCtx->battleStatusMask & SYSCTL_LAST_OF_MULTI_TURN))) { + && (move != MOVE_CURSE || Move_IsGhostCurse(battleCtx, move, attacker) == TRUE) // Ghost-Curse can be Protected + && (Move_IsMultiTurn(battleCtx, move) == FALSE || (battleCtx->battleStatusMask & SYSCTL_LAST_OF_MULTI_TURN))) { Battler_UnlockMoveChoice(battleSys, battleCtx, attacker); battleCtx->moveStatusFlags |= MOVE_STATUS_PROTECTED; return 0; @@ -4348,7 +4348,7 @@ static BOOL BattleController_CheckBattleOver(BattleSystem * battleSys, BattleCon static BOOL BattleController_MustSelectTarget(BattleSystem *battleSys, BattleContext *battleCtx, u8 battler, u32 battleType, int *range, int moveSlot, u32 *target) { if (battleCtx->battleMons[battler].moves[moveSlot] == MOVE_CURSE - && BattleSystem_IsGhostCurse(battleCtx, battleCtx->battleMons[battler].moves[moveSlot], battler) == FALSE) { + && Move_IsGhostCurse(battleCtx, battleCtx->battleMons[battler].moves[moveSlot], battler) == FALSE) { *range = RANGE_USER; } else { *range = MOVE_DATA(battleCtx->battleMons[battler].moves[moveSlot]).range; diff --git a/src/overlay016/battle_script.c b/src/overlay016/battle_script.c index 7ddefe6e19..b0532a0475 100644 --- a/src/overlay016/battle_script.c +++ b/src/overlay016/battle_script.c @@ -5011,7 +5011,7 @@ static BOOL BtlCmd_TryConversion2(BattleSystem *battleSys, BattleContext *battle if (battleCtx->conversion2Move[battleCtx->attacker] && battleCtx->conversion2Battler[battleCtx->attacker] != BATTLER_NONE) { // Fail to execute if the source move's owner is locked into the first turn of a multi-turn move - if (BattleMove_IsMultiTurn(battleCtx, battleCtx->conversion2Move[battleCtx->attacker]) + if (Move_IsMultiTurn(battleCtx, battleCtx->conversion2Move[battleCtx->attacker]) && (battleCtx->battleMons[battleCtx->conversion2Battler[battleCtx->attacker]].statusVolatile & VOLATILE_CONDITION_MOVE_LOCKED)) { BattleScript_Iter(battleCtx, jumpOnFail); return FALSE; @@ -5154,7 +5154,7 @@ static BOOL BtlCmd_TrySleepTalk(BattleSystem *battleSys, BattleContext *battleCt || ATTACKING_MON.moves[i] == MOVE_FOCUS_PUNCH || ATTACKING_MON.moves[i] == MOVE_UPROAR || ATTACKING_MON.moves[i] == MOVE_CHATTER - || BattleMove_IsMultiTurn(battleCtx, ATTACKING_MON.moves[i])) { + || Move_IsMultiTurn(battleCtx, ATTACKING_MON.moves[i])) { invalidMovesMask |= FlagIndex(i); } } diff --git a/src/overlay016/ov16_0225177C.c b/src/overlay016/ov16_0225177C.c index 8ac8f2b1b5..77ac97843e 100644 --- a/src/overlay016/ov16_0225177C.c +++ b/src/overlay016/ov16_0225177C.c @@ -2981,24 +2981,23 @@ int BattleSystem_CountAbility(BattleSystem *battleSys, BattleContext *battleCtx, return result; } -BOOL BattleMove_IsMultiTurn (BattleContext * param0, int param1) -{ - switch (param0->aiContext.moveTable[param1].effect) { - case 26: - case 39: - case 75: - case 145: - case 151: - case 155: - case 255: - case 256: - case 263: - case 272: - return 1; - break; +BOOL Move_IsMultiTurn(BattleContext *battleCtx, int move) +{ + switch (MOVE_DATA(move).effect) { + case BATTLE_EFFECT_BIDE: + case BATTLE_EFFECT_CHARGE_TURN_HIGH_CRIT: + case BATTLE_EFFECT_CHARGE_TURN_HIGH_CRIT_FLINCH: + case BATTLE_EFFECT_CHARGE_TURN_DEF_UP: + case BATTLE_EFFECT_SKIP_CHARGE_TURN_IN_SUN: + case BATTLE_EFFECT_FLY: + case BATTLE_EFFECT_DIVE: + case BATTLE_EFFECT_DIG: + case BATTLE_EFFECT_BOUNCE: + case BATTLE_EFFECT_SHADOW_FORCE: + return TRUE; } - return 0; + return FALSE; } BOOL BattleSystem_TypeMatchup(BattleSystem *battleSys, int idx, u8 *moveType, u8 *vsType, u8 *multi) @@ -3055,9 +3054,9 @@ BOOL Move_IsInvoker(u16 move) return FALSE; } -BOOL BattleSystem_IsGhostCurse (BattleContext * param0, u16 param1, int param2) +BOOL Move_IsGhostCurse(BattleContext *battleCtx, u16 move, int battler) { - return (param1 == 174) && ((BattleMon_Get(param0, param2, 27, NULL) == 7) || (BattleMon_Get(param0, param2, 28, NULL) == 7)); + return move == MOVE_CURSE && MON_HAS_TYPE(battler, TYPE_GHOST); } BOOL BattleSystem_CanStealItem(BattleSystem *battleSys, BattleContext *battleCtx, int battler) @@ -3095,17 +3094,24 @@ BOOL BattleSystem_CanWhirlwind(BattleSystem *battleSys, BattleContext *battleCtx return result; } -u8 Battler_Ability (BattleContext * param0, int param1) +u8 Battler_Ability(BattleContext *battleCtx, int battler) { - if ((param0->battleMons[param1].moveEffectsMask & 0x200000) && (param0->battleMons[param1].ability != 121)) { - return 0; - } else if ((param0->fieldConditionsMask & 0x7000) && (param0->battleMons[param1].ability == 26)) { - return 0; - } else if ((param0->battleMons[param1].moveEffectsMask & 0x400) && (param0->battleMons[param1].ability == 26)) { - return 0; - } else { - return param0->battleMons[param1].ability; + if ((battleCtx->battleMons[battler].moveEffectsMask & MOVE_EFFECT_ABILITY_SUPPRESSED) + && battleCtx->battleMons[battler].ability != ABILITY_MULTITYPE) { + return ABILITY_NONE; + } + + if ((battleCtx->fieldConditionsMask & FIELD_CONDITION_GRAVITY) + && battleCtx->battleMons[battler].ability == ABILITY_LEVITATE) { + return ABILITY_NONE; + } + + if ((battleCtx->battleMons[battler].moveEffectsMask & MOVE_EFFECT_INGRAIN) + && battleCtx->battleMons[battler].ability == ABILITY_LEVITATE) { + return ABILITY_NONE; } + + return battleCtx->battleMons[battler].ability; } BOOL Battler_IgnorableAbility(BattleContext *battleCtx, int attacker, int defender, int ability)