From b43da03371d5a5ba9945d524f407d5155849c402 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 9 Oct 2023 17:18:14 +0200 Subject: [PATCH 1/3] initial commit --- data/battle_scripts_1.s | 27 ++++++++++ include/battle.h | 1 + include/battle_scripts.h | 1 + include/constants/battle.h | 3 +- include/constants/battle_move_effects.h | 5 +- include/constants/hold_effects.h | 3 +- src/battle_main.c | 4 ++ src/battle_script_commands.c | 6 ++- src/battle_util.c | 20 +++++++- src/data/battle_moves.h | 8 +-- src/data/items.h | 6 +++ src/data/trainer_parties.h | 19 +++---- src/data/trainers.h | 2 +- test/battle/move_effect/ivy_cudgel.c | 24 +++++++++ test/battle/move_effect/matcha_gotcha.c | 66 +++++++++++++++++++++++++ test/battle/move_effect/syrup_bomb.c | 18 +++++++ 16 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 test/battle/move_effect/ivy_cudgel.c create mode 100644 test/battle/move_effect/matcha_gotcha.c create mode 100644 test/battle/move_effect/syrup_bomb.c diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a1ccf6f2b12a..722339a093d8 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -438,6 +438,32 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectHit @ EFFECT_GIGATON_HAMMER .4byte BattleScript_EffectSaltCure @ EFFECT_SALT_CURE + .4byte BattleScript_EffectMatchaGotcha @ EFFECT_MATCHA_GOTCHA + .4byte BattleScript_EffectSyrupBomb @ EFFECT_SYRUP_BOMB + .4byte BattleScript_EffectHit @ EFFECT_IVY_CUDGEL + +BattleScript_EffectSyrupBomb:: + setmoveeffect MOVE_EFFECT_SYRUP_BOMB + goto BattleScript_EffectHit + +BattleScript_SyrupBombEndTurn:: + setbyte sSTAT_ANIM_PLAYED, FALSE + jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_SyrupBombLowerSpeed + goto BattleScript_SyrupBombEnd2 +BattleScript_SyrupBombLowerSpeed: + playstatchangeanimation BS_ATTACKER, BIT_SPEED, STAT_CHANGE_NEGATIVE + setbyte sSTAT_ANIM_PLAYED, TRUE + setstatchanger STAT_SPEED, 1, TRUE + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_SyrupBombEnd2 + printfromtable gStatUpStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_SyrupBombEnd2:: + end2 + +BattleScript_EffectMatchaGotcha:: + setmoveeffect MOVE_EFFECT_BURN + goto BattleScript_EffectAbsorb + BattleScript_EffectSaltCure: call BattleScript_EffectHit_Ret jumpiffainted BS_TARGET, TRUE, BattleScript_EffectSaltCure_End @@ -3332,6 +3358,7 @@ BattleScript_EffectPoisonHit: BattleScript_EffectAbsorb:: call BattleScript_EffectHit_Ret + seteffectwithchance jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_AbsorbHealBlock setdrainedhp manipulatedamage DMG_BIG_ROOT diff --git a/include/battle.h b/include/battle.h index 9bb3fb75979a..ded81df5b040 100644 --- a/include/battle.h +++ b/include/battle.h @@ -103,6 +103,7 @@ struct DisableStruct u8 toxicSpikesDone:1; u8 stickyWebDone:1; u8 stealthRockDone:1; + u8 syrupBombTimer; }; struct ProtectStruct diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 335aafb589ed..cc0cba4008af 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -478,6 +478,7 @@ extern const u8 BattleScript_UltraBurst[]; extern const u8 BattleScript_SelectingNotAllowedCurrentMove[]; extern const u8 BattleScript_SelectingNotAllowedCurrentMoveInPalace[]; extern const u8 BattleScript_SaltCureExtraDamage[]; +extern const u8 BattleScript_SyrupBombEndTurn[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/constants/battle.h b/include/constants/battle.h index 68fade0ff96a..57929b0a03f1 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -385,8 +385,9 @@ #define MOVE_EFFECT_STEALTH_ROCK 76 #define MOVE_EFFECT_SPIKES 77 #define MOVE_EFFECT_TRIPLE_ARROWS 78 +#define MOVE_EFFECT_SYRUP_BOMB 79 -#define NUM_MOVE_EFFECTS 79 +#define NUM_MOVE_EFFECTS 80 #define MOVE_EFFECT_AFFECTS_USER 0x4000 #define MOVE_EFFECT_CERTAIN 0x8000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 90d14d58fb7e..d5b8db61839e 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -414,7 +414,10 @@ #define EFFECT_MORTAL_SPIN 408 #define EFFECT_GIGATON_HAMMER 409 #define EFFECT_SALT_CURE 410 +#define EFFECT_MATCHA_GOTCHA 411 +#define EFFECT_SYRUP_BOMB 412 +#define EFFECT_IVY_CUDGEL 413 -#define NUM_BATTLE_MOVE_EFFECTS 411 +#define NUM_BATTLE_MOVE_EFFECTS 414 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index 9f877cffa80f..a54f569cd29e 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -160,9 +160,10 @@ #define HOLD_EFFECT_COVERT_CLOAK 179 #define HOLD_EFFECT_LOADED_DICE 180 #define HOLD_EFFECT_BOOSTER_ENERGY 181 // Not implemented. +#define HOLD_EFFECT_MASK 183 // Gen2 hold effect -#define HOLD_EFFECT_BERSERK_GENE 182 +#define HOLD_EFFECT_BERSERK_GENE 184 #define HOLD_EFFECT_CHOICE(holdEffect)((holdEffect == HOLD_EFFECT_CHOICE_BAND || holdEffect == HOLD_EFFECT_CHOICE_SCARF || holdEffect == HOLD_EFFECT_CHOICE_SPECS)) diff --git a/src/battle_main.c b/src/battle_main.c index 6671513253a1..895edf3f30f9 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -5640,6 +5640,10 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) if (holdEffect == gBattleMoves[move].argument) gBattleStruct->dynamicMoveType = ItemId_GetSecondaryId(gBattleMons[battlerAtk].item) | F_DYNAMIC_TYPE_2; } + else if (gBattleMoves[move].effect == EFFECT_IVY_CUDGEL && holdEffect == HOLD_EFFECT_MASK) + { + gBattleStruct->dynamicMoveType = ItemId_GetSecondaryId(gBattleMons[battlerAtk].item) | F_DYNAMIC_TYPE_2; + } else if (gBattleMoves[move].effect == EFFECT_REVELATION_DANCE) { if (gBattleMons[battlerAtk].type1 != TYPE_MYSTERY) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 7952a75b4eda..b0bf171ee040 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3681,8 +3681,12 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattlescriptCurrInstr++; } } + break; - } + case MOVE_EFFECT_SYRUP_BOMB: + gDisableStructs[gBattlerTarget].syrupBombTimer = 3; + gBattlescriptCurrInstr++; + break; } } } diff --git a/src/battle_util.c b/src/battle_util.c index 5e4598329a75..a2df79b6e971 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2541,6 +2541,7 @@ enum ENDTURN_PLASMA_FISTS, ENDTURN_CUD_CHEW, ENDTURN_SALT_CURE, + ENDTURN_SYRUP_BOMB, ENDTURN_BATTLER_COUNT }; @@ -3116,6 +3117,23 @@ u8 DoBattlerEndTurnEffects(void) } gBattleStruct->turnEffectsTracker++; break; + case ENDTURN_SYRUP_BOMB: + { + u16 battlerAbility = GetBattlerAbility(battler); + if (gDisableStructs[battler].syrupBombTimer + && --gDisableStructs[battler].slowStartTimer == 0 + && !(GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_CLEAR_AMULET + || battlerAbility == ABILITY_CLEAR_BODY + || battlerAbility == ABILITY_FULL_METAL_BODY + || battlerAbility == ABILITY_WHITE_SMOKE)) + { + gBattlerTarget = battler; + BattleScriptExecute(BattleScript_SyrupBombEndTurn); + effect++; + } + gBattleStruct->turnEffectsTracker++; + } + break; case ENDTURN_BATTLER_COUNT: // done gBattleStruct->turnEffectsTracker = 0; gBattleStruct->turnEffectsBattlerId++; @@ -11200,7 +11218,7 @@ bool32 IsGen6ExpShareEnabled(void) u8 GetBattlerType(u32 battler, u8 typeIndex) -{ +{ u16 types[3] = {0}; types[0] = gBattleMons[battler].type1; types[1] = gBattleMons[battler].type2; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 41bb61eec3a8..98eafc277eae 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -13829,12 +13829,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_MATCHA_GOTCHA] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_MATCHA_GOTCHA + .effect = EFFECT_MATCHA_GOTCHA, .power = 80, .type = TYPE_GRASS, .accuracy = 90, .pp = 15, - .secondaryEffectChance = 20, //burn + .secondaryEffectChance = 20, .target = MOVE_TARGET_BOTH, .priority = 0, .split = SPLIT_SPECIAL, @@ -13845,7 +13845,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_SYRUP_BOMB] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_SYRUP_BOMB + .effect = EFFECT_SYRUP_BOMB, .power = 60, .type = TYPE_GRASS, .accuracy = 85, @@ -13861,7 +13861,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT_Z] = [MOVE_IVY_CUDGEL] = { - .effect = EFFECT_PLACEHOLDER, // EFFECT_IVY_CUDGEL + .effect = EFFECT_IVY_CUDGEL, .power = 100, .type = TYPE_GRASS, .accuracy = 100, diff --git a/src/data/items.h b/src/data/items.h index 131e08386a74..9f18aaf4518f 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -9700,30 +9700,36 @@ const struct Item gItems[] = { .name = _("CornrstneMask"), .price = 0, + .holdEffect = HOLD_EFFECT_MASK, .description = sCornerstoneMaskDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .secondaryId = TYPE_ROCK, }, [ITEM_WELLSPRING_MASK] = { .name = _("WellsprngMask"), .price = 0, + .holdEffect = HOLD_EFFECT_MASK, .description = sWellspringMaskDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .secondaryId = TYPE_WATER, }, [ITEM_HEARTHFLAME_MASK] = { .name = _("HrthflameMask"), .price = 0, + .holdEffect = HOLD_EFFECT_MASK, .description = sHearthflameMaskDesc, .pocket = POCKET_ITEMS, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .secondaryId = TYPE_FIRE, }, [ITEM_HEALTH_MOCHI] = diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index ed53a181dddb..5227dea674de 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -3207,25 +3207,18 @@ static const struct TrainerMon sParty_Drake[] = { static const struct TrainerMon sParty_Roxanne1[] = { { .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), - .lvl = 12, - .species = SPECIES_GEODUDE, + .lvl = 100, + .species = SPECIES_CELEBI, .heldItem = ITEM_NONE, - .moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_ROCK_THROW, MOVE_ROCK_TOMB} + .moves = {MOVE_SPLASH} }, { .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), - .lvl = 12, - .species = SPECIES_GEODUDE, + .lvl = 100, + .species = SPECIES_CELEBI, .heldItem = ITEM_NONE, - .moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_ROCK_THROW, MOVE_ROCK_TOMB} + .moves = {MOVE_SPLASH} }, - { - .iv = TRAINER_PARTY_IVS(24, 24, 24, 24, 24, 24), - .lvl = 15, - .species = SPECIES_NOSEPASS, - .heldItem = ITEM_ORAN_BERRY, - .moves = {MOVE_BLOCK, MOVE_HARDEN, MOVE_TACKLE, MOVE_ROCK_TOMB} - } }; static const struct TrainerMon sParty_Brawly1[] = { diff --git a/src/data/trainers.h b/src/data/trainers.h index 7a34223b8562..0dab16416a3a 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -3187,7 +3187,7 @@ const struct Trainer gTrainers[] = { .trainerPic = TRAINER_PIC_LEADER_ROXANNE, .trainerName = _("ROXANNE"), .items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE}, - .doubleBattle = FALSE, + .doubleBattle = TRUE, .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .party = TRAINER_PARTY(sParty_Roxanne1), }, diff --git a/test/battle/move_effect/ivy_cudgel.c b/test/battle/move_effect/ivy_cudgel.c new file mode 100644 index 000000000000..ef0611c84f5b --- /dev/null +++ b/test/battle/move_effect/ivy_cudgel.c @@ -0,0 +1,24 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Ivy Gudgel changes the move type depending on the mask the user holds") +{ + u16 species; + u16 item; + + PARAMETRIZE { species = SPECIES_BLASTOISE; item = ITEM_NONE; } + PARAMETRIZE { species = SPECIES_CHARIZARD; item = ITEM_CORNERSTONE_MASK; } + PARAMETRIZE { species = SPECIES_CHARIZARD; item = ITEM_WELLSPRING_MASK; } + PARAMETRIZE { species = SPECIES_VENUSAUR; item = ITEM_HEARTHFLAME_MASK; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(item); } + OPPONENT(species); + } WHEN { + TURN { MOVE(player, MOVE_IVY_CUDGEL); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_IVY_CUDGEL, player); + HP_BAR(opponent); + MESSAGE("It's super effective!"); + } +} diff --git a/test/battle/move_effect/matcha_gotcha.c b/test/battle/move_effect/matcha_gotcha.c new file mode 100644 index 000000000000..9ce194ecdf39 --- /dev/null +++ b/test/battle/move_effect/matcha_gotcha.c @@ -0,0 +1,66 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gBattleMoves[MOVE_MATCHA_GOTCHA].effect == EFFECT_MATCHA_GOTCHA); +} + +SINGLE_BATTLE_TEST("Matcha Gotcha inflicts burn 20% of the time") +{ + PASSES_RANDOMLY(20, 100, RNG_SECONDARY_EFFECT); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MATCHA_GOTCHA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MATCHA_GOTCHA, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponent); + STATUS_ICON(opponent, burn: TRUE); + } +} + +DOUBLE_BATTLE_TEST("Matcha Gatcha can burn both targets") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_MATCHA_GOTCHA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MATCHA_GOTCHA, playerLeft); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponentLeft); + STATUS_ICON(opponentLeft, burn: TRUE); + HP_BAR(opponentRight); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, opponentRight); + STATUS_ICON(opponentRight, burn: TRUE); + } +} + +DOUBLE_BATTLE_TEST("Matcha Gatcha recovers 50% of the damage dealt from both targets") +{ + s16 damageLeft; + s16 damageRight; + s16 healedLeft; + s16 healedRight; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_MATCHA_GOTCHA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MATCHA_GOTCHA, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damageLeft); + HP_BAR(playerLeft, captureDamage: &healedLeft); + HP_BAR(opponentRight, captureDamage: &damageRight); + HP_BAR(playerLeft, captureDamage: &healedRight); + } +} \ No newline at end of file diff --git a/test/battle/move_effect/syrup_bomb.c b/test/battle/move_effect/syrup_bomb.c new file mode 100644 index 000000000000..001094502f28 --- /dev/null +++ b/test/battle/move_effect/syrup_bomb.c @@ -0,0 +1,18 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Syrup Bomb") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SYRUP_BOMB); } + TURN {} + TURN {} + TURN {} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SYRUP_BOMB, player); + HP_BAR(opponent); + } +} From 86b48202832e8de642168d0ae28754213bf41d52 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 10 Oct 2023 23:53:56 +0200 Subject: [PATCH 2/3] done --- data/battle_scripts_1.s | 22 ++++++- include/constants/battle.h | 1 + include/constants/battle_string_ids.h | 3 +- src/battle_message.c | 3 + src/battle_script_commands.c | 15 ++++- src/battle_util.c | 29 ++++++---- test/battle/move_effect/syrup_bomb.c | 82 ++++++++++++++++++++++++++- 7 files changed, 136 insertions(+), 19 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 722339a093d8..a4d1a70d256f 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -444,19 +444,35 @@ gBattleScriptsForMoveEffects:: BattleScript_EffectSyrupBomb:: setmoveeffect MOVE_EFFECT_SYRUP_BOMB - goto BattleScript_EffectHit + call BattleScript_EffectHit_Ret + seteffectwithchance + tryfaintmon BS_TARGET + printstring STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP + waitmessage B_WAIT_TIME_LONG + goto BattleScript_MoveEnd BattleScript_SyrupBombEndTurn:: setbyte sSTAT_ANIM_PLAYED, FALSE - jumpifstat BS_TARGET, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_SyrupBombLowerSpeed + copybyte sBATTLER, gBattlerTarget + jumpifholdeffect BS_TARGET, HOLD_EFFECT_CLEAR_AMULET, BattleScript_SyrupBombItemNoStatLoss + jumpifability BS_TARGET, ABILITY_CLEAR_BODY, BattleScript_SyrupBombAbilityNoStatLoss + jumpifability BS_TARGET, ABILITY_FULL_METAL_BODY, BattleScript_SyrupBombAbilityNoStatLoss + jumpifability BS_TARGET, ABILITY_WHITE_SMOKE, BattleScript_SyrupBombAbilityNoStatLoss + jumpifstat BS_TARGET, CMP_GREATER_THAN, BIT_SPEED, MIN_STAT_STAGE, BattleScript_SyrupBombLowerSpeed goto BattleScript_SyrupBombEnd2 BattleScript_SyrupBombLowerSpeed: playstatchangeanimation BS_ATTACKER, BIT_SPEED, STAT_CHANGE_NEGATIVE setbyte sSTAT_ANIM_PLAYED, TRUE setstatchanger STAT_SPEED, 1, TRUE + statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_SyrupBombEnd2 jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_SyrupBombEnd2 - printfromtable gStatUpStringIds + printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG +BattleScript_SyrupBombItemNoStatLoss:: + call BattleScript_ItemNoStatLoss + goto BattleScript_SyrupBombEnd2 +BattleScript_SyrupBombAbilityNoStatLoss:: + call BattleScript_AbilityNoStatLoss BattleScript_SyrupBombEnd2:: end2 diff --git a/include/constants/battle.h b/include/constants/battle.h index 57929b0a03f1..a96f13164a13 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -189,6 +189,7 @@ #define STATUS4_WATER_SPORT (1 << 3) // Only used if B_SPORT_TURNS < GEN_6 #define STATUS4_INFINITE_CONFUSION (1 << 4) // Used for Berserk Gene #define STATUS4_SALT_CURE (1 << 5) +#define STATUS4_SYRUP_BOMB (1 << 6) #define HITMARKER_WAKE_UP_CLEAR (1 << 4) // Cleared when waking up. Never set or checked. #define HITMARKER_SKIP_DMG_TRACK (1 << 5) diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 86a80c33cb77..c390d568cd44 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -670,8 +670,9 @@ #define STRINGID_CURRENTMOVECANTSELECT 668 #define STRINGID_TARGETISBEINGSALTCURED 669 #define STRINGID_TARGETISHURTBYSALTCURE 670 +#define STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP 671 -#define BATTLESTRINGS_COUNT 671 +#define BATTLESTRINGS_COUNT 672 // 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 9ca01f8cf954..4df37c51a506 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -807,6 +807,8 @@ static const u8 sText_TeamGainedEXP[] = _("The rest of your team gained EXP.\nPo static const u8 sText_CurrentMoveCantSelect[] = _("{B_BUFF1} cannot be used!\p"); static const u8 sText_TargetIsBeingSaltCured[] = _("{B_DEF_NAME_WITH_PREFIX} is being salt cured!"); static const u8 sText_TargetIsHurtBySaltCure[] = _("{B_DEF_NAME_WITH_PREFIX} is hurt by {B_BUFF1}!"); +static const u8 sText_TargetCoveredInStickyCandySyrup[] = _("{B_DEF_NAME_WITH_PREFIX} got covered\nin sticky syrup!"); + const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { @@ -1469,6 +1471,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_ULTRABURSTREACTING - BATTLESTRINGS_TABLE_START] = sText_UltraBurstReacting, [STRINGID_ULTRABURSTCOMPLETED - BATTLESTRINGS_TABLE_START] = sText_UltraBurstCompleted, [STRINGID_TEAMGAINEDEXP - BATTLESTRINGS_TABLE_START] = sText_TeamGainedEXP, + [STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP - BATTLESTRINGS_TABLE_START] = sText_TargetCoveredInStickyCandySyrup, }; const u16 gTrainerUsedItemStringIds[] = diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index b0bf171ee040..a552b103aa91 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -3684,9 +3684,18 @@ void SetMoveEffect(bool32 primary, u32 certain) break; case MOVE_EFFECT_SYRUP_BOMB: - gDisableStructs[gBattlerTarget].syrupBombTimer = 3; - gBattlescriptCurrInstr++; - break; } + if (gStatuses4[gEffectBattler] & STATUS4_SYRUP_BOMB) + { + gBattlescriptCurrInstr++; + } + else + { + gStatuses4[gEffectBattler] |= STATUS4_SYRUP_BOMB; + gDisableStructs[gBattlerTarget].syrupBombTimer = 3; + gBattlescriptCurrInstr++; + } + break; + } } } diff --git a/src/battle_util.c b/src/battle_util.c index a2df79b6e971..b9e1dc661334 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3118,21 +3118,28 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_SYRUP_BOMB: - { - u16 battlerAbility = GetBattlerAbility(battler); - if (gDisableStructs[battler].syrupBombTimer - && --gDisableStructs[battler].slowStartTimer == 0 - && !(GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_CLEAR_AMULET - || battlerAbility == ABILITY_CLEAR_BODY - || battlerAbility == ABILITY_FULL_METAL_BODY - || battlerAbility == ABILITY_WHITE_SMOKE)) + if ((gStatuses4[battler] & STATUS4_SYRUP_BOMB) && (gBattleMons[battler].hp != 0)) { - gBattlerTarget = battler; - BattleScriptExecute(BattleScript_SyrupBombEndTurn); + u16 battlerAbility = GetBattlerAbility(battler); + u32 battlerHoldEffect = GetBattlerHoldEffect(battler, TRUE); + + gDisableStructs[battler].syrupBombTimer--; + if (gDisableStructs[battler].syrupBombTimer == 0) + { + gStatuses4[battler] &= ~STATUS4_SYRUP_BOMB; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SYRUP_BOMB); + gBattlescriptCurrInstr = BattleScript_WrapEnds; + } + else if (gDisableStructs[battler].syrupBombTimer != 0) + { + gBattlerTarget = battler; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_SYRUP_BOMB); + gBattlescriptCurrInstr = BattleScript_SyrupBombEndTurn; + } + BattleScriptExecute(gBattlescriptCurrInstr); effect++; } gBattleStruct->turnEffectsTracker++; - } break; case ENDTURN_BATTLER_COUNT: // done gBattleStruct->turnEffectsTracker = 0; diff --git a/test/battle/move_effect/syrup_bomb.c b/test/battle/move_effect/syrup_bomb.c index 001094502f28..ae689b3629ea 100644 --- a/test/battle/move_effect/syrup_bomb.c +++ b/test/battle/move_effect/syrup_bomb.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Syrup Bomb") +SINGLE_BATTLE_TEST("Syrup Bomb covers the foe in sticky syrup for 3 turns") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -14,5 +14,85 @@ SINGLE_BATTLE_TEST("Syrup Bomb") } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SYRUP_BOMB, player); HP_BAR(opponent); + MESSAGE("Foe Wobbuffet got covered in sticky syrup!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Wobbuffet's Speed fell!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Wobbuffet's Speed fell!"); + MESSAGE("Foe Wobbuffet was freed from Syrup Bomb!"); + } +} + +SINGLE_BATTLE_TEST("Syrup Bomb is prevented by Bulletproof") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CHESPIN) { Ability(ABILITY_BULLETPROOF); } + } WHEN { + TURN { MOVE(player, MOVE_SYRUP_BOMB); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_BULLETPROOF); + MESSAGE("Foe Chespin's Bulletproof blocks Syrup Bomb!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SYRUP_BOMB, player); + NOT HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Clear Body, White Smoke and Full Metal Body prevent Sticky Syrup speed reduction") +{ + u32 species; + u32 ability; + + PARAMETRIZE { species = SPECIES_BELDUM; ability = ABILITY_CLEAR_BODY; } + PARAMETRIZE { species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } + PARAMETRIZE { species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SYRUP_BOMB); } + TURN {} + TURN {} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SYRUP_BOMB, player); + HP_BAR(opponent); + if (species == SPECIES_BELDUM) + { + MESSAGE("Foe Beldum got covered in sticky syrup!"); + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + MESSAGE("Foe Beldum's Clear Body prevents stat loss!"); + } + else if (species == SPECIES_TORKOAL) + { + MESSAGE("Foe Torkoal got covered in sticky syrup!"); + ABILITY_POPUP(opponent, ABILITY_WHITE_SMOKE); + MESSAGE("Foe Torkoal's White Smoke prevents stat loss!"); + } + else if (species == SPECIES_SOLGALEO) + { + MESSAGE("Foe Solgaleo got covered in sticky syrup!"); + ABILITY_POPUP(opponent, ABILITY_FULL_METAL_BODY); + MESSAGE("Foe Solgaleo's Full Metal Body prevents stat loss!"); + } + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + NOT MESSAGE("Foe Beldum's Speed fell!"); + } +} + +SINGLE_BATTLE_TEST("Clear Amulet prevents Sticky Syrup speed reduction") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); } + } WHEN { + TURN { MOVE(player, MOVE_SYRUP_BOMB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SYRUP_BOMB, player); + HP_BAR(opponent); + MESSAGE("Foe Wobbuffet got covered in sticky syrup!"); + MESSAGE("Foe Wobbuffet's Speed was not lowered!"); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + NOT MESSAGE("Foe Wobbuffet's Speed fell!"); } } From 277f41cbffd76a0670a7a1cbfe09e44a5c69e037 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 10 Oct 2023 23:58:04 +0200 Subject: [PATCH 3/3] clean up --- src/data/trainer_parties.h | 19 +++++++++++++------ src/data/trainers.h | 2 +- test/battle/move_effect/matcha_gotcha.c | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/data/trainer_parties.h b/src/data/trainer_parties.h index 5227dea674de..ed53a181dddb 100644 --- a/src/data/trainer_parties.h +++ b/src/data/trainer_parties.h @@ -3207,18 +3207,25 @@ static const struct TrainerMon sParty_Drake[] = { static const struct TrainerMon sParty_Roxanne1[] = { { .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), - .lvl = 100, - .species = SPECIES_CELEBI, + .lvl = 12, + .species = SPECIES_GEODUDE, .heldItem = ITEM_NONE, - .moves = {MOVE_SPLASH} + .moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_ROCK_THROW, MOVE_ROCK_TOMB} }, { .iv = TRAINER_PARTY_IVS(12, 12, 12, 12, 12, 12), - .lvl = 100, - .species = SPECIES_CELEBI, + .lvl = 12, + .species = SPECIES_GEODUDE, .heldItem = ITEM_NONE, - .moves = {MOVE_SPLASH} + .moves = {MOVE_TACKLE, MOVE_DEFENSE_CURL, MOVE_ROCK_THROW, MOVE_ROCK_TOMB} }, + { + .iv = TRAINER_PARTY_IVS(24, 24, 24, 24, 24, 24), + .lvl = 15, + .species = SPECIES_NOSEPASS, + .heldItem = ITEM_ORAN_BERRY, + .moves = {MOVE_BLOCK, MOVE_HARDEN, MOVE_TACKLE, MOVE_ROCK_TOMB} + } }; static const struct TrainerMon sParty_Brawly1[] = { diff --git a/src/data/trainers.h b/src/data/trainers.h index 0dab16416a3a..7a34223b8562 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -3187,7 +3187,7 @@ const struct Trainer gTrainers[] = { .trainerPic = TRAINER_PIC_LEADER_ROXANNE, .trainerName = _("ROXANNE"), .items = {ITEM_POTION, ITEM_POTION, ITEM_NONE, ITEM_NONE}, - .doubleBattle = TRUE, + .doubleBattle = FALSE, .aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY, .party = TRAINER_PARTY(sParty_Roxanne1), }, diff --git a/test/battle/move_effect/matcha_gotcha.c b/test/battle/move_effect/matcha_gotcha.c index 9ce194ecdf39..f1b76b5fcc98 100644 --- a/test/battle/move_effect/matcha_gotcha.c +++ b/test/battle/move_effect/matcha_gotcha.c @@ -63,4 +63,4 @@ DOUBLE_BATTLE_TEST("Matcha Gatcha recovers 50% of the damage dealt from both tar HP_BAR(opponentRight, captureDamage: &damageRight); HP_BAR(playerLeft, captureDamage: &healedRight); } -} \ No newline at end of file +}