diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index b8fc5b7344..4d78eea5c7 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -3642,7 +3642,7 @@ gBattleAnimMove_MagmaStorm:: call FireSpinEffect restorebg waitbgfadeout - setarg 7, 0xFFFF + setarg 7, 0xFFF waitbgfadein clearmonbg ANIM_DEF_PARTNER blendoff @@ -28313,7 +28313,7 @@ Status_MagmaStorm: call FireSpinEffect restorebg waitbgfadeout - setarg 7, 0xFFFF + setarg 7, 0xFFF waitbgfadein stopsound clearmonbg ANIM_DEF_PARTNER diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 42a19b277e..d99330572c 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -6984,9 +6984,9 @@ BattleScript_BattlerFormChangeWithStringEnd3:: BattleScript_IllusionOff:: spriteignore0hp TRUE - playanimation BS_TARGET, B_ANIM_ILLUSION_OFF + playanimation BS_SCRIPTING, B_ANIM_ILLUSION_OFF waitanimation - updatenick BS_TARGET + updatenick BS_SCRIPTING waitstate spriteignore0hp FALSE printstring STRINGID_ILLUSIONWOREOFF @@ -10010,9 +10010,12 @@ BattleScript_DynamaxEnds:: BattleScript_DynamaxEnds_Ret:: flushtextbox + spriteignore0hp TRUE updatedynamax playanimation BS_SCRIPTING, B_ANIM_FORM_CHANGE waitanimation + spriteignore0hp FALSE + pause B_WAIT_TIME_SHORT return BattleScript_MoveBlockedByDynamax:: diff --git a/include/battle.h b/include/battle.h index c6596b3c84..c2e69682d6 100644 --- a/include/battle.h +++ b/include/battle.h @@ -815,7 +815,6 @@ struct BattleStruct u8 usedMicleBerry; struct MessageStatus slideMessageStatus; u8 trainerSlideSpriteIds[MAX_BATTLERS_COUNT]; - u8 embodyAspectBoost[NUM_BATTLE_SIDES]; u16 savedMove; // backup current move for mid-turn switching, e.g. Red Card u16 opponentMonCanTera:6; u16 opponentMonCanDynamax:6; diff --git a/include/config/dexnav.h b/include/config/dexnav.h index 7b4e3ba285..7ef65ae9b4 100644 --- a/include/config/dexnav.h +++ b/include/config/dexnav.h @@ -19,7 +19,7 @@ #define DEXNAV_CHAIN_MAX 100 // maximum chain value -// hidden pokemon options - an approximation of values to due to lack of available data +// hidden pokemon options - an approximation of values due to lack of available data #define HIDDEN_MON_STEP_COUNT 100 // Look for hidden pokemon every x steps #define HIDDEN_MON_SEARCH_RATE 25 // x% chance of finding hidden pokemon every x steps #define HIDDEN_MON_PROBABILTY 15 // x% chance of finding hidden mon compared to regular encounter data diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 8ba2c72096..dfc023676a 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -1,19 +1,6 @@ #ifndef GUARD_CONSTANTS_BATTLE_AI_H #define GUARD_CONSTANTS_BATTLE_AI_H -// battlers -#define AI_TARGET 0 -#define AI_USER 1 -#define AI_TARGET_PARTNER 2 -#define AI_USER_PARTNER 3 - -// get_type command -#define AI_TYPE1_TARGET 0 -#define AI_TYPE1_USER 1 -#define AI_TYPE2_TARGET 2 -#define AI_TYPE2_USER 3 -#define AI_TYPE_MOVE 4 - // AI Flags. Most run specific functions to update score, new flags are used for internal logic in other scripts // See docs/ai_flags.md for more details. #define AI_FLAG_CHECK_BAD_MOVE (1 << 0) // AI will avoid using moves that are likely to fail or be ineffective in the current situation. diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 5d7c6b0a87..d147816543 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -283,7 +283,7 @@ enum EvolutionMethods { EVO_LEVEL_NATURE_AMPED, // Pokémon reaches the specified level, it has a Hardy, Brave, Adamant, Naughty, Docile, Impish, Lax, Hasty, Jolly, Naive, Rash, Sassy, or Quirky nature. EVO_LEVEL_NATURE_LOW_KEY, // Pokémon reaches the specified level, it has a Lonely, Bold, Relaxed, Timid, Serious, Modest, Mild, Quiet, Bashful, Calm, Gentle, or Careful nature. EVO_CRITICAL_HITS, // Pokémon performs specified number of critical hits in one battle - EVO_SCRIPT_TRIGGER_DMG, // Pokémon has specified HP below max, then player interacts trigger + EVO_SCRIPT_TRIGGER_DMG, // Pokémon has specified HP below max, then player interacts with script calling "tryspecialevo EVO_SCRIPT_TRIGGER_DMG" EVO_DARK_SCROLL, // interacts with Scroll of Darkness EVO_WATER_SCROLL, // interacts with Scroll of Waters EVO_ITEM_NIGHT, // specified item is used on Pokémon, is night diff --git a/src/battle_message.c b/src/battle_message.c index 9f1b85514d..a19924050d 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -698,7 +698,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_AIRBALLOONPOP] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s Air Balloon popped!"), [STRINGID_INCINERATEBURN] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_LAST_ITEM} was burnt up!"), [STRINGID_BUGBITE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} stole and ate its target's {B_LAST_ITEM}!"), - [STRINGID_ILLUSIONWOREOFF] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX}'s illusion wore off!"), + [STRINGID_ILLUSIONWOREOFF] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s illusion wore off!"), [STRINGID_ATTACKERCUREDTARGETSTATUS] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} cured {B_DEF_NAME_WITH_PREFIX2}'s problem!"), [STRINGID_ATTACKERLOSTFIRETYPE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} burned itself out!"), [STRINGID_HEALERCURE] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX}'s {B_LAST_ABILITY} cured {B_SCR_NAME_WITH_PREFIX2}'s problem!"), diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b958e4e6bc..b38ab24741 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10382,6 +10382,7 @@ static void Cmd_various(void) VARIOUS_ARGS(); if (GetIllusionMonPtr(battler) != NULL) { + gBattleScripting.battler = battler; gBattlescriptCurrInstr = cmd->nextInstr; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_IllusionOff; diff --git a/src/battle_util.c b/src/battle_util.c index cc3a6820fb..23050d7298 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4034,8 +4034,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK: case ABILITY_EMBODY_ASPECT_WELLSPRING_MASK: case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK: - if (!gSpecialStatuses[battler].switchInAbilityDone - && !(gBattleStruct->embodyAspectBoost[GetBattlerSide(battler)] & (1u << gBattlerPartyIndexes[battler]))) + if (!gSpecialStatuses[battler].switchInAbilityDone) { u32 stat; @@ -4054,7 +4053,6 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gBattleScripting.savedBattler = gBattlerAttacker; gBattlerAttacker = battler; gSpecialStatuses[battler].switchInAbilityDone = TRUE; - gBattleStruct->embodyAspectBoost[GetBattlerSide(battler)] |= 1u << gBattlerPartyIndexes[battler]; SET_STATCHANGER(stat, 1, FALSE); BattleScriptPushCursorAndCallback(BattleScript_BattlerAbilityStatRaiseOnSwitchIn); effect++; @@ -4739,6 +4737,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_ILLUSION: if (gBattleStruct->illusion[gBattlerTarget].on && !gBattleStruct->illusion[gBattlerTarget].broken && IsBattlerTurnDamaged(gBattlerTarget)) { + gBattleScripting.battler = gBattlerTarget; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_IllusionOff; effect++; @@ -10129,19 +10128,12 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battler) { struct Pokemon *party, *partnerMon; s32 i, id; - u8 side, partyCount; gBattleStruct->illusion[battler].set = 1; if (GetMonAbility(mon) != ABILITY_ILLUSION) return FALSE; party = GetBattlerParty(battler); - side = GetBattlerSide(battler); - partyCount = side == B_SIDE_PLAYER ? gPlayerPartyCount : gEnemyPartyCount; - - // If this pokemon is last in the party, ignore Illusion. - if (&party[partyCount - 1] == mon) - return FALSE; if (IsBattlerAlive(BATTLE_PARTNER(battler))) partnerMon = &party[gBattlerPartyIndexes[BATTLE_PARTNER(battler)]]; @@ -10154,15 +10146,21 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battler) id = i; if (GetMonData(&party[id], MON_DATA_SANITY_HAS_SPECIES) && GetMonData(&party[id], MON_DATA_HP) - && !GetMonData(&party[id], MON_DATA_IS_EGG) - && &party[id] != mon - && &party[id] != partnerMon) + && !GetMonData(&party[id], MON_DATA_IS_EGG)) { - gBattleStruct->illusion[battler].on = 1; - gBattleStruct->illusion[battler].broken = 0; - gBattleStruct->illusion[battler].partyId = id; - gBattleStruct->illusion[battler].mon = &party[id]; - return TRUE; + if (&party[id] != mon && &party[id] != partnerMon) + { + gBattleStruct->illusion[battler].on = 1; + gBattleStruct->illusion[battler].broken = 0; + gBattleStruct->illusion[battler].partyId = id; + gBattleStruct->illusion[battler].mon = &party[id]; + return TRUE; + } + else if (&party[id] == mon) + { + // If this pokemon is last in the party, ignore Illusion. + return FALSE; + } } } diff --git a/src/caps.c b/src/caps.c index 941509c2a4..f8e171c898 100644 --- a/src/caps.c +++ b/src/caps.c @@ -84,17 +84,16 @@ u32 GetSoftLevelCapExpValue(u32 level, u32 expValue) u32 GetCurrentEVCap(void) { - static const u16 sEvCapFlagMap[][2] = { // Define EV caps for each milestone - {FLAG_BADGE01_GET, 30}, - {FLAG_BADGE02_GET, 90}, - {FLAG_BADGE03_GET, 150}, - {FLAG_BADGE04_GET, 210}, - {FLAG_BADGE05_GET, 270}, - {FLAG_BADGE06_GET, 330}, - {FLAG_BADGE07_GET, 390}, - {FLAG_BADGE08_GET, 450}, + {FLAG_BADGE01_GET, MAX_TOTAL_EVS * 1 / 17}, + {FLAG_BADGE02_GET, MAX_TOTAL_EVS * 3 / 17}, + {FLAG_BADGE03_GET, MAX_TOTAL_EVS * 5 / 17}, + {FLAG_BADGE04_GET, MAX_TOTAL_EVS * 7 / 17}, + {FLAG_BADGE05_GET, MAX_TOTAL_EVS * 9 / 17}, + {FLAG_BADGE06_GET, MAX_TOTAL_EVS * 11 / 17}, + {FLAG_BADGE07_GET, MAX_TOTAL_EVS * 13 / 17}, + {FLAG_BADGE08_GET, MAX_TOTAL_EVS * 15 / 17}, {FLAG_IS_CHAMPION, MAX_TOTAL_EVS}, }; diff --git a/src/data/battle_partners.h b/src/data/battle_partners.h index ce451e0a4e..34e30ea083 100644 --- a/src/data/battle_partners.h +++ b/src/data/battle_partners.h @@ -15,7 +15,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 4 .trainerPic = TRAINER_BACK_PIC_BRENDAN, - .encounterMusic_gender = + .encounterMusic_gender = #line 6 TRAINER_ENCOUNTER_MUSIC_MALE, .partySize = 0, @@ -32,7 +32,7 @@ .trainerClass = TRAINER_CLASS_RIVAL, #line 11 .trainerPic = TRAINER_BACK_PIC_STEVEN, - .encounterMusic_gender = + .encounterMusic_gender = #line 13 TRAINER_ENCOUNTER_MUSIC_MALE, .partySize = 3, diff --git a/src/data/graphics/gimmicks.h b/src/data/graphics/gimmicks.h index 483cf2218b..06cff2d48e 100644 --- a/src/data/graphics/gimmicks.h +++ b/src/data/graphics/gimmicks.h @@ -99,7 +99,7 @@ static const u16 sMiscIndicatorPal[] = INCBIN_U16("graphics/battle_interface/mis static const u16 sMegaIndicatorPal[] = INCBIN_U16("graphics/battle_interface/mega_indicator.gbapal"); static const u16 sTeraIndicatorPal[] = INCBIN_U16("graphics/battle_interface/tera_indicator.gbapal"); -static const u8 *sTeraIndicatorDataPtrs[] = +static const u8 *const sTeraIndicatorDataPtrs[] = { sNormalIndicatorGfx, sNormalIndicatorGfx, diff --git a/src/daycare.c b/src/daycare.c index 8d2bf13545..bedaf35dd2 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -336,6 +336,11 @@ static void ApplyDaycareExperience(struct Pokemon *mon) CalculateMonStats(mon); } +static u32 GetExpAtLevelCap(struct Pokemon *mon) +{ + return gExperienceTables[gSpeciesInfo[GetMonData(mon, MON_DATA_SPECIES)].growthRate][GetCurrentLevelCap()]; +} + static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon) { u32 species; @@ -358,6 +363,9 @@ static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon) if (GetMonData(&pokemon, MON_DATA_LEVEL) < GetCurrentLevelCap()) { experience = GetMonData(&pokemon, MON_DATA_EXP) + daycareMon->steps; + u32 maxExp = GetExpAtLevelCap(&pokemon); + if (experience > maxExp) + experience = maxExp; SetMonData(&pokemon, MON_DATA_EXP, &experience); ApplyDaycareExperience(&pokemon); } diff --git a/test/battle/ability/embody_aspect.c b/test/battle/ability/embody_aspect.c index 22b28dea22..fffc8cf423 100644 --- a/test/battle/ability/embody_aspect.c +++ b/test/battle/ability/embody_aspect.c @@ -57,26 +57,3 @@ SINGLE_BATTLE_TEST("Embody Aspect activates when it's no longer effected by Neut MESSAGE("The opposing Ogerpon's Embody Aspect raised its Speed!"); } } - -SINGLE_BATTLE_TEST("Embody Aspect raises Speed only once per battle") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_OGERPON_TEAL_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL_MASK); } - OPPONENT(SPECIES_WYNAUT); - } WHEN { - TURN { SWITCH(opponent, 1); } - TURN { SWITCH(opponent, 0); } - } SCENE { - ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL_MASK); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("The opposing Ogerpon's Embody Aspect raised its Speed!"); - NONE_OF { - ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL_MASK); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("The opposing Ogerpon's Embody Aspect raised its Speed!"); - } - } THEN { - EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); - } -} diff --git a/test/battle/ability/illusion.c b/test/battle/ability/illusion.c index ca3bcb2ee0..8afe89817d 100644 --- a/test/battle/ability/illusion.c +++ b/test/battle/ability/illusion.c @@ -22,3 +22,50 @@ SINGLE_BATTLE_TEST("Illusion can only imitate Normal Form terapagos") TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_TACKLE); } } } + +SINGLE_BATTLE_TEST("Illusion breaks if the target faints") +{ + GIVEN { + PLAYER(SPECIES_ZOROARK) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ILLUSION_OFF, player); + MESSAGE("Zoroark's illusion wore off!"); + } +} + +SINGLE_BATTLE_TEST("Illusion breaks if the attacker faints") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_FINAL_GAMBIT) == EFFECT_FINAL_GAMBIT); + PLAYER(SPECIES_ZOROARK) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FINAL_GAMBIT); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FINAL_GAMBIT, player); + HP_BAR(player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ILLUSION_OFF, player); + MESSAGE("Zoroark's illusion wore off!"); + } +} + +SINGLE_BATTLE_TEST("Illusion cannot imitate if the user is on the last slot") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_ZOROARK); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(player, 1); } + } THEN { + EXPECT_EQ(player->species, SPECIES_ZOROARK); + EXPECT_EQ(gBattleStruct->illusion[0].on, FALSE); // Battler is Zoroark and not Illusioned + } +} diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 914c2818b2..bf97361c68 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -900,6 +900,37 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI considers Focus Sash when det } } +AI_SINGLE_BATTLE_TEST("AI sees popped Air Balloon") +{ + GIVEN { + ASSUME(ItemId_GetHoldEffect(ITEM_AIR_BALLOON) == HOLD_EFFECT_AIR_BALLOON); + ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_TORCHIC) { Item(ITEM_AIR_BALLOON); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_GEODUDE) { Moves(MOVE_TACKLE, MOVE_EARTHQUAKE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } + } +} + +AI_SINGLE_BATTLE_TEST("AI sees popped Air Balloon after Air Balloon mon switches out and back in") +{ + GIVEN { + ASSUME(ItemId_GetHoldEffect(ITEM_AIR_BALLOON) == HOLD_EFFECT_AIR_BALLOON); + ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_TORCHIC) { Item(ITEM_AIR_BALLOON); Moves(MOVE_TACKLE); } + PLAYER(SPECIES_TORCHIC) { Item(ITEM_AIR_BALLOON); Moves(MOVE_TACKLE); } + OPPONENT(SPECIES_GEODUDE) { Moves(MOVE_TACKLE, MOVE_EARTHQUAKE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_TACKLE); } + TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); } + TURN { SWITCH(player, 0); EXPECT_MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_EARTHQUAKE); SEND_OUT(player, 1); } + } +} + AI_SINGLE_BATTLE_TEST("AI won't boost stats against opponent with Unaware") { GIVEN { diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index 006b639d75..a43a44e1a0 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -68,6 +68,29 @@ SINGLE_BATTLE_TEST("Dynamax: Dynamax Level increases HP and max HP multipliers b } } +SINGLE_BATTLE_TEST("Dynamax: Dynamax expires when fainted") +{ + u32 dynamax; + PARAMETRIZE { dynamax = GIMMICK_NONE; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, gimmick: dynamax); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (dynamax) + MESSAGE("Wobbuffet used Max Strike!"); + else + MESSAGE("Wobbuffet used Tackle!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player); + if (dynamax) // Expect to have visual reversion when fainting. + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Wobbuffet fainted!"); + } +} + SINGLE_BATTLE_TEST("Dynamax: Dynamax expires after three turns", u16 hp) { u32 dynamax; diff --git a/test/battle/hold_effect/big_root.c b/test/battle/hold_effect/big_root.c new file mode 100644 index 0000000000..0b3d9b4af6 --- /dev/null +++ b/test/battle/hold_effect/big_root.c @@ -0,0 +1,80 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gItemsInfo[ITEM_BIG_ROOT].holdEffect == HOLD_EFFECT_BIG_ROOT); +} + +SINGLE_BATTLE_TEST("Big Root increases healing from absorbing moves", s16 damage, s16 heal) +{ + u32 item; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BIG_ROOT; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ABSORB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + HP_BAR(player, captureDamage: &results[i].heal); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); // Damage is unaffected + EXPECT_MUL_EQ(results[1].heal, Q_4_12(5234 / 4096), results[0].heal); + } +} + +SINGLE_BATTLE_TEST("Big Root increases the damage restored from Leech Seed, Ingrain and Aqua Ring", s16 heal, s16 damage) +{ + KNOWN_FAILING; + + u32 item; + u32 move; + + PARAMETRIZE { item = ITEM_NONE; move = MOVE_LEECH_SEED; } + PARAMETRIZE { item = ITEM_BIG_ROOT; move = MOVE_LEECH_SEED; } + PARAMETRIZE { item = ITEM_NONE; move = MOVE_INGRAIN; } + PARAMETRIZE { item = ITEM_BIG_ROOT; move = MOVE_INGRAIN; } + PARAMETRIZE { item = ITEM_NONE; move = MOVE_AQUA_RING; } + PARAMETRIZE { item = ITEM_BIG_ROOT; move = MOVE_AQUA_RING; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + if (move == MOVE_LEECH_SEED) + HP_BAR(opponent, captureDamage: &results[i].damage); + HP_BAR(player, captureDamage: &results[i].heal); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); // Damage is unaffected + EXPECT_MUL_EQ(results[1].heal, Q_4_12(5234 / 4096), results[0].heal); + EXPECT_MUL_EQ(results[3].heal, Q_4_12(5234 / 4096), results[2].heal); + EXPECT_MUL_EQ(results[5].heal, Q_4_12(5234 / 4096), results[4].heal); + } +} + +SINGLE_BATTLE_TEST("Big Root increases damage from absorbing Liquid Ooze", s16 damage) +{ + u32 item; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BIG_ROOT; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); } + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + } WHEN { + TURN { MOVE(player, MOVE_ABSORB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(5234 / 4096), results[0].damage); + } +} diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index 7222f34587..520de60106 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -277,11 +277,8 @@ DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is be } } -// Test passes in isolation but fails on CI -/* DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data") { - KNOWN_FAILING; // Test passes in isolation but fails on CI GIVEN { ASSUME(GetMoveEffect(MOVE_ALLY_SWITCH) == EFFECT_ALLY_SWITCH); PLAYER(SPECIES_HOOPA); @@ -295,7 +292,6 @@ DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data") EXPECT(&gPlayerParty[2] == gBattleStruct->illusion[0].mon); } } -*/ // Triple Battles required to test //TO_DO_BATTLE_TEST("Ally Switch fails if the user is in the middle of the field in a Triple Battle"); diff --git a/test/battle/trainer_control.h b/test/battle/trainer_control.h index 62a8045694..fb51e78f70 100644 --- a/test/battle/trainer_control.h +++ b/test/battle/trainer_control.h @@ -97,7 +97,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 36 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 38 TRAINER_ENCOUNTER_MUSIC_MALE, #line 39 @@ -128,7 +128,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 48 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 50 TRAINER_ENCOUNTER_MUSIC_MALE, #line 51 @@ -159,7 +159,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 60 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 62 TRAINER_ENCOUNTER_MUSIC_MALE, #line 63 @@ -190,7 +190,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 72 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 74 TRAINER_ENCOUNTER_MUSIC_MALE, #line 75 @@ -220,7 +220,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 84 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 86 TRAINER_ENCOUNTER_MUSIC_MALE, #line 87 @@ -285,7 +285,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 101 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 103 TRAINER_ENCOUNTER_MUSIC_MALE, #line 104 @@ -380,7 +380,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 126 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 128 TRAINER_ENCOUNTER_MUSIC_MALE, #line 129 @@ -529,7 +529,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 164 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 166 TRAINER_ENCOUNTER_MUSIC_MALE, #line 167 @@ -591,7 +591,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 183 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 185 TRAINER_ENCOUNTER_MUSIC_MALE, #line 186 @@ -651,7 +651,7 @@ .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, #line 201 .trainerPic = TRAINER_PIC_RED, - .encounterMusic_gender = + .encounterMusic_gender = #line 203 TRAINER_ENCOUNTER_MUSIC_MALE, #line 204 @@ -704,4 +704,3 @@ }, }, }, -