From 40419505f71217cf078eda831de8747dc4a3854f Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Sat, 12 Apr 2025 18:55:31 +0200 Subject: [PATCH 01/11] Add clarification for underlying math in EV caps (#6580) --- src/caps.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) 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}, }; From 563e094ea8c30c9003a6b25be9e6b753e936db9d Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Sat, 12 Apr 2025 18:56:30 +0200 Subject: [PATCH 02/11] Add clarification for EVO_SCRIPT_TRIGGER_DMG (#6579) --- include/constants/pokemon.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index dc6d399acf..7c70129609 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 From d173e42372a87af089f55eabcf3c76ce60c04d6f Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Sun, 13 Apr 2025 11:22:14 +0200 Subject: [PATCH 03/11] Remove redundant AI defines (#6590) --- include/constants/battle_ai.h | 13 ------------- 1 file changed, 13 deletions(-) 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. From 353e4ae6191f6fc741ff83d93af8fab1270423f8 Mon Sep 17 00:00:00 2001 From: PhallenTree <168426989+PhallenTree@users.noreply.github.com> Date: Sun, 13 Apr 2025 16:41:00 +0100 Subject: [PATCH 04/11] Fixes Dynamax reversion animation when fainting (#6597) --- data/battle_scripts_1.s | 3 +++ test/battle/gimmick/dynamax.c | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 20010ff1d8..a394ae30db 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -9994,9 +9994,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/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index 988f19581d..abe5ee2814 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; From f3c76e866b12ce4f65b0e58696c40d3cc7688889 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 13 Apr 2025 19:06:44 +0200 Subject: [PATCH 05/11] Fix potential compile error caused by sTeraIndicatorDataPtrs (#6599) --- src/data/graphics/gimmicks.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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, From 3b53995691bb209a9fb8ac13c04dd22dae26fe05 Mon Sep 17 00:00:00 2001 From: Pawkkie <61265402+Pawkkie@users.noreply.github.com> Date: Sun, 13 Apr 2025 15:04:58 -0400 Subject: [PATCH 06/11] Air Balloon AI tests (#6604) --- test/battle/ai/ai.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 1c57c88732..d11f146fc1 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -860,3 +860,34 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI considers Focus Sash when det TURN { MOVE(player, MOVE_AIR_SLASH); EXPECT_MOVE(opponent, MOVE_FLAMETHROWER); } } } + +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); } + } +} From 075efd36c1bd1aa7ef978fc2cd6424b833249497 Mon Sep 17 00:00:00 2001 From: Bassoonian Date: Sun, 13 Apr 2025 21:16:05 +0200 Subject: [PATCH 07/11] Big Root tests (#6601) --- test/battle/hold_effect/big_root.c | 80 ++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 test/battle/hold_effect/big_root.c 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); + } +} From a4bfbea3cbb232c00883e33b4624bb063f338412 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Mon, 14 Apr 2025 00:17:10 +0200 Subject: [PATCH 08/11] Revert wrongly done Embody Aspect fix (#6607) --- include/battle.h | 1 - src/battle_util.c | 8 +++----- test/battle/ability/embody_aspect.c | 23 ----------------------- 3 files changed, 3 insertions(+), 29 deletions(-) diff --git a/include/battle.h b/include/battle.h index 30e7a13158..3e4907050b 100644 --- a/include/battle.h +++ b/include/battle.h @@ -834,7 +834,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/src/battle_util.c b/src/battle_util.c index b012b177e3..b9b43ab663 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4764,8 +4764,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; case ABILITY_IMPOSTER: { - u32 diagonalBattler = BATTLE_OPPOSITE(battler); - if (IsDoubleBattle()) + u32 diagonalBattler = BATTLE_OPPOSITE(battler); + if (IsDoubleBattle()) diagonalBattler = BATTLE_PARTNER(diagonalBattler); if (IsBattlerAlive(diagonalBattler) && !(gBattleMons[diagonalBattler].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE)) @@ -5303,8 +5303,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; @@ -5323,7 +5322,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++; 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); - } -} From cb98106db070e90d1e644d1362b12d0ba2a12f67 Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sun, 13 Apr 2025 22:49:38 -0300 Subject: [PATCH 09/11] Corrected Dexnav config related comment (#6610) --- include/config/dexnav.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 40c5ad50433145ca7d615eceec0a6228ad745537 Mon Sep 17 00:00:00 2001 From: hedara90 <90hedara@gmail.com> Date: Mon, 14 Apr 2025 17:07:59 +0200 Subject: [PATCH 10/11] Fix Magma Storm getting stuck (#6605) Co-authored-by: Hedara --- data/battle_anim_scripts.s | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 4891c3ef53..09913a9e6f 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 From 3b05d7934fa84e98f5a4d960cd6f3f44a9f4dd05 Mon Sep 17 00:00:00 2001 From: PhallenTree <168426989+PhallenTree@users.noreply.github.com> Date: Mon, 14 Apr 2025 17:17:24 +0100 Subject: [PATCH 11/11] Fixes wrong battler's Illusion wearing off when the Attacker faints and fixes Illusion tests (#6596) --- data/battle_scripts_1.s | 4 +-- src/battle_message.c | 2 +- src/battle_script_commands.c | 1 + src/battle_util.c | 30 ++++++++--------- test/battle/ability/illusion.c | 47 +++++++++++++++++++++++++++ test/battle/move_effect/ally_switch.c | 4 --- 6 files changed, 66 insertions(+), 22 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a394ae30db..e8224b25fa 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -7030,9 +7030,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 diff --git a/src/battle_message.c b/src/battle_message.c index 995f7756c6..7b02496ac7 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -699,7 +699,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_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 3a2690fb55..ee367133dd 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -10178,6 +10178,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 b9b43ab663..1597674c17 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6013,6 +6013,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++; @@ -11269,19 +11270,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)]]; @@ -11294,15 +11288,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/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/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");