From 7936910f905e95c49bfb7c81f503f3b3be3268fb Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Thu, 14 Sep 2023 13:57:30 +0200 Subject: [PATCH] Bug Bite - Tests and small fix (#3282) Co-authored-by: Eduardo Quezada D'Ottone --- data/battle_scripts_1.s | 14 +-- include/battle_scripts.h | 1 + include/test/battle.h | 2 +- src/battle_util.c | 102 +++++++++++---------- test/battle/move_effect/bug_bite.c | 139 +++++++++++++++++++++++++++++ test/battle/move_effect/fling.c | 10 ++- 6 files changed, 213 insertions(+), 55 deletions(-) create mode 100644 test/battle/move_effect/bug_bite.c diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 405ad3d10..2b3803ab9 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -9633,16 +9633,20 @@ BattleScript_ItemHealHP_RemoveItemEnd2_Anim: removeitem BS_ATTACKER end2 -BattleScript_BerryPPHealEnd2:: - jumpifability BS_ATTACKER, ABILITY_RIPEN, BattleScript_BerryPPHealEnd2_AbilityPopup - goto BattleScript_BerryPPHealEnd2_Anim -BattleScript_BerryPPHealEnd2_AbilityPopup: +BattleScript_BerryPPHealRet:: + jumpifability BS_ATTACKER, ABILITY_RIPEN, BattleScript_BerryPPHeal_AbilityPopup + goto BattleScript_BerryPPHeal_Anim +BattleScript_BerryPPHeal_AbilityPopup: call BattleScript_AbilityPopUp -BattleScript_BerryPPHealEnd2_Anim: +BattleScript_BerryPPHeal_Anim: playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT printstring STRINGID_PKMNSITEMRESTOREDPP waitmessage B_WAIT_TIME_LONG removeitem BS_ATTACKER + return + +BattleScript_BerryPPHealEnd2:: + call BattleScript_BerryPPHealRet end2 BattleScript_ItemHealHP_End2:: diff --git a/include/battle_scripts.h b/include/battle_scripts.h index ecfbb9bec..e08032a7f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -214,6 +214,7 @@ extern const u8 BattleScript_WhiteHerbRet[]; extern const u8 BattleScript_ItemHealHP_RemoveItemRet[]; extern const u8 BattleScript_ItemHealHP_RemoveItemEnd2[]; extern const u8 BattleScript_BerryPPHealEnd2[]; +extern const u8 BattleScript_BerryPPHealRet[]; extern const u8 BattleScript_ItemHealHP_End2[]; extern const u8 BattleScript_ItemHealHP_Ret[]; extern const u8 BattleScript_SelectingNotAllowedMoveChoiceItem[]; diff --git a/include/test/battle.h b/include/test/battle.h index dc40a8a20..57727b84f 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -871,7 +871,7 @@ struct HPEventContext struct StatusEventContext { - u8 status1; + u16 status1; bool8 none:1; bool8 sleep:1; bool8 poison:1; diff --git a/src/battle_util.c b/src/battle_util.c index 32bbce974..a6c7810ba 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6592,10 +6592,11 @@ static u8 TrySetMicleBerry(u32 battlerId, u32 itemId, bool32 end2) static u8 DamagedStatBoostBerryEffect(u8 battlerId, u8 statId, u8 split) { if (IsBattlerAlive(battlerId) - && TARGET_TURN_DAMAGED && CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && (gBattleScripting.overrideBerryRequirements - || (!DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) && GetBattleMoveSplit(gCurrentMove) == split)) + || (!DoesSubstituteBlockMove(gBattlerAttacker, battlerId, gCurrentMove) + && GetBattleMoveSplit(gCurrentMove) == split + && TARGET_TURN_DAMAGED)) ) { BufferStatChange(battlerId, statId, STRINGID_STATROSE); @@ -6639,6 +6640,54 @@ u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 exec return 0; } +static u32 ItemRestorePp(u32 battler, u32 itemId, bool32 execute) +{ + struct Pokemon *party = GetBattlerParty(battler); + struct Pokemon *mon = &party[gBattlerPartyIndexes[battler]]; + u32 i, changedPP = 0; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + u32 move = GetMonData(mon, MON_DATA_MOVE1 + i); + u32 currentPP = GetMonData(mon, MON_DATA_PP1 + i); + u32 ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); + u32 maxPP = CalculatePPWithBonus(move, ppBonuses, i); + if (move && (currentPP == 0 || (gBattleScripting.overrideBerryRequirements && currentPP != maxPP))) + { + u32 ppRestored = GetBattlerItemHoldEffectParam(battler, itemId); + + if (GetBattlerAbility(battler) == ABILITY_RIPEN) + { + ppRestored *= 2; + gBattlerAbility = battler; + } + if (currentPP + ppRestored > maxPP) + changedPP = maxPP; + else + changedPP = currentPP + ppRestored; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); + + if (execute) + { + BattleScriptExecute(BattleScript_BerryPPHealEnd2); + } + else + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryPPHealRet; + } + gActiveBattler = battler; + BtlController_EmitSetMonData(BUFFER_A, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); + MarkBattlerForControllerExec(gActiveBattler); + if (MOVE_IS_PERMANENT(battler, i)) + gBattleMons[battler].pp[i] = changedPP; + return ITEM_PP_CHANGE; + } + } + return 0; +} + static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal) { if (!(gBattleScripting.overrideBerryRequirements && gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP) @@ -6772,6 +6821,9 @@ static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect) case HOLD_EFFECT_RESTORE_PCT_HP: effect = ItemHealHp(battlerId, gLastUsedItem, FALSE, TRUE); break; + case HOLD_EFFECT_RESTORE_PP: + effect = ItemRestorePp(battlerId, gLastUsedItem, FALSE); + break; case HOLD_EFFECT_CONFUSE_SPICY: effect = HealConfuseBerry(battlerId, gLastUsedItem, FLAVOR_SPICY, FALSE); break; @@ -7236,10 +7288,6 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battlerId].status1); MarkBattlerForControllerExec(gActiveBattler); break; - case ITEM_PP_CHANGE: - if (MOVE_IS_PERMANENT(battlerId, i)) - gBattleMons[battlerId].pp[i] = changedPP; - break; } } } @@ -7259,43 +7307,7 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) break; case HOLD_EFFECT_RESTORE_PP: if (!moveTurn) - { - struct Pokemon *party = GetBattlerParty(battlerId); - struct Pokemon *mon = &party[gBattlerPartyIndexes[battlerId]]; - u8 ppBonuses; - u16 move; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - move = GetMonData(mon, MON_DATA_MOVE1 + i); - changedPP = GetMonData(mon, MON_DATA_PP1 + i); - ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); - if (move && changedPP == 0) - break; - } - if (i != MAX_MON_MOVES) - { - u8 maxPP = CalculatePPWithBonus(move, ppBonuses, i); - u8 ppRestored = GetBattlerHoldEffectParam(battlerId); - - if (GetBattlerAbility(battlerId) == ABILITY_RIPEN) - { - ppRestored *= 2; - gBattlerAbility = battlerId; - } - if (changedPP + ppRestored > maxPP) - changedPP = maxPP; - else - changedPP = changedPP + ppRestored; - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); - - BattleScriptExecute(BattleScript_BerryPPHealEnd2); - BtlController_EmitSetMonData(BUFFER_A, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); - MarkBattlerForControllerExec(gActiveBattler); - effect = ITEM_PP_CHANGE; - } - } + effect = ItemRestorePp(battlerId, gLastUsedItem, TRUE); break; case HOLD_EFFECT_RESTORE_STATS: for (i = 0; i < NUM_BATTLE_STATS; i++) @@ -7543,10 +7555,6 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) BtlController_EmitSetMonData(BUFFER_A, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battlerId].status1); MarkBattlerForControllerExec(gActiveBattler); break; - case ITEM_PP_CHANGE: - if (MOVE_IS_PERMANENT(battlerId, i)) - gBattleMons[battlerId].pp[i] = changedPP; - break; } } } diff --git a/test/battle/move_effect/bug_bite.c b/test/battle/move_effect/bug_bite.c new file mode 100644 index 000000000..315d52109 --- /dev/null +++ b/test/battle/move_effect/bug_bite.c @@ -0,0 +1,139 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_BUG_BITE].effect == EFFECT_BUG_BITE); + ASSUME(gBattleMoves[MOVE_BUG_BITE].pp == 20); +} + +// Pretty much copy/paste of the Berry Fling Test. +SINGLE_BATTLE_TEST("Bug Bite eats the target's berry and immediately gains its effect") +{ + u16 item; + u32 status1 = STATUS1_NONE, effect, statId; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_ORAN_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } + PARAMETRIZE { item = ITEM_SITRUS_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } + // PARAMETRIZE { item = ITEM_ENIGMA_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } To do once Enigma Berry's effect is done + PARAMETRIZE { item = ITEM_LEPPA_BERRY; effect = HOLD_EFFECT_RESTORE_PP; } + PARAMETRIZE { item = ITEM_CHESTO_BERRY; effect = HOLD_EFFECT_CURE_SLP; status1 = STATUS1_SLEEP; } + PARAMETRIZE { item = ITEM_CHERI_BERRY; effect = HOLD_EFFECT_CURE_PAR; status1 = STATUS1_PARALYSIS; } + PARAMETRIZE { item = ITEM_PECHA_BERRY; effect = HOLD_EFFECT_CURE_PSN; status1 = STATUS1_POISON; } + PARAMETRIZE { item = ITEM_PECHA_BERRY; effect = HOLD_EFFECT_CURE_PSN; status1 = STATUS1_TOXIC_POISON; } + PARAMETRIZE { item = ITEM_RAWST_BERRY; effect = HOLD_EFFECT_CURE_BRN; status1 = STATUS1_BURN; } + PARAMETRIZE { item = ITEM_ASPEAR_BERRY; effect = HOLD_EFFECT_CURE_FRZ; status1 = STATUS1_FROSTBITE; } + PARAMETRIZE { item = ITEM_APICOT_BERRY; effect = HOLD_EFFECT_SP_DEFENSE_UP; statId = STAT_SPDEF; } + PARAMETRIZE { item = ITEM_MARANGA_BERRY; effect = HOLD_EFFECT_MARANGA_BERRY; statId = STAT_SPDEF; } + PARAMETRIZE { item = ITEM_GANLON_BERRY; effect = HOLD_EFFECT_DEFENSE_UP; statId = STAT_DEF; } + PARAMETRIZE { item = ITEM_KEE_BERRY; effect = HOLD_EFFECT_KEE_BERRY; statId = STAT_DEF; } + PARAMETRIZE { item = ITEM_LIECHI_BERRY; effect = HOLD_EFFECT_ATTACK_UP; statId = STAT_ATK; } + PARAMETRIZE { item = ITEM_PETAYA_BERRY; effect = HOLD_EFFECT_SP_ATTACK_UP; statId = STAT_SPATK; } + PARAMETRIZE { item = ITEM_SALAC_BERRY; effect = HOLD_EFFECT_SPEED_UP; statId = STAT_SPEED; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(399); MaxHP(400); Status1(status1); Moves(MOVE_SLEEP_TALK, MOVE_BUG_BITE); } + OPPONENT(SPECIES_WOBBUFFET) { Item(item); } + } WHEN { + // Chesto Berry can only be applied if the pokemon is asleep and uses Sleep Talk. + if (item == ITEM_CHESTO_BERRY) { + TURN { MOVE(player, MOVE_SLEEP_TALK); } + } else { + TURN { MOVE(player, MOVE_BUG_BITE); } + } + + } SCENE { + if (item == ITEM_CHESTO_BERRY) { + MESSAGE("Wobbuffet used Sleep Talk!"); + } + MESSAGE("Wobbuffet used Bug Bite!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BUG_BITE, player); + HP_BAR(opponent); + if (effect == HOLD_EFFECT_RESTORE_HP) { + if (item == ITEM_ORAN_BERRY) { + MESSAGE("Wobbuffet's Oran Berry restored health!"); + } else if (item == ITEM_SITRUS_BERRY) { + MESSAGE("Wobbuffet's Sitrus Berry restored health!"); + } else { + // MESSAGE("Wobbuffet's Enigma Berry restored health!"); + } + HP_BAR(player); + } + else if (effect == HOLD_EFFECT_RESTORE_PP) { + MESSAGE("Wobbuffet's Leppa Berry restored Bug Bite's PP!"); + } + else if (status1 != STATUS1_NONE) { + if (status1 == STATUS1_BURN) { + MESSAGE("Wobbuffet's Rawst Berry healed its burn!"); + } else if (status1 == STATUS1_SLEEP) { + MESSAGE("Wobbuffet's Chesto Berry woke it from its sleep!"); + } else if (status1 == STATUS1_PARALYSIS) { + MESSAGE("Wobbuffet's Cheri Berry cured paralysis!"); + } else if (status1 == STATUS1_TOXIC_POISON || status1 == STATUS1_POISON) { + MESSAGE("Wobbuffet's Pecha Berry cured poison!"); + } else if (status1 == STATUS1_FROSTBITE) { + MESSAGE("Wobbuffet's Aspear Berry healed its frostbite!"); + } + NOT STATUS_ICON(player, status1); + } + else if (statId != 0) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + if (statId == STAT_ATK) { + MESSAGE("Using Liechi Berry, the Attack of Wobbuffet rose!"); + } else if (statId == STAT_DEF) { + if (item == ITEM_GANLON_BERRY) { + MESSAGE("Using Ganlon Berry, the Defense of Wobbuffet rose!"); + } else { + MESSAGE("Using Kee Berry, the Defense of Wobbuffet rose!"); + } + } else if (statId == STAT_SPDEF) { + if (item == ITEM_APICOT_BERRY) { + MESSAGE("Using Apicot Berry, the Sp. Def of Wobbuffet rose!"); + } else { + MESSAGE("Using Maranga Berry, the Sp. Def of Wobbuffet rose!"); + } + } else if (statId == STAT_SPEED) { + MESSAGE("Using Salac Berry, the Speed of Wobbuffet rose!"); + } else if (statId == STAT_SPATK) { + MESSAGE("Using Petaya Berry, the Sp. Atk of Wobbuffet rose!"); + } + } + } THEN { + if (effect == HOLD_EFFECT_RESTORE_HP) { + EXPECT_EQ(player->hp, player->maxHP); + } else if (effect == HOLD_EFFECT_RESTORE_PP) { + EXPECT_EQ(player->pp[1], 20); + } else if (status1 != STATUS1_NONE) { + EXPECT_EQ(player->status1, STATUS1_NONE); + } + else if (statId != 0) { + EXPECT_EQ(player->statStages[statId], DEFAULT_STAT_STAGE + 1); + } + EXPECT_EQ(opponent->item, ITEM_NONE); // Opponent's Berry was eaten. + } +} + +// To verify in the actual games. +// Bulbapedia - The effect of a Jaboca Berry will activate before the Berry can be stolen. +// Showdown - Jaboca Berry is stolen and eaten and nothing happens. This is how it currently works on expansion. +TO_DO_BATTLE_TEST("Bug Bite interaction with Jaboca Berry."); + +SINGLE_BATTLE_TEST("Tanga Berry activates before Bug Bite") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) {Item(ITEM_TANGA_BERRY); } + } WHEN { + TURN { MOVE(player, MOVE_BUG_BITE); } + } SCENE { + MESSAGE("Wobbuffet used Bug Bite!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + MESSAGE("Foe Wobbuffet ate its Tanga Berry!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BUG_BITE, player); + HP_BAR(opponent); + MESSAGE("Tanga Berry weakened the damage to Foe Wobbuffet!"); + } THEN { + EXPECT_EQ(player->item, ITEM_NONE); + } +} diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c index 8016b2f22..5abb883e1 100644 --- a/test/battle/move_effect/fling.c +++ b/test/battle/move_effect/fling.c @@ -255,6 +255,7 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even PARAMETRIZE { item = ITEM_ORAN_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } PARAMETRIZE { item = ITEM_SITRUS_BERRY; effect = HOLD_EFFECT_RESTORE_HP; } + PARAMETRIZE { item = ITEM_LEPPA_BERRY; effect = HOLD_EFFECT_RESTORE_PP; } PARAMETRIZE { item = ITEM_CHESTO_BERRY; effect = HOLD_EFFECT_CURE_SLP; status1 = STATUS1_SLEEP; } PARAMETRIZE { item = ITEM_CHERI_BERRY; effect = HOLD_EFFECT_CURE_PAR; status1 = STATUS1_PARALYSIS; } PARAMETRIZE { item = ITEM_PECHA_BERRY; effect = HOLD_EFFECT_CURE_PSN; status1 = STATUS1_POISON; } @@ -271,7 +272,7 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(item); } - OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); HP(399); MaxHP(400); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); HP(399); MaxHP(400); MovesWithPP({MOVE_CELEBRATE, 35}); } } WHEN { TURN { MOVE(player, MOVE_FLING); } } SCENE { @@ -286,6 +287,9 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even } HP_BAR(opponent); } + else if (effect == HOLD_EFFECT_RESTORE_PP) { + MESSAGE("Foe Wobbuffet's Leppa Berry restored Celebrate's PP!"); + } else if (status1 != STATUS1_NONE) { if (status1 == STATUS1_BURN) { MESSAGE("Foe Wobbuffet's Rawst Berry healed its burn!"); @@ -325,7 +329,9 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even } THEN { if (effect == HOLD_EFFECT_RESTORE_HP) { EXPECT_EQ(opponent->hp, opponent->maxHP); - } else if (status1 != STATUS1_NONE) { + } else if (effect == HOLD_EFFECT_RESTORE_PP) { + EXPECT_EQ(opponent->pp[0], 39); // Not 40, because Celebrate was used. + } else if (status1 != STATUS1_NONE) { EXPECT_EQ(opponent->status1, STATUS1_NONE); } else if (statId != 0) {