diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index 9ffad7d84336..8d0813527561 100644 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -75,7 +75,9 @@ BattleScript_ItemCureStatus:: BattleScript_ItemHealAndCureStatus:: call BattleScript_UseItemMessage itemrestorehp - curestatus BS_ATTACKER + itemcurestatus + printstring STRINGID_ITEMRESTOREDSPECIESHEALTH + waitmessage B_WAIT_TIME_LONG bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE healthbarupdate BS_ATTACKER diff --git a/include/recorded_battle.h b/include/recorded_battle.h index d04e89c3626b..02bbe8fc3f86 100644 --- a/include/recorded_battle.h +++ b/include/recorded_battle.h @@ -45,6 +45,8 @@ enum RECORDED_PARTY_INDEX, RECORDED_BATTLE_PALACE_ACTION, RECORDED_ITEM_ID, + RECORDED_ITEM_TARGET, + RECORDED_ITEM_MOVE, }; extern u32 gRecordedBattleRngSeed; diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index e7fc6fd84ad4..8255abcab09a 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -1441,6 +1441,8 @@ static void RecordedOpponentHandleChooseItem(void) u8 byte1 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler); u8 byte2 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler); gBattleStruct->chosenItem[gActiveBattler] = (byte1 << 8) | byte2; + gBattleStruct->itemPartyIndex[gActiveBattler] = RecordedBattle_GetBattlerAction(RECORDED_ITEM_TARGET, gActiveBattler); + gChosenMovePos = RecordedBattle_GetBattlerAction(RECORDED_ITEM_MOVE, gActiveBattler); BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]); RecordedOpponentBufferExecCompleted(); } diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index 87f575839937..8350e8594e42 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -1465,6 +1465,8 @@ static void RecordedPlayerHandleChooseItem(void) u8 byte1 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler); u8 byte2 = RecordedBattle_GetBattlerAction(RECORDED_ITEM_ID, gActiveBattler); gBattleStruct->chosenItem[gActiveBattler] = (byte1 << 8) | byte2; + gBattleStruct->itemPartyIndex[gActiveBattler] = RecordedBattle_GetBattlerAction(RECORDED_ITEM_TARGET, gActiveBattler); + gChosenMovePos = RecordedBattle_GetBattlerAction(RECORDED_ITEM_MOVE, gActiveBattler); BtlController_EmitOneReturnValue(BUFFER_B, gBattleStruct->chosenItem[gActiveBattler]); RecordedPlayerBufferExecCompleted(); } diff --git a/src/battle_message.c b/src/battle_message.c index 21f7098f81ac..cf42176a1bff 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -260,7 +260,7 @@ static const u8 sText_XFoundOneY[] = _("{B_ATK_NAME_WITH_PREFIX} found\none {B_L static const u8 sText_SoothingAroma[] = _("A soothing aroma wafted\nthrough the area!"); static const u8 sText_ItemsCantBeUsedNow[] = _("Items can't be used now.{PAUSE 64}"); static const u8 sText_ForXCommaYZ[] = _("For {B_SCR_ACTIVE_NAME_WITH_PREFIX},\n{B_LAST_ITEM} {B_BUFF1}"); -static const u8 sText_PkmnUsedXToGetPumped[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used\n{B_LAST_ITEM} to get pumped!"); +static const u8 sText_PkmnUsedXToGetPumped[] = _("{B_ACTIVE_NAME_WITH_PREFIX} used\n{B_LAST_ITEM} to get pumped!"); static const u8 sText_PkmnLostFocus[] = _("{B_ATK_NAME_WITH_PREFIX} lost its\nfocus and couldn't move!"); static const u8 sText_PkmnWasDraggedOut[] = _("{B_DEF_NAME_WITH_PREFIX} was\ndragged out!\p"); static const u8 sText_TheWallShattered[] = _("The wall shattered!"); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 07669635e38e..31ef4cea75b6 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -16563,8 +16563,7 @@ void BS_ItemIncreaseStat(void) { void BS_ItemRestorePP(void) { NATIVE_ARGS(); const u8 *effect = GetItemEffect(gLastUsedItem); - u32 i, pp, maxPP, moveId; - u32 loopEnd = MAX_MON_MOVES; + u32 i, pp, maxPP, moveId, loopEnd; u32 battlerId = MAX_BATTLERS_COUNT; struct Pokemon *mon = (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) ? &gPlayerParty[gBattleStruct->itemPartyIndex[gBattlerAttacker]] : &gEnemyParty[gBattleStruct->itemPartyIndex[gBattlerAttacker]]; @@ -16574,6 +16573,11 @@ void BS_ItemRestorePP(void) { i = gChosenMovePos; loopEnd = gChosenMovePos + 1; } + else + { + i = 0; + loopEnd = MAX_MON_MOVES; + } // Check if the recipient is an active battler. if (gBattleStruct->itemPartyIndex[gBattlerAttacker] == gBattlerPartyIndexes[gBattlerAttacker]) @@ -16583,7 +16587,7 @@ void BS_ItemRestorePP(void) { battlerId = BATTLE_PARTNER(gBattlerAttacker); // Heal PP! - for (i = 0; i < loopEnd; i++) + for (; i < loopEnd; i++) { pp = GetMonData(mon, MON_DATA_PP1 + i, NULL); moveId = GetMonData(mon, MON_DATA_MOVE1 + i, NULL); diff --git a/src/data/items.h b/src/data/items.h index 84436be55b40..2df5c363872b 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -526,7 +526,7 @@ const struct Item gItems[] = .pocket = POCKET_ITEMS, .type = ITEM_USE_PARTY_MENU, .fieldUseFunc = ItemUseOutOfBattle_Medicine, - .battleUsage = EFFECT_ITEM_RESTORE_HP, + .battleUsage = EFFECT_ITEM_CURE_STATUS, .flingPower = 30, }, diff --git a/test/item_effect_cure_status.c b/test/item_effect_cure_status.c new file mode 100644 index 000000000000..1f7c9d7a23f9 --- /dev/null +++ b/test/item_effect_cure_status.c @@ -0,0 +1,339 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Paralyze Heal heals a battler from being paralyzed") +{ + GIVEN { + ASSUME(gItems[ITEM_PARALYZE_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_PARALYSIS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_PARALYZE_HEAL, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Antidote heals a battler from being poisoned") +{ + GIVEN { + ASSUME(gItems[ITEM_ANTIDOTE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_POISON); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ANTIDOTE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Antidote heals a battler from being badly poisoned") +{ + GIVEN { + ASSUME(gItems[ITEM_ANTIDOTE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_TOXIC_POISON); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ANTIDOTE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Awakening heals a battler from being asleep") +{ + GIVEN { + ASSUME(gItems[ITEM_AWAKENING].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_AWAKENING, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Burn Heal heals a battler from being burned") +{ + GIVEN { + ASSUME(gItems[ITEM_BURN_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_BURN_HEAL, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Ice Heal heals a battler from being paralyzed") +{ + GIVEN { + ASSUME(gItems[ITEM_ICE_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ICE_HEAL, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Full Heal heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_FULL_HEAL].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_FULL_HEAL, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Heal Powder heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_HEAL_POWDER].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_HEAL_POWDER, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Pewter Crunchies heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_PEWTER_CRUNCHIES].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_PEWTER_CRUNCHIES, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Lava Cookies heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_LAVA_COOKIE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_LAVA_COOKIE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Rage Candy Bar heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_RAGE_CANDY_BAR].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_RAGE_CANDY_BAR, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Old Gateu heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_OLD_GATEAU].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_OLD_GATEAU, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Casteliacone heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_CASTELIACONE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_CASTELIACONE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Lumiose Galette heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_LUMIOSE_GALETTE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_LUMIOSE_GALETTE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!");; + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Shalour Sable heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_SHALOUR_SABLE].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_SHALOUR_SABLE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Big Malasada heals a battler from any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_BIG_MALASADA].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { Status1(status); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { USE_ITEM(player, ITEM_BIG_MALASADA, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Full Heal, Heal Powder and Local Specialties heal a battler from being confused") +{ + u16 item; + PARAMETRIZE { item = ITEM_FULL_HEAL; } + PARAMETRIZE { item = ITEM_HEAL_POWDER; } + PARAMETRIZE { item = ITEM_PEWTER_CRUNCHIES; } + PARAMETRIZE { item = ITEM_LAVA_COOKIE; } + PARAMETRIZE { item = ITEM_RAGE_CANDY_BAR; } + PARAMETRIZE { item = ITEM_OLD_GATEAU; } + PARAMETRIZE { item = ITEM_CASTELIACONE; } + PARAMETRIZE { item = ITEM_LUMIOSE_GALETTE; } + PARAMETRIZE { item = ITEM_SHALOUR_SABLE; } + PARAMETRIZE { item = ITEM_BIG_MALASADA; } + GIVEN { + ASSUME(gItems[item].battleUsage == EFFECT_ITEM_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GENGAR); + } WHEN { + TURN { MOVE(opponent, MOVE_CONFUSE_RAY); } + TURN { USE_ITEM(player, item, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its status healed!"); + } THEN { + EXPECT_EQ(player->status2, STATUS1_NONE); // because we dont have STATUS2_NONE + } +} diff --git a/test/item_effect_heal_and_cure_status.c b/test/item_effect_heal_and_cure_status.c new file mode 100644 index 000000000000..17ac5be96945 --- /dev/null +++ b/test/item_effect_heal_and_cure_status.c @@ -0,0 +1,43 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures any primary status") +{ + u16 status; + PARAMETRIZE{ status = STATUS1_BURN; } + PARAMETRIZE{ status = STATUS1_FREEZE; } + PARAMETRIZE{ status = STATUS1_PARALYSIS; } + PARAMETRIZE{ status = STATUS1_POISON; } + PARAMETRIZE{ status = STATUS1_TOXIC_POISON; } + PARAMETRIZE{ status = STATUS1_SLEEP; } + GIVEN { + ASSUME(gItems[ITEM_FULL_RESTORE].battleUsage == EFFECT_ITEM_HEAL_AND_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300); Status1(status); }; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN{ USE_ITEM(player, ITEM_FULL_RESTORE, partyIndex: 0); } + } SCENE { + MESSAGE("Wobbuffet had its HP restored!"); + } THEN { + EXPECT_EQ(player->hp, player->maxHP); + EXPECT_EQ(player->status1, STATUS1_NONE); + } +} + +SINGLE_BATTLE_TEST("Full Restore restores a battler's HP and cures confusion") +{ + GIVEN { + ASSUME(gItems[ITEM_FULL_RESTORE].battleUsage == EFFECT_ITEM_HEAL_AND_CURE_STATUS); + PLAYER(SPECIES_WOBBUFFET) { HP(1); MaxHP(300);}; + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN{ MOVE(opponent, MOVE_CONFUSE_RAY); } + TURN{ USE_ITEM(player, ITEM_FULL_RESTORE, partyIndex: 0); } + TURN{ MOVE(player, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet had its HP restored!"); + NONE_OF { MESSAGE("Wobbuffet is confused!"); } + } THEN { + EXPECT_EQ(player->hp, player->maxHP); + } +} diff --git a/test/item_effect_increase_stat.c b/test/item_effect_increase_stat.c index b459e3ac88fe..bbaf20e2fabf 100644 --- a/test/item_effect_increase_stat.c +++ b/test/item_effect_increase_stat.c @@ -1,7 +1,7 @@ #include "global.h" #include "test_battle.h" -SINGLE_BATTLE_TEST("X-Attack sharply raises battler's Attack stat", s16 damage) +SINGLE_BATTLE_TEST("X Attack sharply raises battler's Attack stat", s16 damage) { u16 useItem; PARAMETRIZE { useItem = FALSE; } @@ -23,3 +23,231 @@ SINGLE_BATTLE_TEST("X-Attack sharply raises battler's Attack stat", s16 damage) EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); } } + +SINGLE_BATTLE_TEST("X Defense sharply raises battler's Defense stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_X_DEFENSE].battleUsage == EFFECT_ITEM_INCREASE_STAT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_X_DEFENSE); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Foe Wobbuffet used Tackle!"); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + if (B_X_ITEMS_BUFF >= GEN_7) + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + else + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.66), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("X Sp. Atk sharply raises battler's Sp. Attack stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_X_SP_ATK].battleUsage == EFFECT_ITEM_INCREASE_STAT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_X_SP_ATK); } + TURN { MOVE(player, MOVE_DISARMING_VOICE); } + } SCENE { + MESSAGE("Wobbuffet used DisrmngVoice!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + if (B_X_ITEMS_BUFF >= GEN_7) + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + else + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("X Sp. Def sharply raises battler's Sp. Defense stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_X_SP_DEF].battleUsage == EFFECT_ITEM_INCREASE_STAT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_X_SP_DEF); } + TURN { MOVE(opponent, MOVE_DISARMING_VOICE); } + } SCENE { + MESSAGE("Foe Wobbuffet used DisrmngVoice!"); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + if (B_X_ITEMS_BUFF >= GEN_7) + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + else + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.66), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("X Speed sharply raises battler's Speed stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_X_SPEED].battleUsage == EFFECT_ITEM_INCREASE_STAT); + if (B_X_ITEMS_BUFF >= GEN_7) + { + PLAYER(SPECIES_WOBBUFFET) { Speed(3); }; + OPPONENT(SPECIES_WOBBUFFET) { Speed(4); }; + } + else + { + PLAYER(SPECIES_WOBBUFFET) { Speed(4); }; + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); }; + } + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_X_SPEED); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (useItem) + { + MESSAGE("Wobbuffet used Tackle!"); + MESSAGE("Foe Wobbuffet used Tackle!"); + } else + { + MESSAGE("Foe Wobbuffet used Tackle!"); + MESSAGE("Wobbuffet used Tackle!"); + } + } +} + +SINGLE_BATTLE_TEST("X Accuracy sharply raises battler's Accuracy stat", s16 damage) +{ + + ASSUME(gBattleMoves[MOVE_SING].accuracy == 55); + if (B_X_ITEMS_BUFF >= GEN_7) + PASSES_RANDOMLY(gBattleMoves[MOVE_SING].accuracy * 5 / 3, 100, RNG_ACCURACY); + else + PASSES_RANDOMLY(gBattleMoves[MOVE_SING].accuracy * 4 / 3, 100, RNG_ACCURACY); + GIVEN { + ASSUME(gItems[ITEM_X_ACCURACY].battleUsage == EFFECT_ITEM_INCREASE_STAT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_X_ACCURACY); } + TURN { MOVE(player, MOVE_SING); } + } SCENE { + MESSAGE("Wobbuffet used Sing!"); + MESSAGE("Foe Wobbuffet fell asleep!"); + } +} + +SINGLE_BATTLE_TEST("Max Mushrooms raises battler's Attack stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_MAX_MUSHROOMS].battleUsage == EFFECT_ITEM_INCREASE_ALL_STATS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + MESSAGE("Wobbuffet used Tackle!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Max Mushrooms raises battler's Defense stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_MAX_MUSHROOMS].battleUsage == EFFECT_ITEM_INCREASE_ALL_STATS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Foe Wobbuffet used Tackle!"); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.66), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Max Mushrooms raises battler's Sp. Attack stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_MAX_MUSHROOMS].battleUsage == EFFECT_ITEM_INCREASE_ALL_STATS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } + TURN { MOVE(player, MOVE_DISARMING_VOICE); } + } SCENE { + MESSAGE("Wobbuffet used DisrmngVoice!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Max Mushrooms battler's Sp. Defense stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_MAX_MUSHROOMS].battleUsage == EFFECT_ITEM_INCREASE_ALL_STATS); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } + TURN { MOVE(opponent, MOVE_DISARMING_VOICE); } + } SCENE { + MESSAGE("Foe Wobbuffet used DisrmngVoice!"); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.66), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Max Mushrooms raises battler's Speed stat", s16 damage) +{ + u16 useItem; + PARAMETRIZE { useItem = FALSE; } + PARAMETRIZE { useItem = TRUE; } + GIVEN { + ASSUME(gItems[ITEM_MAX_MUSHROOMS].battleUsage == EFFECT_ITEM_INCREASE_ALL_STATS); + PLAYER(SPECIES_WOBBUFFET) { Speed(4); }; + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); }; + } WHEN { + if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (useItem) + { + MESSAGE("Wobbuffet used Tackle!"); + MESSAGE("Foe Wobbuffet used Tackle!"); + } else + { + MESSAGE("Foe Wobbuffet used Tackle!"); + MESSAGE("Wobbuffet used Tackle!"); + } + } +} diff --git a/test/item_effect_restore_hp.c b/test/item_effect_restore_hp.c index 971ec2400b04..4662e9f25c11 100644 --- a/test/item_effect_restore_hp.c +++ b/test/item_effect_restore_hp.c @@ -1,37 +1,186 @@ #include "global.h" #include "test_battle.h" +#define TEST_HP 1 +#define MAX_HP 400 + SINGLE_BATTLE_TEST("Potion restores a battler's HP by 20") { - s16 damage; GIVEN { ASSUME(gItems[ITEM_POTION].battleUsage == EFFECT_ITEM_RESTORE_HP); - PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); } + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { USE_ITEM(player, ITEM_POTION, partyIndex: 0); } } SCENE { - HP_BAR(player, captureDamage: &damage); - } FINALLY { - EXPECT_EQ(damage, -20); + HP_BAR(player, hp: TEST_HP + 20); + } +} + +SINGLE_BATTLE_TEST("Super Potion restores a battler's HP by 60") +{ + GIVEN { + ASSUME(gItems[ITEM_SUPER_POTION].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_SUPER_POTION, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 60); + } +} + +SINGLE_BATTLE_TEST("Hyper Potion restores a battler's HP by 120") +{ + GIVEN { + ASSUME(gItems[ITEM_HYPER_POTION].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_HYPER_POTION, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 120); + } +} + +SINGLE_BATTLE_TEST("Max Potion restores a battler's HP fully") +{ + GIVEN { + ASSUME(gItems[ITEM_MAX_POTION].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_MAX_POTION, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: MAX_HP); + } +} + +SINGLE_BATTLE_TEST("Fresh Water restores a battler's HP by 30") +{ + GIVEN { + ASSUME(gItems[ITEM_FRESH_WATER].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_FRESH_WATER, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 30); + } +} + +SINGLE_BATTLE_TEST("Soda Pop restores a battler's HP by 50") +{ + GIVEN { + ASSUME(gItems[ITEM_SODA_POP].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_SODA_POP, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 50); + } +} + +SINGLE_BATTLE_TEST("Lemonade restores a battler's HP by 70") +{ + GIVEN { + ASSUME(gItems[ITEM_LEMONADE].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_LEMONADE, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 70); + } +} + +SINGLE_BATTLE_TEST("Moomoo Milk restores a battler's HP by 100") +{ + GIVEN { + ASSUME(gItems[ITEM_MOOMOO_MILK].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_MOOMOO_MILK, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 100); + } +} + +SINGLE_BATTLE_TEST("Energy Powder restores a battler's HP by 60(50)") +{ + GIVEN { + ASSUME(gItems[ITEM_ENERGY_POWDER].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ENERGY_POWDER, partyIndex: 0); } + } SCENE { + if (I_HEALTH_RECOVERY >= GEN_7) + HP_BAR(player, hp: TEST_HP + 60); + else + HP_BAR(player, hp: TEST_HP + 50); + } +} + +SINGLE_BATTLE_TEST("Energy Root restores a battler's HP by 120(200)") +{ + GIVEN { + ASSUME(gItems[ITEM_ENERGY_ROOT].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ENERGY_ROOT, partyIndex: 0); } + } SCENE { + if (I_HEALTH_RECOVERY >= GEN_7) + HP_BAR(player, hp: TEST_HP + 120); + else + HP_BAR(player, hp: TEST_HP + 200); } } -SINGLE_BATTLE_TEST("Sitrus Berry restores a battler's HP") +SINGLE_BATTLE_TEST("Sweet Heart restores a battler's HP by 20") +{ + GIVEN { + ASSUME(gItems[ITEM_SWEET_HEART].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_SWEET_HEART, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 20); + } +} + +SINGLE_BATTLE_TEST("Oran Berry restores a battler's HP by 10") +{ + GIVEN { + ASSUME(gItems[ITEM_ORAN_BERRY].battleUsage == EFFECT_ITEM_RESTORE_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ORAN_BERRY, partyIndex: 0); } + } SCENE { + HP_BAR(player, hp: TEST_HP + 10); + } +} + +SINGLE_BATTLE_TEST("Sitrus Berry restores a battler's HP by 25% of its max HP(30HP flat)") { - s16 damage; GIVEN { ASSUME(gItems[ITEM_SITRUS_BERRY].battleUsage == EFFECT_ITEM_RESTORE_HP); - PLAYER(SPECIES_WOBBUFFET) { HP(50); MaxHP(100); } + PLAYER(SPECIES_WOBBUFFET) { HP(TEST_HP); MaxHP(MAX_HP); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { USE_ITEM(player, ITEM_SITRUS_BERRY, partyIndex: 0); } } SCENE { - HP_BAR(player, captureDamage: &damage); - } FINALLY { if (I_SITRUS_BERRY_HEAL >= GEN_4) - EXPECT_EQ(damage, -25); + HP_BAR(player, hp: TEST_HP + MAX_HP * 0.25); else - EXPECT_EQ(damage, -30); + HP_BAR(player, hp: TEST_HP + 30); } } + +#undef TEST_HP +#undef MAX_HP \ No newline at end of file diff --git a/test/item_effect_restore_pp.c b/test/item_effect_restore_pp.c index 234d4ae4e50b..7194efbbb534 100644 --- a/test/item_effect_restore_pp.c +++ b/test/item_effect_restore_pp.c @@ -1,19 +1,66 @@ #include "global.h" #include "test_battle.h" -SINGLE_BATTLE_TEST("Ether restores the PP of one of a battler's moves") +SINGLE_BATTLE_TEST("Ether restores the PP of one of a battler's moves by 10 ") { GIVEN { ASSUME(gItems[ITEM_ETHER].battleUsage == EFFECT_ITEM_RESTORE_PP); ASSUME(gItems[ITEM_ETHER].type == ITEM_USE_PARTY_MENU_MOVES); - PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_CONFUSION); } + PLAYER(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_TACKLE, 0}, {MOVE_CONFUSION, 20}); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_TACKLE); } - TURN { MOVE(player, MOVE_CONFUSION); } TURN { USE_ITEM(player, ITEM_ETHER, partyIndex: 0, move: MOVE_TACKLE); } - } FINALLY { + } THEN { + EXPECT_EQ(player->pp[0], 10); + EXPECT_EQ(player->pp[1], 20); + } +} + +SINGLE_BATTLE_TEST("Max Ether restores the PP of one of a battler's moves fully") +{ + GIVEN { + ASSUME(gItems[ITEM_MAX_ETHER].battleUsage == EFFECT_ITEM_RESTORE_PP); + ASSUME(gItems[ITEM_MAX_ETHER].type == ITEM_USE_PARTY_MENU_MOVES); + PLAYER(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_TACKLE, 0}, {MOVE_CONFUSION, 20}); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_MAX_ETHER, partyIndex: 0, move: MOVE_TACKLE); } + } THEN { + EXPECT_EQ(player->pp[0], 35); + EXPECT_EQ(player->pp[1], 20); + } +} + +SINGLE_BATTLE_TEST("Elixir restores the PP of all of a battler's moves by 10") +{ + GIVEN { + ASSUME(gItems[ITEM_ELIXIR].battleUsage == EFFECT_ITEM_RESTORE_PP); + ASSUME(gItems[ITEM_ELIXIR].type == ITEM_USE_PARTY_MENU); + PLAYER(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_TACKLE, 0}, {MOVE_CONFUSION, 0}, {MOVE_SCRATCH, 0}, {MOVE_GROWL, 0}); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_ELIXIR, partyIndex: 0); } + } THEN { + EXPECT_EQ(player->pp[0], 10); + EXPECT_EQ(player->pp[1], 10); + EXPECT_EQ(player->pp[2], 10); + EXPECT_EQ(player->pp[3], 10); + } +} + +SINGLE_BATTLE_TEST("Max Elixir restores the PP of all of a battler's moves fully") +{ + GIVEN { + ASSUME(gItems[ITEM_MAX_ELIXIR].battleUsage == EFFECT_ITEM_RESTORE_PP); + ASSUME(gItems[ITEM_MAX_ELIXIR].type == ITEM_USE_PARTY_MENU); + PLAYER(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_TACKLE, 0}, {MOVE_CONFUSION, 0}, {MOVE_SCRATCH, 0}, {MOVE_GROWL, 0}); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_MAX_ELIXIR, partyIndex: 0); } + } THEN { EXPECT_EQ(player->pp[0], 35); - EXPECT_EQ(player->pp[1], 24); + EXPECT_EQ(player->pp[1], 25); + EXPECT_EQ(player->pp[2], 35); + EXPECT_EQ(player->pp[3], 40); } } diff --git a/test/item_effect_revive.c b/test/item_effect_revive.c new file mode 100644 index 000000000000..77423fff1b29 --- /dev/null +++ b/test/item_effect_revive.c @@ -0,0 +1,78 @@ +#include "global.h" +#include "test_battle.h" + +#define MAX_HP 200 + +SINGLE_BATTLE_TEST("Revive restores a fainted battler's HP to half") +{ + GIVEN { + ASSUME(gItems[ITEM_REVIVE].battleUsage == EFFECT_ITEM_REVIVE); + PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(MAX_HP); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { USE_ITEM(player, ITEM_REVIVE, partyIndex: 0); } + TURN { SWITCH(player, 0); } + } SCENE { + MESSAGE("Wynaut had its HP restored!"); + } THEN { + EXPECT_EQ(player->hp, MAX_HP/2); + } +} + +SINGLE_BATTLE_TEST("Max Revive restores a fainted battler's HP fully") +{ + GIVEN { + ASSUME(gItems[ITEM_MAX_REVIVE].battleUsage == EFFECT_ITEM_REVIVE); + PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(MAX_HP); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { USE_ITEM(player, ITEM_MAX_REVIVE, partyIndex: 0); } + TURN { SWITCH(player, 0); } + } SCENE { + MESSAGE("Wynaut had its HP restored!"); + } THEN { + EXPECT_EQ(player->hp, MAX_HP); + } +} + +SINGLE_BATTLE_TEST("Revival Herb restores a fainted battler's HP fully") +{ + GIVEN { + ASSUME(gItems[ITEM_REVIVAL_HERB].battleUsage == EFFECT_ITEM_REVIVE); + PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(MAX_HP); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { USE_ITEM(player, ITEM_REVIVAL_HERB, partyIndex: 0); } + TURN { SWITCH(player, 0); } + } SCENE { + MESSAGE("Wynaut had its HP restored!"); + } THEN { + EXPECT_EQ(player->hp, MAX_HP); + } +} + +SINGLE_BATTLE_TEST("Max Honey restores a fainted battler's HP fully") +{ + GIVEN { + ASSUME(gItems[ITEM_MAX_HONEY].battleUsage == EFFECT_ITEM_REVIVE); + PLAYER(SPECIES_WYNAUT) { HP(1); MaxHP(MAX_HP); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + TURN { USE_ITEM(player, ITEM_MAX_HONEY, partyIndex: 0); } + TURN { SWITCH(player, 0); } + } SCENE { + MESSAGE("Wynaut had its HP restored!"); + } THEN { + EXPECT_EQ(player->hp, MAX_HP); + } +} + +#undef MAX_HP diff --git a/test/item_effect_set_focus_energy.c b/test/item_effect_set_focus_energy.c new file mode 100644 index 000000000000..95648465e68f --- /dev/null +++ b/test/item_effect_set_focus_energy.c @@ -0,0 +1,21 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Dire Hit increases a battler's critical hit chance by 2 stages") +{ + ASSUME(B_CRIT_CHANCE >= GEN_7); + PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); + GIVEN { + ASSUME(gItems[ITEM_DIRE_HIT].battleUsage == EFFECT_ITEM_SET_FOCUS_ENERGY); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_DIRE_HIT, partyIndex: 0); } + TURN { MOVE(player, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player); + MESSAGE("Wobbuffet used Dire Hit to get pumped!"); + MESSAGE("Wobbuffet used Scratch!"); + MESSAGE("A critical hit!"); + } +} diff --git a/test/item_effect_set_mist.c b/test/item_effect_set_mist.c new file mode 100644 index 000000000000..e01775ec4807 --- /dev/null +++ b/test/item_effect_set_mist.c @@ -0,0 +1,19 @@ +#include "global.h" +#include "test_battle.h" + +SINGLE_BATTLE_TEST("Guard Spec. sets Mist effect on the battlers side") +{ + GIVEN { + ASSUME(gItems[ITEM_GUARD_SPEC].battleUsage == EFFECT_ITEM_SET_MIST); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { USE_ITEM(player, ITEM_GUARD_SPEC, partyIndex: 0); } + TURN { MOVE(opponent, MOVE_GROWL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MIST, player); + MESSAGE("Ally became shrouded in MIST!"); + MESSAGE("Foe Wobbuffet used Growl!"); + MESSAGE("Wobbuffet is protected by MIST!"); + } +} diff --git a/test/test_battle.h b/test/test_battle.h index 967bb661dd18..f2d8bab786f9 100644 --- a/test/test_battle.h +++ b/test/test_battle.h @@ -713,6 +713,11 @@ void Randomly(u32 sourceLine, u32 passes, u32 trials, struct RandomlyContext); /* Given */ +struct moveWithPP { + u16 moveId; + u8 pp; +}; + #define GIVEN for (; gBattleTestRunnerState->runGiven; gBattleTestRunnerState->runGiven = FALSE) #define RNGSeed(seed) RNGSeed_(__LINE__, seed) @@ -733,6 +738,7 @@ void Randomly(u32 sourceLine, u32 passes, u32 trials, struct RandomlyContext); #define Speed(speed) Speed_(__LINE__, speed) #define Item(item) Item_(__LINE__, item) #define Moves(move1, ...) Moves_(__LINE__, (const u16 [MAX_MON_MOVES]) { move1, __VA_ARGS__ }) +#define MovesWithPP(movewithpp1, ...) MovesWithPP_(__LINE__, (struct moveWithPP[MAX_MON_MOVES]) {movewithpp1, __VA_ARGS__}) #define Friendship(friendship) Friendship_(__LINE__, friendship) #define Status1(status1) Status1_(__LINE__, status1) @@ -753,6 +759,7 @@ void SpDefense_(u32 sourceLine, u32 spDefense); void Speed_(u32 sourceLine, u32 speed); void Item_(u32 sourceLine, u32 item); void Moves_(u32 sourceLine, const u16 moves[MAX_MON_MOVES]); +void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]); void Friendship_(u32 sourceLine, u32 friendship); void Status1_(u32 sourceLine, u32 status1); diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 365120f1370b..f10291262047 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -1161,6 +1161,21 @@ void Moves_(u32 sourceLine, const u16 moves[MAX_MON_MOVES]) DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; } +void MovesWithPP_(u32 sourceLine, struct moveWithPP moveWithPP[MAX_MON_MOVES]) +{ + s32 i; + INVALID_IF(!DATA.currentMon, "Moves outside of PLAYER/OPPONENT"); + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (moveWithPP[i].moveId == MOVE_NONE) + break; + INVALID_IF(moveWithPP[i].moveId >= MOVES_COUNT, "Illegal move: %d", &moveWithPP[i].moveId); + SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &moveWithPP[i].moveId); + SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &moveWithPP[i].pp); + } + DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; +} + void Friendship_(u32 sourceLine, u32 friendship) { INVALID_IF(!DATA.currentMon, "Friendship outside of PLAYER/OPPONENT"); @@ -1539,10 +1554,8 @@ void UseItem(u32 sourceLine, struct BattlePokemon *battler, struct ItemContext c PushBattlerAction(sourceLine, battlerId, RECORDED_ACTION_TYPE, B_ACTION_USE_ITEM); PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, (ctx.itemId >> 8) & 0xFF); PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_ID, ctx.itemId & 0xFF); - if (ctx.explicitPartyIndex) - gBattleStruct->itemPartyIndex[battlerId] = ctx.partyIndex; - if (ctx.explicitMove) - gBattleStruct->itemPartyIndex[battlerId] = i; + PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_TARGET, ctx.partyIndex); + PushBattlerAction(sourceLine, battlerId, RECORDED_ITEM_MOVE, i); DATA.actionBattlers |= 1 << battlerId; }