diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f5bedcbf7f..612c771871 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,9 +11,9 @@ -## Issue(s) that this PR introduces +## Feature(s) this PR does NOT handle: ## **Discord contact info** - \ No newline at end of file + diff --git a/include/battle.h b/include/battle.h index 77b86591f9..5fddd8d11f 100644 --- a/include/battle.h +++ b/include/battle.h @@ -1034,7 +1034,6 @@ extern u32 gStatuses4[MAX_BATTLERS_COUNT]; extern struct DisableStruct gDisableStructs[MAX_BATTLERS_COUNT]; extern u16 gPauseCounterBattle; extern u16 gPaydayMoney; -extern u16 gRandomTurnNumber; extern u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT]; extern u8 gBattleOutcome; extern struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT]; diff --git a/include/random.h b/include/random.h index d4dd359b38..c3d6067efa 100644 --- a/include/random.h +++ b/include/random.h @@ -97,6 +97,7 @@ enum RandomTag RNG_TRIPLE_ARROWS_DEFENSE_DOWN, RNG_TRIPLE_ARROWS_FLINCH, RNG_QUICK_DRAW, + RNG_QUICK_CLAW, RNG_TRACE, }; diff --git a/src/battle_main.c b/src/battle_main.c index 93702541c5..cd2e4a8f73 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -100,7 +100,8 @@ static void SetActionsAndBattlersTurnOrder(void); static void UpdateBattlerPartyOrdersOnSwitch(u32 battler); static bool8 AllAtActionConfirmed(void); static void TryChangeTurnOrder(void); -static void CheckQuickClaw_CustapBerryActivation(void); +static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2); +static void CheckChangingTurnOrderEffects(void); static void FreeResetData_ReturnToOvOrDoEvolutions(void); static void ReturnFromBattleToOverworld(void); static void TryEvolvePokemon(void); @@ -192,7 +193,6 @@ 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; -EWRAM_DATA u16 gRandomTurnNumber = 0; EWRAM_DATA u8 gBattleCommunication[BATTLE_COMMUNICATION_ENTRIES_COUNT] = {0}; EWRAM_DATA u8 gBattleOutcome = 0; EWRAM_DATA struct ProtectStruct gProtectStructs[MAX_BATTLERS_COUNT] = {0}; @@ -3045,8 +3045,6 @@ static void BattleStartClearSetData(void) gBattleStruct->givenExpMons = 0; gBattleStruct->palaceFlags = 0; - gRandomTurnNumber = Random(); - gBattleResults.shinyWildMon = IsMonShiny(&gEnemyParty[0]); gBattleStruct->arenaLostPlayerMons = 0; @@ -3815,8 +3813,6 @@ static void TryDoEventsBeforeFirstTurn(void) gBattleStruct->turnCountersTracker = 0; gMoveResultFlags = 0; - gRandomTurnNumber = Random(); - memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); // erase all totem boosts just to be safe SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers @@ -3913,7 +3909,6 @@ void BattleTurnPassed(void) BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers gBattleMainFunc = HandleTurnActionSelectionState; - gRandomTurnNumber = Random(); if (gBattleTypeFlags & BATTLE_TYPE_PALACE) BattleScriptExecute(BattleScript_PalacePrintFlavorText); @@ -4710,26 +4705,6 @@ u32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov { u32 strikesFirst = 0; - // Battler 1 - // Quick Draw - if (!ignoreChosenMoves && ability1 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler1]) && RandomPercentage(RNG_QUICK_DRAW, 30)) - gProtectStructs[battler1].quickDraw = TRUE; - // Quick Claw and Custap Berry - if (!gProtectStructs[battler1].quickDraw - && ((holdEffectBattler1 == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * GetBattlerHoldEffectParam(battler1)) / 100) - || (holdEffectBattler1 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler1, 4, gBattleMons[battler1].item)))) - gProtectStructs[battler1].usedCustapBerry = TRUE; - - // Battler 2 - // Quick Draw - if (!ignoreChosenMoves && ability2 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler2]) && RandomPercentage(RNG_QUICK_DRAW, 30)) - gProtectStructs[battler2].quickDraw = TRUE; - // Quick Claw and Custap Berry - if (!gProtectStructs[battler2].quickDraw - && ((holdEffectBattler2 == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * GetBattlerHoldEffectParam(battler2)) / 100) - || (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, 4, gBattleMons[battler2].item)))) - gProtectStructs[battler2].usedCustapBerry = TRUE; - if (priority1 == priority2) { // QUICK CLAW / CUSTAP - always first @@ -4900,6 +4875,7 @@ static void SetActionsAndBattlersTurnOrder(void) { u8 battler1 = gBattlerByTurnOrder[i]; u8 battler2 = gBattlerByTurnOrder[j]; + TryChangingTurnOrderEffects(battler1, battler2); if (gActionsByTurnOrder[i] != B_ACTION_USE_ITEM && gActionsByTurnOrder[j] != B_ACTION_USE_ITEM && gActionsByTurnOrder[i] != B_ACTION_SWITCH @@ -4914,7 +4890,7 @@ static void SetActionsAndBattlersTurnOrder(void) } } } - gBattleMainFunc = CheckQuickClaw_CustapBerryActivation; + gBattleMainFunc = CheckChangingTurnOrderEffects; gBattleStruct->quickClawBattlerId = 0; } @@ -4932,6 +4908,7 @@ static void TurnValuesCleanUp(bool8 var0) gProtectStructs[i].banefulBunkered = FALSE; gProtectStructs[i].quash = FALSE; gProtectStructs[i].usedCustapBerry = FALSE; + gProtectStructs[i].quickDraw = FALSE; } else { @@ -5083,7 +5060,35 @@ static void TryChangeTurnOrder(void) } } -static void CheckQuickClaw_CustapBerryActivation(void) +static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2) +{ + u32 ability1 = GetBattlerAbility(battler1); + u32 holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE); + u32 holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE); + u32 ability2 = GetBattlerAbility(battler2); + + // Battler 1 + // Quick Draw + if (ability1 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler1]) && RandomPercentage(RNG_QUICK_DRAW, 30)) + gProtectStructs[battler1].quickDraw = TRUE; + // Quick Claw and Custap Berry + if (!gProtectStructs[battler1].quickDraw + && ((holdEffectBattler1 == HOLD_EFFECT_QUICK_CLAW && RandomPercentage(RNG_QUICK_CLAW, GetBattlerHoldEffectParam(battler1))) + || (holdEffectBattler1 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler1, 4, gBattleMons[battler1].item)))) + gProtectStructs[battler1].usedCustapBerry = TRUE; + + // Battler 2 + // Quick Draw + if (ability2 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler2]) && RandomPercentage(RNG_QUICK_DRAW, 30)) + gProtectStructs[battler2].quickDraw = TRUE; + // Quick Claw and Custap Berry + if (!gProtectStructs[battler2].quickDraw + && ((holdEffectBattler2 == HOLD_EFFECT_QUICK_CLAW && RandomPercentage(RNG_QUICK_CLAW, GetBattlerHoldEffectParam(battler2))) + || (holdEffectBattler2 == HOLD_EFFECT_CUSTAP_BERRY && HasEnoughHpToEatBerry(battler2, 4, gBattleMons[battler2].item)))) + gProtectStructs[battler2].usedCustapBerry = TRUE; +} + +static void CheckChangingTurnOrderEffects(void) { u32 i, battler; @@ -5118,7 +5123,6 @@ static void CheckQuickClaw_CustapBerryActivation(void) else if (gProtectStructs[battler].quickDraw) { gBattlerAbility = battler; - gProtectStructs[battler].quickDraw = FALSE; gLastUsedAbility = gBattleMons[battler].ability; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); RecordAbilityBattle(battler, gLastUsedAbility); diff --git a/test/battle/ability/quick_draw.c b/test/battle/ability/quick_draw.c index 7dd918e5d3..cdf237475b 100644 --- a/test/battle/ability/quick_draw.c +++ b/test/battle/ability/quick_draw.c @@ -15,3 +15,18 @@ SINGLE_BATTLE_TEST("Quick Draw has a 30% chance of going first") MESSAGE("Foe Wobbuffet used Celebrate!"); } } + +SINGLE_BATTLE_TEST("Quick Draw does not activate 70% of the time") +{ + PASSES_RANDOMLY(7, 10, RNG_QUICK_DRAW); + GIVEN { + PLAYER(SPECIES_SLOWBRO_GALARIAN) { Ability(ABILITY_QUICK_DRAW); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_TACKLE); } + } SCENE { + NOT ABILITY_POPUP(player, ABILITY_QUICK_DRAW); + MESSAGE("Foe Wobbuffet used Celebrate!"); + MESSAGE("Slowbro used Tackle!"); + } +} diff --git a/test/battle/ai.c b/test/battle/ai.c index d8f382961a..11fd97219c 100644 --- a/test/battle/ai.c +++ b/test/battle/ai.c @@ -246,7 +246,7 @@ AI_SINGLE_BATTLE_TEST("AI can choose a status move that boosts the attack by two { GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); - PLAYER(SPECIES_WOBBUFFET) { HP(278); }; + PLAYER(SPECIES_WOBBUFFET) { HP(277); }; PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KANGASKHAN) { Moves(MOVE_STRENGTH, MOVE_HORN_ATTACK, MOVE_SWORDS_DANCE); } } WHEN { diff --git a/test/battle/hold_effect/custap_berry.c b/test/battle/hold_effect/custap_berry.c index 8b6c7832d4..039e55fb81 100644 --- a/test/battle/hold_effect/custap_berry.c +++ b/test/battle/hold_effect/custap_berry.c @@ -35,3 +35,17 @@ SINGLE_BATTLE_TEST("Custap Berry allows the holder to move first in its priority ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); } } + +SINGLE_BATTLE_TEST("Custap Berry activates even if the opposing mon switches out") +{ + GIVEN { + PLAYER(SPECIES_REGIROCK) { HP(1); Item(ITEM_CUSTAP_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Regirock can act faster, thanks to Custap Berry!"); + } +} diff --git a/test/battle/hold_effect/quick_claw.c b/test/battle/hold_effect/quick_claw.c new file mode 100644 index 0000000000..ded242b65c --- /dev/null +++ b/test/battle/hold_effect/quick_claw.c @@ -0,0 +1,21 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gItems[ITEM_QUICK_CLAW].holdEffect == HOLD_EFFECT_QUICK_CLAW); +} + +SINGLE_BATTLE_TEST("Quick Claw activates 10% of the time") +{ + PASSES_RANDOMLY(2, 10, RNG_QUICK_CLAW); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(1); Item(ITEM_QUICK_CLAW); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet used Tackle!"); + MESSAGE("Foe Wobbuffet used Celebrate!"); + } +} diff --git a/test/battle/move_effect/ivy_cudgel.c b/test/battle/move_effect/ivy_cudgel.c index e7aab5bc95..819047f34a 100644 --- a/test/battle/move_effect/ivy_cudgel.c +++ b/test/battle/move_effect/ivy_cudgel.c @@ -7,7 +7,7 @@ ASSUMPTIONS ASSUME(gBattleMoves[MOVE_IVY_CUDGEL].argument == HOLD_EFFECT_MASK); } -SINGLE_BATTLE_TEST("Ivy Gudgel changes the move type depending on the mask the user holds") +SINGLE_BATTLE_TEST("Ivy Cudgel changes the move type depending on the mask the user holds") { u16 species; u16 item;