diff --git a/include/battle.h b/include/battle.h index deff8df86..43fbd67a1 100644 --- a/include/battle.h +++ b/include/battle.h @@ -177,8 +177,6 @@ struct DisableStruct struct ProtectStruct { u32 protected:1; - u32 wideGuarded:1; - u32 quickGuarded:1; u32 spikyShielded:1; u32 kingsShielded:1; u32 banefulBunkered:1; @@ -589,7 +587,6 @@ struct BattleStruct struct MegaEvolutionData mega; const u8 *trainerSlideMsg; bool8 trainerSlideLowHpMsgDone; - s8 movePriorities[MAX_BATTLERS_COUNT]; }; #define GET_MOVE_TYPE(move, typeArg) \ diff --git a/include/battle_main.h b/include/battle_main.h index da716a0be..b68acfeab 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -80,6 +80,7 @@ u8 IsRunningFromBattleImpossible(void); void sub_803BDA0(u8 battlerId); void SwapTurnOrder(u8 id1, u8 id2); u32 GetBattlerTotalSpeedStat(u8 battlerId); +s8 GetMovePriority(u8 battlerId); u8 GetWhoStrikesFirst(u8 battlerId1, u8 battlerId2, bool8 ignoreChosenMoves); void RunBattleScriptCommands_PopCallbacksStack(void); void RunBattleScriptCommands(void); diff --git a/include/constants/battle.h b/include/constants/battle.h index 22f7be7c6..17114ba55 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -209,6 +209,8 @@ #define SIDE_STATUS_STEALTH_ROCK_DAMAGED (1 << 15) #define SIDE_STATUS_TOXIC_SPIKES_DAMAGED (1 << 16) #define SIDE_STATUS_STICKY_WEB_DAMAGED (1 << 17) +#define SIDE_STATUS_QUICK_GUARD (1 << 18) +#define SIDE_STATUS_WIDE_GUARD (1 << 18) // Field affecting statuses. #define STATUS_FIELD_MAGIC_ROOM 0x1 diff --git a/src/battle_debug.c b/src/battle_debug.c index d67271d83..52dd91cca 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -109,6 +109,7 @@ enum VAR_SHOW_HP, VAR_SUBSTITUTE, VAR_IN_LOVE, + VAR_U16_4_ENTRIES, }; enum @@ -855,6 +856,8 @@ static void CreateSecondaryListMenu(struct BattleDebugMenu *data) itemsCount = 3; break; case LIST_ITEM_MOVES: + itemsCount = 5; + break; case LIST_ITEM_PP: itemsCount = 4; break; @@ -958,6 +961,15 @@ static void PrintSecondaryEntries(struct BattleDebugMenu *data) printer.currentY = printer.y = (i * yMultiplier) + sSecondaryListTemplate.upText_Y; AddTextPrinter(&printer, 0, NULL); } + // Allow changing all moves at once. Useful for testing in wild doubles. + if (data->currentMainListItemId == LIST_ITEM_MOVES) + { + u8 textAll[] = _("All"); + + PadString(textAll, text); + printer.currentY = printer.y = (i * yMultiplier) + sSecondaryListTemplate.upText_Y; + AddTextPrinter(&printer, 0, NULL); + } break; case LIST_ITEM_ABILITY: PadString(gAbilityNames[gBattleMons[data->battlerId].ability], text); @@ -1052,6 +1064,12 @@ static void UpdateBattlerValue(struct BattleDebugMenu *data) case VAL_U16: *(u16*)(data->modifyArrows.modifiedValPtr) = data->modifyArrows.currValue; break; + case VAR_U16_4_ENTRIES: + ((u16*)(data->modifyArrows.modifiedValPtr))[0] = data->modifyArrows.currValue; + ((u16*)(data->modifyArrows.modifiedValPtr))[1] = data->modifyArrows.currValue; + ((u16*)(data->modifyArrows.modifiedValPtr))[2] = data->modifyArrows.currValue; + ((u16*)(data->modifyArrows.modifiedValPtr))[3] = data->modifyArrows.currValue; + break; case VAL_U32: *(u32*)(data->modifyArrows.modifiedValPtr) = data->modifyArrows.currValue; break; @@ -1273,9 +1291,18 @@ static void SetUpModifyArrows(struct BattleDebugMenu *data) data->modifyArrows.minValue = 0; data->modifyArrows.maxValue = MOVES_COUNT_GEN7 - 1; data->modifyArrows.maxDigits = 3; - data->modifyArrows.modifiedValPtr = &gBattleMons[data->battlerId].moves[data->currentSecondaryListItemId]; - data->modifyArrows.typeOfVal = VAL_U16; - data->modifyArrows.currValue = gBattleMons[data->battlerId].moves[data->currentSecondaryListItemId]; + if (data->currentSecondaryListItemId == 4) + { + data->modifyArrows.modifiedValPtr = &gBattleMons[data->battlerId].moves[0]; + data->modifyArrows.currValue = gBattleMons[data->battlerId].moves[0]; + data->modifyArrows.typeOfVal = VAR_U16_4_ENTRIES; + } + else + { + data->modifyArrows.modifiedValPtr = &gBattleMons[data->battlerId].moves[data->currentSecondaryListItemId]; + data->modifyArrows.currValue = gBattleMons[data->battlerId].moves[data->currentSecondaryListItemId]; + data->modifyArrows.typeOfVal = VAL_U16; + } break; case LIST_ITEM_PP: data->modifyArrows.minValue = 0; diff --git a/src/battle_main.c b/src/battle_main.c index d5afc7c2f..fab12d3ed 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3238,8 +3238,6 @@ void FaintClearSetData(void) ptr[i] = 0; gProtectStructs[gActiveBattler].protected = 0; - gProtectStructs[gActiveBattler].wideGuarded = 0; - gProtectStructs[gActiveBattler].quickGuarded = 0; gProtectStructs[gActiveBattler].spikyShielded = 0; gProtectStructs[gActiveBattler].kingsShielded = 0; gProtectStructs[gActiveBattler].banefulBunkered = 0; @@ -4711,8 +4709,9 @@ u32 GetBattlerTotalSpeedStat(u8 battlerId) return speed; } -static s8 GetMovePriority(u8 battlerId) +s8 GetMovePriority(u8 battlerId) { + s8 priority; u16 move; if (gProtectStructs[battlerId].noValidMoves) @@ -4720,17 +4719,17 @@ static s8 GetMovePriority(u8 battlerId) else move = gBattleMons[battlerId].moves[*(gBattleStruct->chosenMovePositions + battlerId)]; - gBattleStruct->movePriorities[battlerId] = gBattleMoves[move].priority; + priority = gBattleMoves[move].priority; if (GetBattlerAbility(battlerId) == ABILITY_GALE_WINGS && gBattleMoves[move].type == TYPE_FLYING && (B_GALE_WINGS == GEN_6 || BATTLER_MAX_HP(battlerId))) { - gBattleStruct->movePriorities[battlerId]++; + priority++; } else if (GetBattlerAbility(battlerId) == ABILITY_PRANKSTER && gBattleMoves[move].split == SPLIT_STATUS) { - gBattleStruct->movePriorities[battlerId]++; + priority++; } else if (GetBattlerAbility(battlerId) == ABILITY_TRIAGE) { @@ -4748,12 +4747,12 @@ static s8 GetMovePriority(u8 battlerId) case EFFECT_SOFTBOILED: case EFFECT_ABSORB: case EFFECT_ROOST: - gBattleStruct->movePriorities[battlerId] += 3; + priority += 3; break; } } - return gBattleStruct->movePriorities[battlerId]; + return priority; } u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves) @@ -4949,9 +4948,6 @@ static void TurnValuesCleanUp(bool8 var0) if (var0) { gProtectStructs[gActiveBattler].protected = 0; - gProtectStructs[gActiveBattler].endured = 0; - gProtectStructs[gActiveBattler].wideGuarded = 0; - gProtectStructs[gActiveBattler].quickGuarded = 0; gProtectStructs[gActiveBattler].spikyShielded = 0; gProtectStructs[gActiveBattler].kingsShielded = 0; gProtectStructs[gActiveBattler].banefulBunkered = 0; @@ -4977,6 +4973,8 @@ static void TurnValuesCleanUp(bool8 var0) gBattleMons[gActiveBattler].status2 &= ~(STATUS2_SUBSTITUTE); } + gSideStatuses[0] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD); + gSideStatuses[1] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD); gSideTimers[0].followmeTimer = 0; gSideTimers[1].followmeTimer = 0; } diff --git a/src/battle_message.c b/src/battle_message.c index 3eddc2295..0e3ec0652 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -551,7 +551,7 @@ static const u8 sText_PointedStonesFloat[] =_("Pointed stones float in the air\n static const u8 sText_CloakedInMysticalMoonlight[] =_("It became cloaked in mystical\nmoonlight!"); static const u8 sText_TrappedBySwirlingMagma[] =_("{B_DEF_NAME_WITH_PREFIX} became\ntrapped by swirling magma!"); static const u8 sText_VanishedInstantly[] =_("{B_ATK_NAME_WITH_PREFIX} vanished\ninstantly!"); -static const u8 sText_ProtectedTeam[] =_("{B_CURRENT_MOVE} protected\nyour team!"); +static const u8 sText_ProtectedTeam[] =_("{B_CURRENT_MOVE} protected\n{B_ATK_TEAM}!"); static const u8 sText_SharedItsGuard[] =_("{B_ATK_NAME_WITH_PREFIX} shared its\nguard with the target!"); static const u8 sText_SharedItsPower[] =_("{B_ATK_NAME_WITH_PREFIX} shared its\npower with the target!"); static const u8 sText_SwapsDefAndSpDefOfAllPkmn[] =_("It created a bizarre area in which\nthe Defense and Sp.Def stats are swapped!"); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 38dccfad5..5078f0dc9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -903,7 +903,7 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) return FALSE; else if (gProtectStructs[battlerId].protected) return TRUE; - else if ((gProtectStructs[battlerId].wideGuarded || gProtectStructs[BATTLE_PARTNER(battlerId)].wideGuarded) + else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD && gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)) return TRUE; else if (gProtectStructs[battlerId].banefulBunkered) @@ -912,8 +912,8 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move) return TRUE; else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0) return TRUE; - else if ((gProtectStructs[battlerId].quickGuarded || gProtectStructs[BATTLE_PARTNER(battlerId)].quickGuarded) - && gBattleStruct->movePriorities[battlerId] > 0) + else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_QUICK_GUARD + && GetMovePriority(gBattlerAttacker) > 0) return TRUE; else return FALSE; @@ -2732,15 +2732,15 @@ void SetMoveEffect(bool8 primary, u8 certain) break; case MOVE_EFFECT_FEINT: if (gProtectStructs[gBattlerTarget].protected - || gProtectStructs[gBattlerTarget].wideGuarded - || gProtectStructs[gBattlerTarget].quickGuarded + || gSideStatuses[GetBattlerSide(gBattlerTarget)] & SIDE_STATUS_WIDE_GUARD + || gSideStatuses[GetBattlerSide(gBattlerTarget)] & SIDE_STATUS_QUICK_GUARD || gProtectStructs[gBattlerTarget].spikyShielded || gProtectStructs[gBattlerTarget].kingsShielded || gProtectStructs[gBattlerTarget].banefulBunkered) { gProtectStructs[gBattlerTarget].protected = 0; - gProtectStructs[gBattlerTarget].wideGuarded = 0; - gProtectStructs[gBattlerTarget].quickGuarded = 0; + gSideStatuses[GetBattlerSide(gBattlerTarget)] &= ~(SIDE_STATUS_WIDE_GUARD); + gSideStatuses[GetBattlerSide(gBattlerTarget)] &= ~(SIDE_STATUS_QUICK_GUARD); gProtectStructs[gBattlerTarget].spikyShielded = 0; gProtectStructs[gBattlerTarget].kingsShielded = 0; gProtectStructs[gBattlerTarget].banefulBunkered = 0; @@ -7202,8 +7202,9 @@ static void atk76_various(void) gBattlescriptCurrInstr += 3; } -static void atk77_setprotectlike(void) // protect and endure +static void atk77_setprotectlike(void) { + bool32 fail = TRUE; bool32 notLastTurn = TRUE; if (!(gBattleMoves[gLastResultingMoves[gBattlerAttacker]].flags & FLAG_PROTECTION_MOVE)) @@ -7214,44 +7215,58 @@ static void atk77_setprotectlike(void) // protect and endure if (sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] >= Random() && notLastTurn) { - if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE) + if (!gBattleMoves[gCurrentMove].argument) // Protects one mon only. { - gProtectStructs[gBattlerAttacker].endured = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; + if (gBattleMoves[gCurrentMove].effect == EFFECT_ENDURE) + { + gProtectStructs[gBattlerAttacker].endured = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + } + else if (gCurrentMove == MOVE_DETECT || gCurrentMove == MOVE_PROTECT) + { + gProtectStructs[gBattlerAttacker].protected = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else if (gCurrentMove == MOVE_SPIKY_SHIELD) + { + gProtectStructs[gBattlerAttacker].spikyShielded = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else if (gCurrentMove == MOVE_KING_S_SHIELD) + { + gProtectStructs[gBattlerAttacker].kingsShielded = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + else if (gCurrentMove == MOVE_BANEFUL_BUNKER) + { + gProtectStructs[gBattlerAttacker].banefulBunkered = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + } + + gDisableStructs[gBattlerAttacker].protectUses++; + fail = FALSE; } - else if (gCurrentMove == MOVE_DETECT || gCurrentMove == MOVE_PROTECT) + else // Protects the whole side. { - gProtectStructs[gBattlerAttacker].protected = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; + u8 side = GetBattlerSide(gBattlerAttacker); + if (gCurrentMove == MOVE_WIDE_GUARD && !(gSideStatuses[side] & SIDE_STATUS_WIDE_GUARD)) + { + gSideStatuses[side] |= SIDE_STATUS_WIDE_GUARD; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gDisableStructs[gBattlerAttacker].protectUses++; + fail = FALSE; + } + else if (gCurrentMove == MOVE_QUICK_GUARD && !(gSideStatuses[side] & SIDE_STATUS_QUICK_GUARD)) + { + gSideStatuses[side] |= SIDE_STATUS_QUICK_GUARD; + gBattleCommunication[MULTISTRING_CHOOSER] = 3; + gDisableStructs[gBattlerAttacker].protectUses++; + fail = FALSE; + } } - else if (gCurrentMove == MOVE_SPIKY_SHIELD) - { - gProtectStructs[gBattlerAttacker].spikyShielded = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else if (gCurrentMove == MOVE_KING_S_SHIELD) - { - gProtectStructs[gBattlerAttacker].kingsShielded = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else if (gCurrentMove == MOVE_BANEFUL_BUNKER) - { - gProtectStructs[gBattlerAttacker].banefulBunkered = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 0; - } - else if (gCurrentMove == MOVE_WIDE_GUARD) - { - gProtectStructs[gBattlerAttacker].wideGuarded = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 3; - } - else if (gCurrentMove == MOVE_QUICK_GUARD) - { - gProtectStructs[gBattlerAttacker].quickGuarded = 1; - gBattleCommunication[MULTISTRING_CHOOSER] = 3; - } - gDisableStructs[gBattlerAttacker].protectUses++; } - else + + if (fail) { gDisableStructs[gBattlerAttacker].protectUses = 0; gBattleCommunication[MULTISTRING_CHOOSER] = 2; diff --git a/src/battle_util.c b/src/battle_util.c index 81997b575..e5f7f5b29 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2319,7 +2319,7 @@ u8 AtkCanceller_UnableToUseMove2(void) case CANCELLER_PSYCHIC_TERRAIN: if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN && IsBattlerGrounded(gBattlerAttacker) - && gBattleStruct->movePriorities[gBattlerAttacker] > 0 + && GetMovePriority(gBattlerAttacker) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) { CancelMultiTurnMoves(gBattlerAttacker); @@ -2899,7 +2899,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA else if ((gLastUsedAbility == ABILITY_DAZZLING || (IsBattlerAlive(battler ^= BIT_FLANK) && GetBattlerAbility(battler) == ABILITY_DAZZLING) ) - && gBattleStruct->movePriorities[gBattlerAttacker] > 0 + && GetMovePriority(battler) > 0 && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(battler)) { if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS) diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 9c6ded27c..4ea7c9f85 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -6587,6 +6587,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .priority = 3, .flags = FLAG_PROTECTION_MOVE, .split = SPLIT_STATUS, + .argument = TRUE, // Protects the whole side. }, [MOVE_GUARD_SPLIT] = @@ -7035,6 +7036,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .priority = 3, .flags = FLAG_PROTECTION_MOVE, .split = SPLIT_STATUS, + .argument = TRUE, // Protects the whole side. }, [MOVE_ALLY_SWITCH] =