From afc4b4cdee2d5596a6262084bd795281f887d7b9 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Tue, 28 Mar 2023 15:07:37 -0400 Subject: [PATCH 1/5] add mirror herb --- data/battle_scripts_1.s | 29 ++++++++++++++++++++++----- include/battle.h | 1 + include/battle_scripts.h | 2 ++ include/constants/battle_string_ids.h | 3 ++- src/battle_message.c | 2 ++ src/battle_script_commands.c | 14 +++++++++++++ src/battle_util.c | 26 ++++++++++++++++++++++++ 7 files changed, 71 insertions(+), 6 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 200a04461..c8bd53735 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -9980,23 +9980,42 @@ BattleScript_PrintPlayerForfeitedLinkBattle:: end2 BattleScript_TotemFlaredToLife:: - playanimation BS_ATTACKER, B_ANIM_TOTEM_FLARE + playanimation BS_ATTACKER, B_ANIM_TOTEM_FLARE, NULL printstring STRINGID_AURAFLAREDTOLIFE waitmessage B_WAIT_TIME_LONG - goto BattleScript_ApplyTotemVarBoost + call BattleScript_ApplyTotemVarBoost + end2 + +@ remove the mirror herb, do totem loop +BattleScript_MirrorHerbCopyStatChangeEnd2:: + call BattleScript_MirrorHerbCopyStatChange + end2 + +BattleScript_MirrorHerbCopyStatChange:: + playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL + printstring STRINGID_MIRRORHERBCOPIED + waitmessage B_WAIT_TIME_LONG + removeitem BS_SCRIPTING + call BattleScript_TotemVar_Ret + copybyte gBattlerAttacker, sSAVED_BATTLER @ restore the original attacker just to be safe + return BattleScript_TotemVar:: + call BattleScript_TotemVar_Ret + end2 + +BattleScript_TotemVar_Ret:: gettotemboost BattleScript_ApplyTotemVarBoost BattleScript_TotemVarEnd: - end2 + return BattleScript_ApplyTotemVarBoost: statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_TotemVarEnd setgraphicalstatchangevalues playanimation BS_SCRIPTING, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 -BattleScript_TotemVarPrintStatMsg: printfromtable gStatUpStringIds waitmessage B_WAIT_TIME_LONG - goto BattleScript_TotemVar @loop until stats bitfield is empty + goto BattleScript_TotemVar_Ret @loop until stats bitfield is empty + BattleScript_AnnounceAirLockCloudNine:: call BattleScript_AbilityPopUp diff --git a/include/battle.h b/include/battle.h index 491273b80..f1818d583 100644 --- a/include/battle.h +++ b/include/battle.h @@ -145,6 +145,7 @@ struct ProtectStruct u16 quash:1; u16 shellTrap:1; u16 silkTrapped:1; + u16 eatMirrorHerb:1; u32 physicalDmg; u32 specialDmg; u8 physicalBattlerId; diff --git a/include/battle_scripts.h b/include/battle_scripts.h index c78fcafe4..248f28119 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -1,6 +1,8 @@ #ifndef GUARD_BATTLE_SCRIPTS_H #define GUARD_BATTLE_SCRIPTS_H +extern const u8 BattleScript_MirrorHerbCopyStatChange[]; +extern const u8 BattleScript_MirrorHerbCopyStatChangeEnd2[]; extern const u8 BattleScript_NotAffected[]; extern const u8 BattleScript_HitFromCritCalc[]; extern const u8 BattleScript_MoveEnd[]; diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index b94176334..4051a3a6d 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -647,8 +647,9 @@ #define STRINGID_STEALTHROCKDISAPPEAREDFROMTEAM 645 #define STRINGID_COULDNTFULLYPROTECT 646 #define STRINGID_STOCKPILEDEFFECTWOREOFF 647 +#define STRINGID_MIRRORHERBCOPIED 648 -#define BATTLESTRINGS_COUNT 648 +#define BATTLESTRINGS_COUNT 649 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, diff --git a/src/battle_message.c b/src/battle_message.c index 2ecfac0c7..9ab40cd4e 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -782,9 +782,11 @@ static const u8 sText_PrepareShellTrap[] = _("{B_ATK_NAME_WITH_PREFIX} set a she static const u8 sText_ShellTrapDidntWork[] = _("{B_ATK_NAME_WITH_PREFIX}'s shell trap didn't work!"); static const u8 sText_CouldntFullyProtect[] = _("{B_DEF_NAME_WITH_PREFIX} couldn't fully protect\nitself and got hurt!"); static const u8 sText_StockpiledEffectWoreOff[] = _("{B_ATK_NAME_WITH_PREFIX}'s stockpiled\neffect wore off!"); +static const u8 sText_MirrorHerbCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s used its {B_LAST_ITEM}\nto mirror its opponent's stat changes!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_MIRRORHERBCOPIED - BATTLESTRINGS_TABLE_START] = sText_MirrorHerbCopied, [STRINGID_STOCKPILEDEFFECTWOREOFF - BATTLESTRINGS_TABLE_START] = sText_StockpiledEffectWoreOff, [STRINGID_COULDNTFULLYPROTECT - BATTLESTRINGS_TABLE_START] = sText_CouldntFullyProtect, [STRINGID_ATTACKERGAINEDSTRENGTHFROMTHEFALLEN - BATTLESTRINGS_TABLE_START] = sText_AttackerGainedStrengthFromTheFallen, diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 28bf60c39..72a332af9 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -12080,6 +12080,20 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr { gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); gProtectStructs[gActiveBattler].statRaised = TRUE; + + // check mirror herb + for (index = 0; index < gBattlersCount; index++) + { + if (GetBattlerSide(index) == GetBattlerSide(gActiveBattler)) + continue; // Only triggers on opposing side + if (GetBattlerHoldEffect(index, TRUE) == HOLD_EFFECT_MIRROR_HERB + && gBattleMons[index].statStages[statId] < MAX_STAT_STAGE) + { + gProtectStructs[index].eatMirrorHerb = 1; + gTotemBoosts[index].stats |= (1 << (statId - 1)); // -1 to start at atk + gTotemBoosts[index].statChanges[statId - 1] = statValue; + } + } } } diff --git a/src/battle_util.c b/src/battle_util.c index dea28b5d8..e92ccfdbd 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6877,6 +6877,26 @@ static bool32 GetMentalHerbEffect(u8 battlerId) return ret; } +static u8 TryConsumeMirrorHerb(u8 battlerId, bool32 execute) +{ + u8 effect = 0; + + if (gProtectStructs[battlerId].eatMirrorHerb) { + gLastUsedItem = gBattleMons[battlerId].item; + gBattleScripting.savedBattler = gBattlerAttacker; + gBattleScripting.battler = gBattlerAttacker = battlerId; + gProtectStructs[battlerId].eatMirrorHerb = 0; + if (execute) { + BattleScriptExecute(BattleScript_MirrorHerbCopyStatChangeEnd2); + } else { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MirrorHerbCopyStatChange; + } + effect = ITEM_STATS_CHANGE; + } + return effect; +} + static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect) { u8 effect = 0; @@ -7058,6 +7078,9 @@ static u8 ItemEffectMoveEnd(u32 battlerId, u16 holdEffect) effect = ITEM_EFFECT_OTHER; } break; + case HOLD_EFFECT_MIRROR_HERB: + effect = TryConsumeMirrorHerb(battlerId, FALSE); + break; } return effect; @@ -7580,6 +7603,9 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) if (!moveTurn) effect = TrySetMicleBerry(battlerId, gLastUsedItem, TRUE); break; + case HOLD_EFFECT_MIRROR_HERB: + effect = TryConsumeMirrorHerb(battlerId, TRUE); + break; } if (effect != 0) From f8bbcdfe73bafea1fa8db869e4fcdfe4c492c948 Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Tue, 28 Mar 2023 15:12:54 -0400 Subject: [PATCH 2/5] minor fix to mirror herb message --- src/battle_message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/battle_message.c b/src/battle_message.c index 9ab40cd4e..140b8b3c4 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -782,7 +782,7 @@ static const u8 sText_PrepareShellTrap[] = _("{B_ATK_NAME_WITH_PREFIX} set a she static const u8 sText_ShellTrapDidntWork[] = _("{B_ATK_NAME_WITH_PREFIX}'s shell trap didn't work!"); static const u8 sText_CouldntFullyProtect[] = _("{B_DEF_NAME_WITH_PREFIX} couldn't fully protect\nitself and got hurt!"); static const u8 sText_StockpiledEffectWoreOff[] = _("{B_ATK_NAME_WITH_PREFIX}'s stockpiled\neffect wore off!"); -static const u8 sText_MirrorHerbCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s used its {B_LAST_ITEM}\nto mirror its opponent's stat changes!"); +static const u8 sText_MirrorHerbCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used its {B_LAST_ITEM}\nto mirror its opponent's stat changes!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { From bdd0195fe01963e81dfe09c5b8e2368a1d12f0be Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 1 May 2023 17:00:37 -0400 Subject: [PATCH 3/5] add mirror herb tests --- test/hold_effect_mirror_herb.c | 51 ++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 test/hold_effect_mirror_herb.c diff --git a/test/hold_effect_mirror_herb.c b/test/hold_effect_mirror_herb.c new file mode 100644 index 000000000..68ea5614b --- /dev/null +++ b/test/hold_effect_mirror_herb.c @@ -0,0 +1,51 @@ +#include "global.h" +#include "test_battle.h" + +ASSUMPTIONS +{ + gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB; +}; + +SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16 damage) +{ + u32 item; + PARAMETRIZE{ item = ITEM_NONE; } + PARAMETRIZE{ item = ITEM_MIRROR_HERB; } + GIVEN { + ASSUME(gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB); + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Item(item); } + } WHEN { + TURN { MOVE(player, MOVE_DRAGON_DANCE); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (item == ITEM_NONE) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + } + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + EXPECT_EQ(player->statStages[STAT_ATK], opponent->statStages[STAT_ATK]); + EXPECT_EQ(player->statStages[STAT_SPEED], opponent->statStages[STAT_SPEED]); + } +} + +SINGLE_BATTLE_TEST("Mirror Herb copies all of of Stuff Cheeks", s16 damage) +{ + GIVEN { + ASSUME(gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB); + ASSUME(gItems[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); + PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_MIRROR_HERB); } + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], opponent->statStages[STAT_ATK]); + EXPECT_EQ(player->statStages[STAT_DEF], opponent->statStages[STAT_DEF]); + } +} From 3652e8261a3fa8575c0f54a194d562f5c11f434c Mon Sep 17 00:00:00 2001 From: ghoulslash <41651341+ghoulslash@users.noreply.github.com> Date: Mon, 1 May 2023 15:09:20 -0600 Subject: [PATCH 4/5] Apply suggestions from code review Co-authored-by: Salem <65783283+CallmeEchoo@users.noreply.github.com> --- test/hold_effect_mirror_herb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/hold_effect_mirror_herb.c b/test/hold_effect_mirror_herb.c index 68ea5614b..b1c3c8132 100644 --- a/test/hold_effect_mirror_herb.c +++ b/test/hold_effect_mirror_herb.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB; + ASSUME(gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB); }; SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16 damage) @@ -12,7 +12,6 @@ SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16 PARAMETRIZE{ item = ITEM_NONE; } PARAMETRIZE{ item = ITEM_MIRROR_HERB; } GIVEN { - ASSUME(gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Item(item); } } WHEN { @@ -38,7 +37,6 @@ SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16 SINGLE_BATTLE_TEST("Mirror Herb copies all of of Stuff Cheeks", s16 damage) { GIVEN { - ASSUME(gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB); ASSUME(gItems[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_MIRROR_HERB); } From 63c2e8a7d98b50921bdc1398dfb41bf04326de4e Mon Sep 17 00:00:00 2001 From: ghoulslash Date: Mon, 1 May 2023 18:02:21 -0400 Subject: [PATCH 5/5] small mirror herb test synta fix --- test/hold_effect_mirror_herb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hold_effect_mirror_herb.c b/test/hold_effect_mirror_herb.c index b1c3c8132..fc0a6de95 100644 --- a/test/hold_effect_mirror_herb.c +++ b/test/hold_effect_mirror_herb.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gItems[ITEM_MIRROR_HERB].holdEffect == HOLD_EFFECT_MIRROR_HERB); -}; +} SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's stat changes in a turn", s16 damage) {