diff --git a/INSTALL.md b/INSTALL.md index 25e6adb428..6e52559f67 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -110,9 +110,9 @@ To compile the `modern` target with this toolchain, the subdirectories `lib`, `i ### Building with debug info -To build **pokeemerald.elf** with debug symbols under a modern toolchain: +To build **pokeemerald.elf** with debug symbols and debug-compatible optimization under a modern toolchain: ```bash -make DINFO=1 +make debug ``` # Useful additional tools diff --git a/Makefile b/Makefile index 71d2a48af9..3548aa8cc9 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ CPPFLAGS := $(INCLUDE_CPP_ARGS) -Wno-trigraphs -DMODERN=1 -DTESTING=$(TEST) ARMCC := $(PREFIX)gcc PATH_ARMCC := PATH="$(PATH)" $(ARMCC) CC1 := $(shell $(PATH_ARMCC) --print-prog-name=cc1) -quiet -override CFLAGS += -mthumb -mthumb-interwork -O$(O_LEVEL) -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init +override CFLAGS += -mthumb -mthumb-interwork -O$(O_LEVEL) -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init ifeq ($(ANALYZE),1) override CFLAGS += -fanalyzer endif @@ -346,6 +346,7 @@ endif $(C_BUILDDIR)/librfu_intr.o: CFLAGS := -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast $(C_BUILDDIR)/berry_crush.o: override CFLAGS += -Wno-address-of-packed-member +$(C_BUILDDIR)/agb_flash.o: override CFLAGS += -fno-toplevel-reorder $(C_BUILDDIR)/pokedex_plus_hgss.o: CFLAGS := -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init # Annoyingly we can't turn this on just for src/data/trainers.h $(C_BUILDDIR)/data.o: CFLAGS += -fno-show-column -fno-diagnostics-show-caret diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 118aebab8f..48920a04a2 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1426,11 +1426,6 @@ callnative BS_TryRevertWeatherForm .endm - .macro applysaltcure battler:req - callnative BS_ApplySaltCure - .byte \battler - .endm - .macro trysetoctolock battler:req, failInstr:req callnative BS_TrySetOctolock .byte \battler @@ -2242,11 +2237,6 @@ .4byte \jumpInstr .endm - .macro eeriespellppreduce failInstr:req - various BS_TARGET, VARIOUS_EERIE_SPELL_PP_REDUCE - .4byte \failInstr - .endm - .macro jumpifteamhealthy battler:req, jumpInstr:req various \battler, VARIOUS_JUMP_IF_TEAM_HEALTHY .4byte \jumpInstr diff --git a/asm/macros/event.inc b/asm/macros/event.inc index ede71eb19b..1a01779702 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -1226,6 +1226,13 @@ .4byte \products .endm + @ Used as the endpoint for a Pokemart item list + .macro pokemartlistend + .2byte ITEM_NONE + release + end + .endm + @ Opens the Pokemart system and treats the list of items as decorations. @ Products should be a list of .2byte decoration values preceded by an .align 2 .macro pokemartdecoration products:req diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 9a1e977bf3..93d07e8cd1 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -134,7 +134,11 @@ BattleScript_EffectTidyUp:: pause B_WAIT_TIME_MED ppreduce waitstate + saveattacker + savetarget trytidyup FALSE, BattleScript_EffectTidyUpDoMoveAnimation + restoreattacker + restoretarget goto BattleScript_EffectDragonDanceFromStatUp BattleScript_EffectTidyUpDoMoveAnimation:: @@ -143,6 +147,8 @@ BattleScript_EffectTidyUpDoMoveAnimation:: trytidyup TRUE, NULL printstring STRINGID_TIDYINGUPCOMPLETE waitmessage B_WAIT_TIME_LONG + restoreattacker + restoretarget goto BattleScript_EffectDragonDanceFromStatUp BattleScript_EffectUpperHand:: @@ -398,16 +404,10 @@ BattleScript_EffectHit_Pledge:: tryfaintmon BS_TARGET return -BattleScript_EffectSaltCure:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - jumpiffainted BS_TARGET, TRUE, BattleScript_EffectSaltCure_End - jumpifsubstituteblocks BattleScript_EffectSaltCure_End - applysaltcure BS_TARGET +BattleScript_MoveEffectSaltCure:: printstring STRINGID_TARGETISBEINGSALTCURED waitmessage B_WAIT_TIME_LONG -BattleScript_EffectSaltCure_End: - goto BattleScript_MoveEnd + return BattleScript_SaltCureExtraDamage:: playanimation BS_TARGET, B_ANIM_SALT_CURE_DAMAGE, NULL @@ -951,13 +951,10 @@ BattleScript_HyperspaceFuryRemoveProtect:: waitmessage B_WAIT_TIME_LONG return -BattleScript_EffectPlasmaFists:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - orword gFieldStatuses, STATUS_FIELD_ION_DELUGE +BattleScript_MoveEffectIonDeluge:: printstring STRINGID_IONDELUGEON waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_EffectSparklySwirl:: call BattleScript_EffectHit_Ret @@ -968,41 +965,25 @@ BattleScript_EffectSparklySwirl:: waitstate goto BattleScript_MoveEnd -BattleScript_EffectFreezyFrost:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - normalisebuffs +BattleScript_MoveEffectHaze:: printstring STRINGID_STATCHANGESGONE waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return -BattleScript_EffectSappySeed:: - jumpifstatus3 BS_TARGET, STATUS3_LEECHSEED, BattleScript_EffectHit - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - jumpifhasnohp BS_TARGET, BattleScript_MoveEnd - setseeded - printfromtable gLeechSeedStringIds +BattleScript_MoveEffectLeechSeed:: + printstring STRINGID_PKMNSEEDED waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectBaddyBad:: - jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_REFLECT, BattleScript_EffectHit - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - setreflect +BattleScript_MoveEffectReflect:: printfromtable gReflectLightScreenSafeguardStringIds waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return -BattleScript_EffectGlitzyGlow:: - jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_LIGHTSCREEN, BattleScript_EffectHit - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - setlightscreen +BattleScript_MoveEffectLightScreen:: printfromtable gReflectLightScreenSafeguardStringIds waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_EffectStuffCheeks:: attackcanceler @@ -1220,7 +1201,6 @@ BattleScript_StrengthSapLower: playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 printfromtable gStatDownStringIds waitmessage B_WAIT_TIME_LONG - goto BattleScript_StrengthSapHp @ Drain HP without lowering a stat BattleScript_StrengthSapHp: jumpifability BS_TARGET, ABILITY_LIQUID_OOZE, BattleScript_StrengthSapManipulateDmg @@ -2793,6 +2773,10 @@ BattleScript_EffectHitEscape:: jumpifbattleend BattleScript_HitEscapeEnd jumpifbyte CMP_NOT_EQUAL, gBattleOutcome, 0, BattleScript_HitEscapeEnd jumpifemergencyexited BS_TARGET, BattleScript_HitEscapeEnd + jumpiffainted BS_TARGET, FALSE, BattleScript_HitEscapeSwitch + setbyte sGIVEEXP_STATE, 0 + getexp BS_TARGET +BattleScript_HitEscapeSwitch: goto BattleScript_MoveSwitchPursuit BattleScript_HitEscapeEnd: end @@ -4078,13 +4062,10 @@ BattleScript_EffectDestinyBond:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectEerieSpell:: - call BattleScript_EffectHit_Ret - tryfaintmon BS_TARGET - eeriespellppreduce BattleScript_MoveEnd +BattleScript_MoveEffectEerieSpell:: printstring STRINGID_PKMNREDUCEDPP waitmessage B_WAIT_TIME_LONG - goto BattleScript_MoveEnd + return BattleScript_EffectSpite:: attackcanceler @@ -6339,18 +6320,14 @@ BattleScript_GulpMissileGulping:: datahpupdate BS_ATTACKER tryfaintmon BS_ATTACKER jumpiffainted BS_ATTACKER, TRUE, BattleScript_GulpMissileNoSecondEffectGulping - jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_CLEAR_AMULET, BattleScript_GulpMissileNoSecondEffectGulping - jumpifability BS_ATTACKER, ABILITY_CLEAR_BODY, BattleScript_GulpMissileNoSecondEffectGulping - jumpifability BS_ATTACKER, ABILITY_FULL_METAL_BODY, BattleScript_GulpMissileNoSecondEffectGulping - jumpifability BS_ATTACKER, ABILITY_WHITE_SMOKE, BattleScript_GulpMissileNoSecondEffectGulping - jumpifflowerveilattacker BattleScript_GulpMissileNoSecondEffectGulping BattleScript_GulpMissileNoDmgGulping: handleformchange BS_TARGET, 0 playanimation BS_TARGET, B_ANIM_FORM_CHANGE waitanimation swapattackerwithtarget @ to make gStatDownStringIds down below print the right battler setstatchanger STAT_DEF, 1, TRUE - statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED, BattleScript_GulpMissileGorgingTargetDefenseCantGoLower + statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_GulpMissileGulpingEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_GulpMissileGulpingTargetDefenseCantGoLower setgraphicalstatchangevalues playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 printfromtable gStatDownStringIds @@ -6362,9 +6339,11 @@ BattleScript_GulpMissileNoSecondEffectGulping: playanimation BS_TARGET, B_ANIM_FORM_CHANGE waitanimation return -BattleScript_GulpMissileGorgingTargetDefenseCantGoLower: +BattleScript_GulpMissileGulpingTargetDefenseCantGoLower: printstring STRINGID_STATSWONTDECREASE waitmessage B_WAIT_TIME_LONG +BattleScript_GulpMissileGulpingEnd: + swapattackerwithtarget @ restore the battlers, just in case return BattleScript_SeedSowerActivates:: @@ -6708,7 +6687,7 @@ BattleScript_WishComesTrue:: playanimation BS_TARGET, B_ANIM_WISH_HEAL printstring STRINGID_PKMNWISHCAMETRUE waitmessage B_WAIT_TIME_LONG - orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE healthbarupdate BS_TARGET datahpupdate BS_TARGET printstring STRINGID_PKMNREGAINEDHEALTH @@ -7092,7 +7071,8 @@ BattleScript_CottonDownLoop: jumpiffainted BS_TARGET, TRUE, BattleScript_CottonDownLoopIncrement setstatchanger STAT_SPEED, 1, TRUE jumpifbyteequal gBattlerTarget, gEffectBattler, BattleScript_CottonDownLoopIncrement - statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED, BattleScript_CottonDownTargetSpeedCantGoLower + statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_CottonDownLoopIncrement + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_CottonDownTargetSpeedCantGoLower setgraphicalstatchangevalues playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 printfromtable gStatDownStringIds @@ -9035,7 +9015,7 @@ BattleScript_BerryStatRaiseEnd2:: BattleScript_BerryStatRaiseEnd2_AbilityPopup: call BattleScript_AbilityPopUp BattleScript_BerryStatRaiseEnd2_Anim: - statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_BerryStatRaiseEnd2_End + statbuffchange STAT_CHANGE_ALLOW_PTR | MOVE_EFFECT_AFFECTS_USER, BattleScript_BerryStatRaiseEnd2_End setgraphicalstatchangevalues playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, sB_ANIM_ARG1 setbyte cMULTISTRING_CHOOSER, B_MSG_STAT_ROSE_ITEM diff --git a/data/maps/BattleFrontier_Mart/scripts.inc b/data/maps/BattleFrontier_Mart/scripts.inc index 6afe6a0186..f118476cfe 100644 --- a/data/maps/BattleFrontier_Mart/scripts.inc +++ b/data/maps/BattleFrontier_Mart/scripts.inc @@ -28,9 +28,7 @@ BattleFrontier_Mart_Pokemart: .2byte ITEM_ZINC .2byte ITEM_CARBOS .2byte ITEM_HP_UP - .2byte ITEM_NONE - release - end + pokemartlistend BattleFrontier_Mart_EventScript_OldMan:: msgbox BattleFrontier_Mart_Text_ChaperonGrandson, MSGBOX_NPC diff --git a/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc b/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc index c13e716975..37e691fa3b 100644 --- a/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc +++ b/data/maps/EverGrandeCity_PokemonLeague_1F/scripts.inc @@ -45,9 +45,7 @@ EverGrandeCity_PokemonLeague_1F_Pokemart: .2byte ITEM_FULL_HEAL .2byte ITEM_REVIVE .2byte ITEM_MAX_REPEL - .2byte ITEM_NONE - release - end + pokemartlistend @ The door guards only check for FLAG_BADGE06_GET because Winonas badge is the only one that can be skipped @ Its assumed the player has the remaining badges diff --git a/data/maps/FallarborTown_Mart/scripts.inc b/data/maps/FallarborTown_Mart/scripts.inc index 27c8cc1e70..507a6352d3 100644 --- a/data/maps/FallarborTown_Mart/scripts.inc +++ b/data/maps/FallarborTown_Mart/scripts.inc @@ -25,9 +25,7 @@ FallarborTown_Mart_Pokemart: .2byte ITEM_X_DEFENSE .2byte ITEM_DIRE_HIT .2byte ITEM_GUARD_SPEC - .2byte ITEM_NONE - release - end + pokemartlistend FallarborTown_Mart_EventScript_Woman:: msgbox FallarborTown_Mart_Text_DecidingSkittyEvolve, MSGBOX_NPC diff --git a/data/maps/FortreeCity_DecorationShop/scripts.inc b/data/maps/FortreeCity_DecorationShop/scripts.inc index 4394312876..4da66f27b9 100644 --- a/data/maps/FortreeCity_DecorationShop/scripts.inc +++ b/data/maps/FortreeCity_DecorationShop/scripts.inc @@ -29,9 +29,7 @@ FortreeCity_DecorationShop_PokemartDecor_Desks: .2byte DECOR_BRICK_DESK .2byte DECOR_CAMP_DESK .2byte DECOR_HARD_DESK - .2byte DECOR_NONE - release - end + pokemartlistend FortreeCity_DecorationShop_EventScript_ClerkChairs:: lock @@ -53,9 +51,7 @@ FortreeCity_DecorationShop_PokemartDecor_Chairs: .2byte DECOR_BRICK_CHAIR .2byte DECOR_CAMP_CHAIR .2byte DECOR_HARD_CHAIR - .2byte DECOR_NONE - release - end + pokemartlistend FortreeCity_DecorationShop_Text_MerchandiseSentToPC: .string "Merchandise you buy here is sent to\n" diff --git a/data/maps/FortreeCity_Mart/scripts.inc b/data/maps/FortreeCity_Mart/scripts.inc index c37716bc85..0986e68c0c 100644 --- a/data/maps/FortreeCity_Mart/scripts.inc +++ b/data/maps/FortreeCity_Mart/scripts.inc @@ -23,9 +23,7 @@ FortreeCity_Mart_Pokemart: .2byte ITEM_REVIVE .2byte ITEM_SUPER_REPEL .2byte ITEM_WOOD_MAIL - .2byte ITEM_NONE - release - end + pokemartlistend FortreeCity_Mart_EventScript_Woman:: msgbox FortreeCity_Mart_Text_SuperRepelBetter, MSGBOX_NPC diff --git a/data/maps/LavaridgeTown_HerbShop/scripts.inc b/data/maps/LavaridgeTown_HerbShop/scripts.inc index dbe1b564ac..22e3851e9d 100644 --- a/data/maps/LavaridgeTown_HerbShop/scripts.inc +++ b/data/maps/LavaridgeTown_HerbShop/scripts.inc @@ -17,9 +17,7 @@ LavaridgeTown_HerbShop_Pokemart: .2byte ITEM_ENERGY_ROOT .2byte ITEM_HEAL_POWDER .2byte ITEM_REVIVAL_HERB - .2byte ITEM_NONE - release - end + pokemartlistend LavaridgeTown_HerbShop_EventScript_ExpertM:: msgbox LavaridgeTown_HerbShop_Text_HerbalMedicineWorksButMonWillDislike, MSGBOX_NPC diff --git a/data/maps/LavaridgeTown_Mart/scripts.inc b/data/maps/LavaridgeTown_Mart/scripts.inc index 001df31401..8df5d02dfc 100644 --- a/data/maps/LavaridgeTown_Mart/scripts.inc +++ b/data/maps/LavaridgeTown_Mart/scripts.inc @@ -22,9 +22,7 @@ LavaridgeTown_Mart_Pokemart: .2byte ITEM_REVIVE .2byte ITEM_SUPER_REPEL .2byte ITEM_X_SPEED - .2byte ITEM_NONE - release - end + pokemartlistend LavaridgeTown_Mart_EventScript_ExpertM:: msgbox LavaridgeTown_Mart_Text_XSpeedFirstStrike, MSGBOX_NPC diff --git a/data/maps/LilycoveCity_DepartmentStore_2F/scripts.inc b/data/maps/LilycoveCity_DepartmentStore_2F/scripts.inc index 478f5cfd31..0a502a4f0e 100644 --- a/data/maps/LilycoveCity_DepartmentStore_2F/scripts.inc +++ b/data/maps/LilycoveCity_DepartmentStore_2F/scripts.inc @@ -36,9 +36,7 @@ LilycoveCity_DepartmentStore_2F_Pokemart1: .2byte ITEM_ICE_HEAL .2byte ITEM_AWAKENING .2byte ITEM_FLUFFY_TAIL - .2byte ITEM_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_2F_EventScript_ClerkRight:: lock @@ -62,9 +60,7 @@ LilycoveCity_DepartmentStore_2F_Pokemart2: .2byte ITEM_MAX_REPEL .2byte ITEM_WAVE_MAIL .2byte ITEM_MECH_MAIL - .2byte ITEM_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_2F_Text_LearnToUseItemsProperly: .string "Learn to use items properly.\n" diff --git a/data/maps/LilycoveCity_DepartmentStore_3F/scripts.inc b/data/maps/LilycoveCity_DepartmentStore_3F/scripts.inc index 9189df1f50..8375f9b82a 100644 --- a/data/maps/LilycoveCity_DepartmentStore_3F/scripts.inc +++ b/data/maps/LilycoveCity_DepartmentStore_3F/scripts.inc @@ -19,9 +19,7 @@ LilycoveCity_DepartmentStore_3F_Pokemart_Vitamins: .2byte ITEM_ZINC .2byte ITEM_CARBOS .2byte ITEM_HP_UP - .2byte ITEM_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_3F_EventScript_ClerkRight:: lock @@ -42,9 +40,7 @@ LilycoveCity_DepartmentStore_3F_Pokemart_StatBoosters: .2byte ITEM_DIRE_HIT .2byte ITEM_GUARD_SPEC .2byte ITEM_X_ACCURACY - .2byte ITEM_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_3F_EventScript_TriathleteM:: msgbox LilycoveCity_DepartmentStore_3F_Text_ItemsBestForTougheningPokemon, MSGBOX_NPC diff --git a/data/maps/LilycoveCity_DepartmentStore_4F/scripts.inc b/data/maps/LilycoveCity_DepartmentStore_4F/scripts.inc index 760abc600d..0d6403b206 100644 --- a/data/maps/LilycoveCity_DepartmentStore_4F/scripts.inc +++ b/data/maps/LilycoveCity_DepartmentStore_4F/scripts.inc @@ -29,9 +29,7 @@ LilycoveCity_DepartmentStore_4F_Pokemart_AttackTMs: .2byte ITEM_TM_THUNDER .2byte ITEM_TM_BLIZZARD .2byte ITEM_TM_HYPER_BEAM - .2byte ITEM_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_4F_EventScript_ClerkRight:: lock @@ -49,9 +47,7 @@ LilycoveCity_DepartmentStore_4F_Pokemart_DefenseTMs: .2byte ITEM_TM_SAFEGUARD .2byte ITEM_TM_REFLECT .2byte ITEM_TM_LIGHT_SCREEN - .2byte ITEM_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_4F_Text_AttackOrDefenseTM: .string "Hmm…\p" diff --git a/data/maps/LilycoveCity_DepartmentStore_5F/scripts.inc b/data/maps/LilycoveCity_DepartmentStore_5F/scripts.inc index a9683d13c9..f75a48e708 100644 --- a/data/maps/LilycoveCity_DepartmentStore_5F/scripts.inc +++ b/data/maps/LilycoveCity_DepartmentStore_5F/scripts.inc @@ -41,9 +41,7 @@ LilycoveCity_DepartmentStore_5F_Pokemart_Dolls: .2byte DECOR_SKITTY_DOLL .2byte DECOR_SWABLU_DOLL .2byte DECOR_GULPIN_DOLL - .2byte DECOR_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_5F_EventScript_ClerkMidLeft:: lock @@ -66,9 +64,7 @@ LilycoveCity_DepartmentStore_5F_Pokemart_Cushions: .2byte DECOR_GRASS_CUSHION .2byte DECOR_FIRE_CUSHION .2byte DECOR_WATER_CUSHION - .2byte DECOR_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_5F_EventScript_ClerkMidRight:: lock @@ -91,9 +87,7 @@ LilycoveCity_DepartmentStore_5F_Pokemart_Posters: .2byte DECOR_LONG_POSTER .2byte DECOR_SEA_POSTER .2byte DECOR_SKY_POSTER - .2byte DECOR_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_5F_EventScript_ClerkFarRight:: lock @@ -117,9 +111,7 @@ LilycoveCity_DepartmentStore_5F_Pokemart_Mats: .2byte DECOR_GLITTER_MAT .2byte DECOR_JUMP_MAT .2byte DECOR_SPIN_MAT - .2byte DECOR_NONE - release - end + pokemartlistend LilycoveCity_DepartmentStore_5F_EventScript_PokefanF:: msgbox LilycoveCity_DepartmentStore_5F_Text_PlaceFullOfCuteDolls, MSGBOX_NPC diff --git a/data/maps/MauvilleCity_Mart/scripts.inc b/data/maps/MauvilleCity_Mart/scripts.inc index 751835caab..f7028c20f8 100644 --- a/data/maps/MauvilleCity_Mart/scripts.inc +++ b/data/maps/MauvilleCity_Mart/scripts.inc @@ -25,9 +25,7 @@ MauvilleCity_Mart_Pokemart: .2byte ITEM_GUARD_SPEC .2byte ITEM_DIRE_HIT .2byte ITEM_X_ACCURACY - .2byte ITEM_NONE - release - end + pokemartlistend MauvilleCity_Mart_EventScript_ExpertM:: msgbox MauvilleCity_Mart_Text_ItemsToTemporarilyElevateStats, MSGBOX_NPC diff --git a/data/maps/MossdeepCity_Mart/scripts.inc b/data/maps/MossdeepCity_Mart/scripts.inc index 6618b6a6a3..cfe97d5e1f 100644 --- a/data/maps/MossdeepCity_Mart/scripts.inc +++ b/data/maps/MossdeepCity_Mart/scripts.inc @@ -22,9 +22,7 @@ MossdeepCity_Mart_Pokemart: .2byte ITEM_MAX_REPEL .2byte ITEM_X_ATTACK .2byte ITEM_X_DEFENSE - .2byte ITEM_NONE - release - end + pokemartlistend MossdeepCity_Mart_EventScript_Woman:: msgbox MossdeepCity_Mart_Text_ReviveIsFantastic, MSGBOX_NPC diff --git a/data/maps/OldaleTown_Mart/scripts.inc b/data/maps/OldaleTown_Mart/scripts.inc index 0b3c7b1a34..1e1aacbb10 100644 --- a/data/maps/OldaleTown_Mart/scripts.inc +++ b/data/maps/OldaleTown_Mart/scripts.inc @@ -18,9 +18,7 @@ OldaleTown_Mart_Pokemart_Basic: .2byte ITEM_ANTIDOTE .2byte ITEM_PARALYZE_HEAL .2byte ITEM_AWAKENING - .2byte ITEM_NONE - release - end + pokemartlistend OldaleTown_Mart_ExpandedItems:: pokemart OldaleTown_Mart_Pokemart_Expanded @@ -35,9 +33,7 @@ OldaleTown_Mart_Pokemart_Expanded: .2byte ITEM_ANTIDOTE .2byte ITEM_PARALYZE_HEAL .2byte ITEM_AWAKENING - .2byte ITEM_NONE - release - end + pokemartlistend OldaleTown_Mart_EventScript_Woman:: lock diff --git a/data/maps/PetalburgCity_Mart/scripts.inc b/data/maps/PetalburgCity_Mart/scripts.inc index acae50929d..54ca3aa6d8 100644 --- a/data/maps/PetalburgCity_Mart/scripts.inc +++ b/data/maps/PetalburgCity_Mart/scripts.inc @@ -25,9 +25,7 @@ PetalburgCity_Mart_Pokemart_Basic: .2byte ITEM_X_ATTACK .2byte ITEM_X_DEFENSE .2byte ITEM_ORANGE_MAIL - .2byte ITEM_NONE - release - end + pokemartlistend PetalburgCity_Mart_EventScript_ExpandedItems:: pokemart PetalburgCity_Mart_Pokemart_Expanded @@ -50,9 +48,7 @@ PetalburgCity_Mart_Pokemart_Expanded: .2byte ITEM_X_ATTACK .2byte ITEM_X_DEFENSE .2byte ITEM_ORANGE_MAIL - .2byte ITEM_NONE - release - end + pokemartlistend PetalburgCity_Mart_EventScript_Woman:: msgbox PetalburgCity_Mart_Text_WeakWillGrowStronger, MSGBOX_NPC diff --git a/data/maps/Route104_PrettyPetalFlowerShop/scripts.inc b/data/maps/Route104_PrettyPetalFlowerShop/scripts.inc index 54b2dacef1..fec03cc681 100644 --- a/data/maps/Route104_PrettyPetalFlowerShop/scripts.inc +++ b/data/maps/Route104_PrettyPetalFlowerShop/scripts.inc @@ -59,9 +59,7 @@ Route104_PrettyPetalFlowerShop_Pokemart_Plants: .2byte DECOR_COLORFUL_PLANT .2byte DECOR_BIG_PLANT .2byte DECOR_GORGEOUS_PLANT - .2byte DECOR_NONE - release - end + pokemartlistend Route104_PrettyPetalFlowerShop_EventScript_WailmerPailGirl:: lock diff --git a/data/maps/RustboroCity_Mart/scripts.inc b/data/maps/RustboroCity_Mart/scripts.inc index 65cc71baba..50acba60b4 100644 --- a/data/maps/RustboroCity_Mart/scripts.inc +++ b/data/maps/RustboroCity_Mart/scripts.inc @@ -28,9 +28,7 @@ RustboroCity_Mart_Pokemart_Basic: .2byte ITEM_X_SPEED .2byte ITEM_X_ATTACK .2byte ITEM_X_DEFENSE - .2byte ITEM_NONE - release - end + pokemartlistend RustboroCity_Mart_EventScript_PokemartExpanded:: pokemart RustboroCity_Mart_Pokemart_Expanded @@ -52,9 +50,7 @@ RustboroCity_Mart_Pokemart_Expanded: .2byte ITEM_X_SPEED .2byte ITEM_X_ATTACK .2byte ITEM_X_DEFENSE - .2byte ITEM_NONE - release - end + pokemartlistend RustboroCity_Mart_EventScript_PokefanF:: msgbox RustboroCity_Mart_Text_BuyingHealsInCaseOfShroomish, MSGBOX_NPC diff --git a/data/maps/SlateportCity/scripts.inc b/data/maps/SlateportCity/scripts.inc index ae3910750e..5438a7f364 100644 --- a/data/maps/SlateportCity/scripts.inc +++ b/data/maps/SlateportCity/scripts.inc @@ -154,9 +154,7 @@ SlateportCity_Pokemart_EnergyGuru: .2byte ITEM_ZINC .2byte ITEM_CALCIUM .2byte ITEM_HP_UP - .2byte ITEM_NONE - release - end + pokemartlistend SlateportCity_EventScript_EffortRibbonWoman:: lock @@ -514,9 +512,7 @@ SlateportCity_PokemartDecor_Dolls: .2byte DECOR_AZURILL_DOLL .2byte DECOR_MARILL_DOLL .2byte DECOR_SKITTY_DOLL - .2byte DECOR_NONE - release - end + pokemartlistend SlateportCity_EventScript_ComeBackWithSecretPower:: msgbox gText_ComeBackWithSecretPower, MSGBOX_DEFAULT @@ -550,9 +546,7 @@ SlateportCity_PokemartDecor: .2byte DECOR_A_NOTE_MAT .2byte DECOR_B_NOTE_MAT .2byte DECOR_C_HIGH_NOTE_MAT - .2byte DECOR_NONE - release - end + pokemartlistend SlateportCity_EventScript_PowerTMClerk:: lock @@ -568,9 +562,7 @@ SlateportCity_EventScript_PowerTMClerk:: SlateportCity_Pokemart_PowerTMs: .2byte ITEM_TM_HIDDEN_POWER .2byte ITEM_TM_SECRET_POWER - .2byte ITEM_NONE - release - end + pokemartlistend @ Scene with Capt Sterns interview and Team Aqua announcing plans to steal Submarine SlateportCity_EventScript_CaptStern:: diff --git a/data/maps/SlateportCity_Mart/scripts.inc b/data/maps/SlateportCity_Mart/scripts.inc index a0c0a8612e..ce7dd45b86 100644 --- a/data/maps/SlateportCity_Mart/scripts.inc +++ b/data/maps/SlateportCity_Mart/scripts.inc @@ -22,9 +22,7 @@ SlateportCity_Mart_Pokemart: .2byte ITEM_ESCAPE_ROPE .2byte ITEM_REPEL .2byte ITEM_HARBOR_MAIL - .2byte ITEM_NONE - release - end + pokemartlistend SlateportCity_Mart_EventScript_BlackBelt:: msgbox SlateportCity_Mart_Text_SomeItemsOnlyAtMart, MSGBOX_NPC diff --git a/data/maps/SootopolisCity_Mart/scripts.inc b/data/maps/SootopolisCity_Mart/scripts.inc index 618f78c524..7b3171f67f 100644 --- a/data/maps/SootopolisCity_Mart/scripts.inc +++ b/data/maps/SootopolisCity_Mart/scripts.inc @@ -22,9 +22,7 @@ SootopolisCity_Mart_Pokemart: .2byte ITEM_X_ATTACK .2byte ITEM_X_DEFENSE .2byte ITEM_SHADOW_MAIL - .2byte ITEM_NONE - release - end + pokemartlistend SootopolisCity_Mart_EventScript_FatMan:: lock diff --git a/data/maps/TrainerHill_Entrance/scripts.inc b/data/maps/TrainerHill_Entrance/scripts.inc index efc63d6561..4efceaa1cc 100644 --- a/data/maps/TrainerHill_Entrance/scripts.inc +++ b/data/maps/TrainerHill_Entrance/scripts.inc @@ -267,9 +267,7 @@ TrainerHill_Entrance_Pokemart_Basic: .2byte ITEM_DIRE_HIT .2byte ITEM_GUARD_SPEC .2byte ITEM_X_ACCURACY - .2byte ITEM_NONE - release - end + pokemartlistend TrainerHill_Entrance_EventScript_ExpandedPokemart:: pokemart TrainerHill_Entrance_Pokemart_Expanded @@ -291,9 +289,7 @@ TrainerHill_Entrance_Pokemart_Expanded: .2byte ITEM_DIRE_HIT .2byte ITEM_GUARD_SPEC .2byte ITEM_X_ACCURACY - .2byte ITEM_NONE - release - end + pokemartlistend TrainerHill_Entrance_Text_StillGettingReady: .string "This is the TRAINER HILL where\n" diff --git a/data/maps/VerdanturfTown_Mart/scripts.inc b/data/maps/VerdanturfTown_Mart/scripts.inc index c809d6703a..3c6f77b3a5 100644 --- a/data/maps/VerdanturfTown_Mart/scripts.inc +++ b/data/maps/VerdanturfTown_Mart/scripts.inc @@ -24,9 +24,7 @@ VerdanturfTown_Mart_Pokemart: .2byte ITEM_REPEL .2byte ITEM_X_SP_ATK .2byte ITEM_FLUFFY_TAIL - .2byte ITEM_NONE - release - end + pokemartlistend VerdanturfTown_Mart_EventScript_Boy:: msgbox VerdanturfTown_Mart_Text_XSpecialIsCrucial, MSGBOX_NPC diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 597534e318..21584f3ad7 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -12,6 +12,7 @@ - [How to add a new move](tutorials/how_to_new_move.md) - [How to add a new trainer class](tutorials/how_to_trainer_class.md) - [How to add a new Pokémon]() + - [v1.10.x](tutorials/how_to_new_pokemon_1_10_0.md) - [v1.9.x](tutorials/how_to_new_pokemon_1_9_0.md) - [v1.8.x](tutorials/how_to_new_pokemon_1_8_0.md) - [v1.7.x](tutorials/how_to_new_pokemon_1_7_0.md) diff --git a/docs/tutorials/how_to_battle_script_command_macro.md b/docs/tutorials/how_to_battle_script_command_macro.md index 042a87601d..2bbf503fbe 100644 --- a/docs/tutorials/how_to_battle_script_command_macro.md +++ b/docs/tutorials/how_to_battle_script_command_macro.md @@ -1,51 +1,47 @@ ## How to add new Battle Script Commands/Macros -To preface this tutorial, the battle engine upgrade has exhausted all battle script command IDs, and instead uses the `various` command to effectively add new commands. This is preferential to creating a secondary battle script command table like is done in the CFRU. +To preface this tutorial, the battle engine upgrade has exhausted all battle script command IDs. Historically, we've used the `various` command to effectively add new commands. However, this has caused issues of maintainability and readability due to the massive switch needed for it. Thanks to the cleanup made by the team and contributors, we now are able to call an infinite amount of commands by using `callnative`. This is preferential to creating a secondary battle script command table like is done in the CFRU. -In general, `gBattlescriptCurrInstr` tracks the current battle script position as a ROM address. Fortunately, we don't need to worry about ROM addresses when using the decomps, but it is important to understand because of how the `various` command is set up. +In general, `gBattlescriptCurrInstr` tracks the current battle script position as a ROM address. Fortunately, we don't need to worry about ROM addresses when using the decomps, but it is important to understand because of how the `callnative` command is set up. ``` -.macro various battler:req, param1:req - .byte 0x76 - .byte \battler - .byte \param1 - .endm + .macro callnative func:req + .byte 0xff + .4byte \func + .endm ``` +`callnative` uses the last battle script command ID in order to pass a native function as an argument. Additional optional arguments are added recursively via a macro, so no need to worry about how they need to align to the amount of instructions to skip. -`various` is 3 bytes in size, so if we wanted to advance to the next battle script command, we would write `gBattlescriptCurrInstr += 3`. Coincidentally, this is found at the end of `Cmd_Various` in `src/battle_script_commands.c`. - -Now, how might we add a custom various command case? Here are the steps. We will use `VARIOUS_SET_SIMPLE_BEAM` as an example. -### 1. Add a definition to `include/constants/battle_script_commands.h`. - -For example, `#define VARIOUS_SET_SIMPLE_BEAM 39` - -### 2. Create a macro in `asm/macros/battle_script.inc`. For example: +Now, how might we add a custom `callnative` command? Here are the steps. We will use `BS_TrySetOctolock` as an example. +### 1. Create a macro in `asm/macros/battle_script.inc`. For example: ```c -.macro setabilitysimple battler:req, ptr:req - various \battler VARIOUS_SET_SIMPLE_BEAM - .4byte \ptr - .endm + .macro trysetoctolock battler:req, failInstr:req + callnative BS_TrySetOctolock + .byte \battler + .4byte \failInstr + .endm ``` - -### 3. Add your new various command ID to `Cmd_Various`. For example: +### 2. Add your new callnative command ID to `src/battle_script_commands.c`. For example: ```c - case VARIOUS_SET_SIMPLE_BEAM: - if (IsEntrainmentTargetOrSimpleBeamBannedAbility(gBattleMons[gBattlerTarget].ability) - || gBattleMons[gBattlerTarget].ability == ABILITY_SIMPLE) - { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); - } - else - { - gBattleMons[gBattlerTarget].ability = ABILITY_SIMPLE; - RecordAbilityBattle(gActiveBattler, ABILITY_SIMPLE); - gBattlescriptCurrInstr += 7; - } - return; +void BS_TrySetOctolock(void) +{ + NATIVE_ARGS(u8 battler, const u8 *failInstr); + u32 battler = GetBattlerForBattleScript(cmd->battler); + + if (gDisableStructs[battler].octolock) + { + gBattlescriptCurrInstr = cmd->failInstr; + } + else + { + gDisableStructs[battler].octolock = TRUE; + gBattleMons[battler].status2 |= STATUS2_ESCAPE_PREVENTION; + gDisableStructs[battler].battlerPreventingEscape = gBattlerAttacker; + gBattlescriptCurrInstr = cmd->nextInstr; + } +} ``` - -The macros' `battler` argument is the battler who will be affected/considered by your command. In our case, which battler we will try to give `ABILITY_SIMPLE`. Note that `gActiveBattler` is always set to this battler at the beginning of `Cmd_Various`. - -The `ptr` argument is an extra argument that, in this case, provides a battle script to jump to in the event that we fail to set `ABILITY_SIMPLE`. We must add the `.4byte \ptr` inside our macro. So now when we want to advance to the next battle script command in our script, we must increment `gBattlescriptCurrInstr` by `7` because our overall macro is 3 bytes for the various command, and 4 bytes for the pointer. *IMPORTANT* the `return` at the end of the switch case is required because remember that `various` always defaults to `gBattlescriptCurrInstr += 3` at the very end of the function, so if we included `gBattlescriptCurrInstr += 7` with a `break`, we would end up effectively doing `gBattlescriptCurrInstr += 10`. - -This behavior can be found under the `else` statement in the example above, corresponding to `ABILITY_SIMPLE` being correctly applied. If we are unable to set `ABILITY_SIMPLE`, however, notice the following `gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);`. This means we are jumping to the battle script provided by the pointer 3 bytes after our various command (which is the `ptr` argument described previously). We still must `return` or else we would actually jump to 3 bytes after the `ptr` battle script begins. +Each of the arguments defined in the macro (`battler`, `failInstr`) need to be called at the start of the command using `NATIVE_ARGS`. +The byte count in the macro should correspond to the type that will be used for the command (eg, `u8` is `byte`, while the pointer are `4byte`). +These arguments can then be accessed as `cmd->battler` and `cmd->battler`. +`gBattlescriptCurrInstr = cmd->nextInstr;` advances to the next instruction. diff --git a/graphics/birch_speech/bg2.pal b/graphics/birch_speech/bg2.pal index 3457f9b455..33f619ee44 100644 --- a/graphics/birch_speech/bg2.pal +++ b/graphics/birch_speech/bg2.pal @@ -1,6 +1,6 @@ JASC-PAL 0100 -8 +16 255 255 164 255 255 106 222 222 90 @@ -9,3 +9,11 @@ JASC-PAL 123 123 49 90 90 32 57 57 16 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 +0 0 0 diff --git a/graphics/pokemon/ariados/anim_front.png b/graphics/pokemon/ariados/anim_front.png index 945c4d188f..82d947054b 100644 Binary files a/graphics/pokemon/ariados/anim_front.png and b/graphics/pokemon/ariados/anim_front.png differ diff --git a/graphics/pokemon/diggersby/anim_front.png b/graphics/pokemon/diggersby/anim_front.png index f2a0998e88..69c49c5276 100644 Binary files a/graphics/pokemon/diggersby/anim_front.png and b/graphics/pokemon/diggersby/anim_front.png differ diff --git a/graphics/pokemon/diggersby/back.png b/graphics/pokemon/diggersby/back.png index 36a4373816..a1cc29260d 100644 Binary files a/graphics/pokemon/diggersby/back.png and b/graphics/pokemon/diggersby/back.png differ diff --git a/graphics/pokemon/diggersby/shiny.pal b/graphics/pokemon/diggersby/shiny.pal index 5fd7727a42..f5f12f2cf0 100644 --- a/graphics/pokemon/diggersby/shiny.pal +++ b/graphics/pokemon/diggersby/shiny.pal @@ -6,7 +6,7 @@ JASC-PAL 120 120 112 160 160 144 8 8 8 -120 120 112 +84 84 78 48 48 56 232 232 232 240 152 168 diff --git a/graphics/pokemon/duraludon/overworld.png b/graphics/pokemon/duraludon/overworld.png index 0c8228abcb..a7488c4960 100644 Binary files a/graphics/pokemon/duraludon/overworld.png and b/graphics/pokemon/duraludon/overworld.png differ diff --git a/graphics/pokemon/honedge/anim_front.png b/graphics/pokemon/honedge/anim_front.png index 9a5dc75078..6376e2d1e2 100644 Binary files a/graphics/pokemon/honedge/anim_front.png and b/graphics/pokemon/honedge/anim_front.png differ diff --git a/graphics/pokemon/honedge/back.png b/graphics/pokemon/honedge/back.png index d9092fa13a..b1bc8634b0 100644 Binary files a/graphics/pokemon/honedge/back.png and b/graphics/pokemon/honedge/back.png differ diff --git a/graphics/pokemon/honedge/normal.pal b/graphics/pokemon/honedge/normal.pal index 51f60119df..d6a8a50995 100644 --- a/graphics/pokemon/honedge/normal.pal +++ b/graphics/pokemon/honedge/normal.pal @@ -3,17 +3,17 @@ JASC-PAL 16 152 208 160 8 48 56 -0 128 160 +36 103 149 16 16 16 80 64 40 -248 208 128 -176 152 88 +255 215 132 +181 158 90 136 104 56 -152 232 248 +102 225 253 96 192 216 80 88 88 168 168 168 216 216 216 -48 56 40 -152 128 80 -136 88 56 +99 84 80 +201 185 131 +167 139 110 diff --git a/graphics/pokemon/maractus/back.png b/graphics/pokemon/maractus/back.png index bc83adca5c..66a6520840 100644 Binary files a/graphics/pokemon/maractus/back.png and b/graphics/pokemon/maractus/back.png differ diff --git a/graphics/pokemon/pichu/spiky_eared/front.png b/graphics/pokemon/pichu/spiky_eared/front.png deleted file mode 100644 index 15b9201a27..0000000000 Binary files a/graphics/pokemon/pichu/spiky_eared/front.png and /dev/null differ diff --git a/graphics/pokemon/pichu/spiky_eared/overworld.png b/graphics/pokemon/pichu/spiky_eared/overworld.png index 7208db5108..36c1040003 100644 Binary files a/graphics/pokemon/pichu/spiky_eared/overworld.png and b/graphics/pokemon/pichu/spiky_eared/overworld.png differ diff --git a/graphics/pokemon/pincurchin/anim_front.png b/graphics/pokemon/pincurchin/anim_front.png index b8ed4964e4..ffc6bb6008 100644 Binary files a/graphics/pokemon/pincurchin/anim_front.png and b/graphics/pokemon/pincurchin/anim_front.png differ diff --git a/include/battle.h b/include/battle.h index 8dc45b9ff0..0f798ea481 100644 --- a/include/battle.h +++ b/include/battle.h @@ -864,9 +864,10 @@ STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLER #define F_DYNAMIC_TYPE_IGNORE_PHYSICALITY (1 << 6) // If set, the dynamic type's physicality won't be used for certain move effects. #define F_DYNAMIC_TYPE_SET (1 << 7) // Set for all dynamic types to distinguish a dynamic type of Normal (0) from no dynamic type. -#define IS_MOVE_PHYSICAL(move)(GetBattleMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL) -#define IS_MOVE_SPECIAL(move)(GetBattleMoveCategory(move) == DAMAGE_CATEGORY_SPECIAL) -#define IS_MOVE_STATUS(move)(gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) +#define IS_MOVE_PHYSICAL(move) (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL) +#define IS_MOVE_SPECIAL(move) (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_SPECIAL) +#define IS_MOVE_STATUS(move) (gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) + #define IS_MOVE_RECOIL(move)(gMovesInfo[move].recoil > 0 || gMovesInfo[move].effect == EFFECT_RECOIL_IF_MISS) /* Checks if 'battlerId' is any of the types. diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 729d173933..7cfc28e5d6 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -116,7 +116,7 @@ bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensiv bool32 HasMoveWithCategory(u32 battler, u32 category); bool32 HasMoveWithType(u32 battler, u32 type); bool32 HasMoveEffect(u32 battlerId, u32 moveEffect); -bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument); +bool32 IsPowerBasedOnStatus(u32 battlerId, u32 effect, u32 argument); bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect); bool32 HasMoveWithCriticalHitChance(u32 battlerId); bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index ef30b10b8a..5dccb53a3f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -804,18 +804,18 @@ extern const u8 BattleScript_EffectGeomancy[]; extern const u8 BattleScript_EffectFairyLock[]; extern const u8 BattleScript_EffectAllySwitch[]; extern const u8 BattleScript_EffectRelicSong[]; -extern const u8 BattleScript_EffectEerieSpell[]; +extern const u8 BattleScript_MoveEffectEerieSpell[]; extern const u8 BattleScript_EffectJungleHealing[]; extern const u8 BattleScript_EffectCoaching[]; extern const u8 BattleScript_EffectDecorate[]; extern const u8 BattleScript_EffectRecoilHP25[]; extern const u8 BattleScript_EffectStuffCheeks[]; -extern const u8 BattleScript_EffectGlitzyGlow[]; -extern const u8 BattleScript_EffectBaddyBad[]; -extern const u8 BattleScript_EffectSappySeed[]; -extern const u8 BattleScript_EffectFreezyFrost[]; +extern const u8 BattleScript_MoveEffectLightScreen[]; +extern const u8 BattleScript_MoveEffectReflect[]; +extern const u8 BattleScript_MoveEffectLeechSeed[]; +extern const u8 BattleScript_MoveEffectHaze[]; extern const u8 BattleScript_EffectSparklySwirl[]; -extern const u8 BattleScript_EffectPlasmaFists[]; +extern const u8 BattleScript_MoveEffectIonDeluge[]; extern const u8 BattleScript_EffectHyperspaceFury[]; extern const u8 BattleScript_EffectAuraWheel[]; extern const u8 BattleScript_EffectPhotonGeyser[]; @@ -838,7 +838,7 @@ extern const u8 BattleScript_EffectRevivalBlessing[]; extern const u8 BattleScript_EffectSnow[]; extern const u8 BattleScript_EffectTakeHeart[]; extern const u8 BattleScript_EffectCorrosiveGas[]; -extern const u8 BattleScript_EffectSaltCure[]; +extern const u8 BattleScript_MoveEffectSaltCure[]; extern const u8 BattleScript_EffectChillyReception[]; extern const u8 BattleScript_EffectMaxMove[]; extern const u8 BattleScript_EffectGlaiveRush[]; diff --git a/include/battle_util.h b/include/battle_util.h index 637ac7e4b5..eae29ca7a3 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -100,33 +100,37 @@ struct TypePower enum { CANCELLER_FLAGS, + CANCELLER_STANCE_CHANGE_1, CANCELLER_SKY_DROP, + CANCELLER_RECHARGE, CANCELLER_ASLEEP, CANCELLER_FROZEN, CANCELLER_OBEDIENCE, CANCELLER_TRUANT, - CANCELLER_RECHARGE, CANCELLER_FLINCH, + CANCELLER_IN_LOVE, CANCELLER_DISABLED, - CANCELLER_GRAVITY, CANCELLER_HEAL_BLOCKED, + CANCELLER_GRAVITY, + CANCELLER_THROAT_CHOP, CANCELLER_TAUNTED, CANCELLER_IMPRISONED, CANCELLER_CONFUSED, CANCELLER_PARALYSED, - CANCELLER_IN_LOVE, CANCELLER_BIDE, CANCELLER_THAW, + CANCELLER_STANCE_CHANGE_2, + CANCELLER_WEATHER_PRIMAL, + CANCELLER_DYNAMAX_BLOCKED, CANCELLER_POWDER_MOVE, CANCELLER_POWDER_STATUS, - CANCELLER_THROAT_CHOP, + CANCELLER_PROTEAN, + CANCELLER_PSYCHIC_TERRAIN, CANCELLER_EXPLODING_DAMP, CANCELLER_MULTIHIT_MOVES, CANCELLER_Z_MOVES, CANCELLER_MULTI_TARGET_MOVES, CANCELLER_END, - CANCELLER_PSYCHIC_TERRAIN, - CANCELLER_END2, }; enum { @@ -197,9 +201,8 @@ u8 DoBattlerEndTurnEffects(void); bool32 HandleWishPerishSongOnTurnEnd(void); bool32 HandleFaintedMonActions(void); void TryClearRageAndFuryCutter(void); -u8 AtkCanceller_UnableToUseMove(u32 moveType); +u32 AtkCanceller_MoveSuccessOrder(void); void SetAtkCancellerForCalledMove(void); -u8 AtkCanceller_UnableToUseMove2(void); bool32 HasNoMonsToSwitch(u32 battler, u8 r1, u8 r2); bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility); u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef); @@ -297,7 +300,7 @@ bool32 IsGen6ExpShareEnabled(void); bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect); bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance); bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect); -bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument); +bool32 IsMoveEffectRemoveSpeciesType(u32 move, u32 moveEffect, u32 argument); bool32 MoveHasChargeTurnAdditionalEffect(u32 move); bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef); bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef); diff --git a/include/config/battle.h b/include/config/battle.h index 9657d4646e..901b611a76 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -156,6 +156,7 @@ #define B_ABILITY_TRIGGER_CHANCE GEN_LATEST // In Gen3, Shed Skin, Cute Charm, Flame Body, Static and Poison Point have a 1/3 chance to trigger. In Gen 4+ it's 30%. // In Gen3, Effect Spore has a 10% chance to sleep, poison or paralyze, with an equal chance. // In Gen4, it's 30%. In Gen5+ it has 11% to sleep, 9% chance to poison and 10% chance to paralyze. +#define B_PICKUP_WILD GEN_LATEST // In Gen9+, Pickup allows its user to pickup its own used item at the end of the turn in wild battles. // Item settings #define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore HP activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. @@ -165,6 +166,7 @@ #define B_MENTAL_HERB GEN_LATEST // In Gen5+, the Mental Herb cures Taunt, Encore, Torment, Heal Block, and Disable in addition to Infatuation from before. #define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items. #define B_RETURN_STOLEN_NPC_ITEMS GEN_LATEST // In Gen5+, Thief and Covet no longer steal items from NPCs. +#define B_STEAL_WILD_ITEMS GEN_LATEST // In Gen9, Thief and Covet steal a wild pokemon's item and send it to the bag. Before Gen9, the stolen item would be held by the Thief/Covet user. #define B_RESTORE_HELD_BATTLE_ITEMS GEN_LATEST // In Gen9, all non-berry items are restored after battle. #define B_SOUL_DEW_BOOST GEN_LATEST // In Gens3-6, Soul Dew boosts Latis' Sp. Atk and Sp. Def. In Gen7+ it boosts the power of their Psychic and Dragon type moves instead. #define B_NET_BALL_MODIFIER GEN_LATEST // In Gen7+, Net Ball's catch multiplier is x5 instead of x3. diff --git a/include/config/pokemon.h b/include/config/pokemon.h index 65542a6ccd..0b5d3828ad 100644 --- a/include/config/pokemon.h +++ b/include/config/pokemon.h @@ -56,7 +56,7 @@ #define P_SHOW_TERA_TYPE GEN_8 // Since Gen 9, the Tera Type is shown on the summary screen. #define P_TM_LITERACY GEN_LATEST // Since Gen 6, TM illiterate Pokémon can learn TMs that teach moves that are in their level-up learnsets. #define P_CAN_FORGET_HIDDEN_MOVE FALSE // If TRUE, Pokémon can forget any move, even if it is a Hidden Move. -#define P_EGG_CYCLE_LENGTH GEN_LATEST // Since Gen 8, egg cycles take half as many steps as before. +#define P_EGG_CYCLE_LENGTH GEN_LATEST // Since Gen 8, egg cycles take half as many steps as before. Previous Gens have some varied step counts around 255. #define P_ONLY_OBTAINABLE_SHINIES FALSE // If TRUE, Pokémon encountered in the Battle Pyramid won't be shiny. #define P_NO_SHINIES_WITHOUT_POKEBALLS FALSE // If TRUE, Pokémon encountered when the player is out of Poké Balls won't be shiny #define P_SHOW_DYNAMIC_TYPES FALSE // If TRUE, all moves with dynamic type changes will be reflected as their current type in battle/summary screens instead of just select ones like in vanilla. diff --git a/include/constants/battle.h b/include/constants/battle.h index 99e498b628..16745572b7 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -325,7 +325,11 @@ enum BattleWeather #define MOVE_EFFECT_TOXIC 6 #define MOVE_EFFECT_FROSTBITE 7 #define PRIMARY_STATUS_MOVE_EFFECT MOVE_EFFECT_FROSTBITE // All above move effects apply primary status -#define MOVE_EFFECT_FREEZE_OR_FROSTBITE (B_USE_FROSTBITE == TRUE ? MOVE_EFFECT_FROSTBITE : MOVE_EFFECT_FREEZE) +#if B_USE_FROSTBITE == TRUE +#define MOVE_EFFECT_FREEZE_OR_FROSTBITE MOVE_EFFECT_FROSTBITE +#else +#define MOVE_EFFECT_FREEZE_OR_FROSTBITE MOVE_EFFECT_FREEZE +#endif #define MOVE_EFFECT_CONFUSION 8 #define MOVE_EFFECT_FLINCH 9 #define MOVE_EFFECT_TRI_ATTACK 10 @@ -399,8 +403,16 @@ enum BattleWeather #define MOVE_EFFECT_PSYCHIC_NOISE 78 #define MOVE_EFFECT_TERA_BLAST 79 #define MOVE_EFFECT_ORDER_UP 80 +#define MOVE_EFFECT_ION_DELUGE 81 +#define MOVE_EFFECT_AROMATHERAPY 82 // No functionality yet +#define MOVE_EFFECT_HAZE 83 +#define MOVE_EFFECT_LEECH_SEED 84 +#define MOVE_EFFECT_REFLECT 85 +#define MOVE_EFFECT_LIGHT_SCREEN 86 +#define MOVE_EFFECT_SALT_CURE 87 +#define MOVE_EFFECT_EERIE_SPELL 88 -#define NUM_MOVE_EFFECTS 81 +#define NUM_MOVE_EFFECTS 88 #define MOVE_EFFECT_AFFECTS_USER 0x2000 #define MOVE_EFFECT_CERTAIN 0x4000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 15edbd28ef..df752bf496 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -285,7 +285,6 @@ enum { EFFECT_ALLY_SWITCH, EFFECT_RELIC_SONG, EFFECT_BODY_PRESS, - EFFECT_EERIE_SPELL, EFFECT_JUNGLE_HEALING, EFFECT_COACHING, EFFECT_LASH_OUT, @@ -296,12 +295,7 @@ enum { EFFECT_RECOIL_HP_25, EFFECT_STUFF_CHEEKS, EFFECT_GRAV_APPLE, - EFFECT_GLITZY_GLOW, - EFFECT_BADDY_BAD, - EFFECT_SAPPY_SEED, - EFFECT_FREEZY_FROST, EFFECT_SPARKLY_SWIRL, - EFFECT_PLASMA_FISTS, EFFECT_HYPERSPACE_FURY, EFFECT_AURA_WHEEL, EFFECT_PHOTON_GEYSER, @@ -334,7 +328,6 @@ enum { EFFECT_COLLISION_COURSE, EFFECT_CORROSIVE_GAS, EFFECT_POPULATION_BOMB, - EFFECT_SALT_CURE, EFFECT_CHILLY_RECEPTION, EFFECT_MAX_MOVE, EFFECT_GLAIVE_RUSH, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 3b3faa5790..bd1c61ec09 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -88,138 +88,137 @@ #define CMP_COMMON_BITS 4 #define CMP_NO_COMMON_BITS 5 -// Cmd_various -#define VARIOUS_CANCEL_MULTI_TURN_MOVES 0 -#define VARIOUS_IS_RUNNING_IMPOSSIBLE 1 -#define VARIOUS_GET_MOVE_TARGET 2 -#define VARIOUS_GET_BATTLER_FAINTED 3 -#define VARIOUS_RESET_SWITCH_IN_ABILITY_BITS 4 -#define VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP 5 -#define VARIOUS_RESET_PLAYER_FAINTED 6 -#define VARIOUS_PALACE_FLAVOR_TEXT 7 -#define VARIOUS_ARENA_JUDGMENT_WINDOW 8 -#define VARIOUS_ARENA_OPPONENT_MON_LOST 9 -#define VARIOUS_ARENA_PLAYER_MON_LOST 10 -#define VARIOUS_ARENA_BOTH_MONS_LOST 11 -#define VARIOUS_EMIT_YESNOBOX 12 -#define VARIOUS_DRAW_ARENA_REF_TEXT_BOX 13 -#define VARIOUS_ERASE_ARENA_REF_TEXT_BOX 14 -#define VARIOUS_ARENA_JUDGMENT_STRING 15 -#define VARIOUS_ARENA_WAIT_STRING 16 -#define VARIOUS_WAIT_CRY 17 -#define VARIOUS_RETURN_OPPONENT_MON1 18 -#define VARIOUS_RETURN_OPPONENT_MON2 19 -#define VARIOUS_VOLUME_DOWN 20 -#define VARIOUS_VOLUME_UP 21 -#define VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT 22 -#define VARIOUS_PALACE_TRY_ESCAPE_STATUS 23 -#define VARIOUS_SET_TELEPORT_OUTCOME 24 -#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 25 -#define VARIOUS_STAT_TEXT_BUFFER 26 -#define VARIOUS_SWITCHIN_ABILITIES 27 -#define VARIOUS_INSTANT_HP_DROP 28 -#define VARIOUS_CLEAR_STATUS 29 -#define VARIOUS_RESTORE_PP 30 -#define VARIOUS_TRY_ACTIVATE_MOXIE 31 -#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 32 -#define VARIOUS_PLAY_MOVE_ANIMATION 33 -#define VARIOUS_SET_LUCKY_CHANT 34 -#define VARIOUS_SUCKER_PUNCH_CHECK 35 -#define VARIOUS_SET_SIMPLE_BEAM 36 -#define VARIOUS_TRY_ENTRAINMENT 37 -#define VARIOUS_SET_LAST_USED_ABILITY 38 -#define VARIOUS_INVERT_STAT_STAGES 39 -#define VARIOUS_TRY_ME_FIRST 40 -#define VARIOUS_JUMP_IF_BATTLE_END 41 -#define VARIOUS_TRY_ELECTRIFY 42 -#define VARIOUS_TRY_REFLECT_TYPE 43 -#define VARIOUS_TRY_SOAK 44 -#define VARIOUS_HANDLE_MEGA_EVO 45 -#define VARIOUS_TRY_LAST_RESORT 46 -#define VARIOUS_SET_ARG_TO_BATTLE_DAMAGE 47 -#define VARIOUS_TRY_AUTOTOMIZE 48 -#define VARIOUS_ABILITY_POPUP 49 -#define VARIOUS_JUMP_IF_TARGET_ALLY 50 -#define VARIOUS_TRY_SYNCHRONOISE 51 -#define VARIOUS_PSYCHO_SHIFT 52 -#define VARIOUS_CURE_STATUS 53 -#define VARIOUS_POWER_TRICK 54 -#define VARIOUS_AFTER_YOU 55 -#define VARIOUS_BESTOW 56 -#define VARIOUS_JUMP_IF_NOT_GROUNDED 57 -#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 58 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 59 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 60 -#define VARIOUS_SET_AURORA_VEIL 61 -#define VARIOUS_TRY_THIRD_TYPE 62 -#define VARIOUS_ACUPRESSURE 63 -#define VARIOUS_SET_POWDER 64 -#define VARIOUS_SPECTRAL_THIEF 65 -#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 66 -#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 67 -#define VARIOUS_JUMP_IF_ROAR_FAILS 68 -#define VARIOUS_TRY_INSTRUCT 69 -#define VARIOUS_JUMP_IF_NOT_BERRY 70 -#define VARIOUS_TRACE_ABILITY 71 -#define VARIOUS_UPDATE_NICK 72 -#define VARIOUS_TRY_ILLUSION_OFF 73 -#define VARIOUS_SET_SPRITEIGNORE0HP 74 -#define VARIOUS_HANDLE_FORM_CHANGE 75 -#define VARIOUS_GET_STAT_VALUE 76 -#define VARIOUS_JUMP_IF_FULL_HP 77 -#define VARIOUS_LOSE_TYPE 78 -#define VARIOUS_TRY_ACTIVATE_SOULHEART 79 -#define VARIOUS_TRY_ACTIVATE_RECEIVER 80 -#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 81 -#define VARIOUS_TRY_FRISK 82 -#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 83 -#define VARIOUS_TRY_FAIRY_LOCK 84 -#define VARIOUS_JUMP_IF_NO_ALLY 85 -#define VARIOUS_POISON_TYPE_IMMUNITY 86 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 87 -#define VARIOUS_INFATUATE_WITH_BATTLER 88 -#define VARIOUS_SET_LAST_USED_ITEM 89 -#define VARIOUS_PARALYZE_TYPE_IMMUNITY 90 -#define VARIOUS_JUMP_IF_ABSENT 91 -#define VARIOUS_DESTROY_ABILITY_POPUP 92 -#define VARIOUS_TOTEM_BOOST 93 -#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 94 -#define VARIOUS_MOVEEND_ITEM_EFFECTS 95 -#define VARIOUS_TERRAIN_SEED 96 -#define VARIOUS_MAKE_INVISIBLE 97 -#define VARIOUS_ROOM_SERVICE 98 -#define VARIOUS_EERIE_SPELL_PP_REDUCE 99 -#define VARIOUS_JUMP_IF_TEAM_HEALTHY 100 -#define VARIOUS_TRY_HEAL_QUARTER_HP 101 -#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 102 -#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 103 -#define VARIOUS_GET_ROTOTILLER_TARGETS 104 -#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 105 -#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 106 -#define VARIOUS_CONSUME_BERRY 107 -#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 108 -#define VARIOUS_JUMP_IF_SPECIES 109 -#define VARIOUS_UPDATE_ABILITY_POPUP 110 -#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 111 -#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 112 -#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 113 -#define VARIOUS_TRY_NO_RETREAT 114 -#define VARIOUS_CHECK_POLTERGEIST 115 -#define VARIOUS_CUT_1_3_HP_RAISE_STATS 116 -#define VARIOUS_TRY_END_NEUTRALIZING_GAS 117 -#define VARIOUS_JUMP_IF_UNDER_200 118 -#define VARIOUS_SET_SKY_DROP 119 -#define VARIOUS_CLEAR_SKY_DROP 120 -#define VARIOUS_SKY_DROP_YAWN 121 -#define VARIOUS_CURE_CERTAIN_STATUSES 122 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 123 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 124 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 125 -#define VARIOUS_SAVE_BATTLER_ITEM 126 -#define VARIOUS_RESTORE_BATTLER_ITEM 127 -#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 128 -#define VARIOUS_SWAP_SIDE_STATUSES 129 -#define VARIOUS_SWAP_STATS 130 +enum CmdVarious +{ + VARIOUS_CANCEL_MULTI_TURN_MOVES, + VARIOUS_IS_RUNNING_IMPOSSIBLE, + VARIOUS_GET_MOVE_TARGET, + VARIOUS_GET_BATTLER_FAINTED, + VARIOUS_RESET_SWITCH_IN_ABILITY_BITS, + VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP, + VARIOUS_RESET_PLAYER_FAINTED, + VARIOUS_PALACE_FLAVOR_TEXT, + VARIOUS_ARENA_JUDGMENT_WINDOW, + VARIOUS_ARENA_OPPONENT_MON_LOST, + VARIOUS_ARENA_PLAYER_MON_LOST, + VARIOUS_ARENA_BOTH_MONS_LOST, + VARIOUS_EMIT_YESNOBOX, + VARIOUS_DRAW_ARENA_REF_TEXT_BOX, + VARIOUS_ERASE_ARENA_REF_TEXT_BOX, + VARIOUS_ARENA_JUDGMENT_STRING, + VARIOUS_ARENA_WAIT_STRING, + VARIOUS_WAIT_CRY, + VARIOUS_RETURN_OPPONENT_MON1, + VARIOUS_RETURN_OPPONENT_MON2, + VARIOUS_VOLUME_DOWN, + VARIOUS_VOLUME_UP, + VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT, + VARIOUS_PALACE_TRY_ESCAPE_STATUS, + VARIOUS_SET_TELEPORT_OUTCOME, + VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC, + VARIOUS_STAT_TEXT_BUFFER, + VARIOUS_SWITCHIN_ABILITIES, + VARIOUS_INSTANT_HP_DROP, + VARIOUS_CLEAR_STATUS, + VARIOUS_RESTORE_PP, + VARIOUS_TRY_ACTIVATE_MOXIE, + VARIOUS_TRY_ACTIVATE_FELL_STINGER, + VARIOUS_PLAY_MOVE_ANIMATION, + VARIOUS_SET_LUCKY_CHANT, + VARIOUS_SUCKER_PUNCH_CHECK, + VARIOUS_SET_SIMPLE_BEAM, + VARIOUS_TRY_ENTRAINMENT, + VARIOUS_SET_LAST_USED_ABILITY, + VARIOUS_INVERT_STAT_STAGES, + VARIOUS_TRY_ME_FIRST, + VARIOUS_JUMP_IF_BATTLE_END, + VARIOUS_TRY_ELECTRIFY, + VARIOUS_TRY_SOAK, + VARIOUS_TRY_LAST_RESORT, + VARIOUS_SET_ARG_TO_BATTLE_DAMAGE, + VARIOUS_TRY_AUTOTOMIZE, + VARIOUS_ABILITY_POPUP, + VARIOUS_JUMP_IF_TARGET_ALLY, + VARIOUS_TRY_SYNCHRONOISE, + VARIOUS_PSYCHO_SHIFT, + VARIOUS_CURE_STATUS, + VARIOUS_POWER_TRICK, + VARIOUS_AFTER_YOU, + VARIOUS_BESTOW, + VARIOUS_JUMP_IF_NOT_GROUNDED, + VARIOUS_HANDLE_TRAINER_SLIDE_MSG, + VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF, + VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON, + VARIOUS_SET_AURORA_VEIL, + VARIOUS_TRY_THIRD_TYPE, + VARIOUS_ACUPRESSURE, + VARIOUS_SET_POWDER, + VARIOUS_SPECTRAL_THIEF, + VARIOUS_GRAVITY_ON_AIRBORNE_MONS, + VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS, + VARIOUS_JUMP_IF_ROAR_FAILS, + VARIOUS_TRY_INSTRUCT, + VARIOUS_JUMP_IF_NOT_BERRY, + VARIOUS_TRACE_ABILITY, + VARIOUS_UPDATE_NICK, + VARIOUS_TRY_ILLUSION_OFF, + VARIOUS_SET_SPRITEIGNORE0HP, + VARIOUS_HANDLE_FORM_CHANGE, + VARIOUS_GET_STAT_VALUE, + VARIOUS_JUMP_IF_FULL_HP, + VARIOUS_LOSE_TYPE, + VARIOUS_TRY_ACTIVATE_SOULHEART, + VARIOUS_TRY_ACTIVATE_RECEIVER, + VARIOUS_TRY_ACTIVATE_BEAST_BOOST, + VARIOUS_TRY_FRISK, + VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED, + VARIOUS_TRY_FAIRY_LOCK, + VARIOUS_JUMP_IF_NO_ALLY, + VARIOUS_POISON_TYPE_IMMUNITY, + VARIOUS_JUMP_IF_HOLD_EFFECT, + VARIOUS_INFATUATE_WITH_BATTLER, + VARIOUS_SET_LAST_USED_ITEM, + VARIOUS_PARALYZE_TYPE_IMMUNITY, + VARIOUS_JUMP_IF_ABSENT, + VARIOUS_DESTROY_ABILITY_POPUP, + VARIOUS_TOTEM_BOOST, + VARIOUS_TRY_ACTIVATE_GRIM_NEIGH, + VARIOUS_MOVEEND_ITEM_EFFECTS, + VARIOUS_TERRAIN_SEED, + VARIOUS_MAKE_INVISIBLE, + VARIOUS_ROOM_SERVICE, + VARIOUS_JUMP_IF_TEAM_HEALTHY, + VARIOUS_TRY_HEAL_QUARTER_HP, + VARIOUS_JUMP_IF_PRANKSTER_BLOCKED, + VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER, + VARIOUS_GET_ROTOTILLER_TARGETS, + VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED, + VARIOUS_TRY_ACTIVATE_BATTLE_BOND, + VARIOUS_CONSUME_BERRY, + VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL, + VARIOUS_JUMP_IF_SPECIES, + VARIOUS_UPDATE_ABILITY_POPUP, + VARIOUS_JUMP_IF_WEATHER_AFFECTED, + VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED, + VARIOUS_SET_ATTACKER_STICKY_WEB_USER, + VARIOUS_TRY_NO_RETREAT, + VARIOUS_CHECK_POLTERGEIST, + VARIOUS_CUT_1_3_HP_RAISE_STATS, + VARIOUS_TRY_END_NEUTRALIZING_GAS, + VARIOUS_JUMP_IF_UNDER_200, + VARIOUS_SET_SKY_DROP, + VARIOUS_CLEAR_SKY_DROP, + VARIOUS_SKY_DROP_YAWN, + VARIOUS_CURE_CERTAIN_STATUSES, + VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES, + VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY, + VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT, + VARIOUS_SAVE_BATTLER_ITEM, + VARIOUS_RESTORE_BATTLER_ITEM, + VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM, + VARIOUS_SWAP_SIDE_STATUSES, + VARIOUS_SWAP_STATS, +}; // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 1 diff --git a/include/global.h b/include/global.h index 5846f09359..687281eaa7 100644 --- a/include/global.h +++ b/include/global.h @@ -815,8 +815,7 @@ struct DayCare { struct DaycareMon mons[DAYCARE_MON_COUNT]; u32 offspringPersonality; - u8 stepCounter; - //u8 padding[3]; + u32 stepCounter; }; struct LilycoveLadyQuiz diff --git a/include/pokemon.h b/include/pokemon.h index 8a618f5fe1..0618c6c785 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -495,6 +495,24 @@ struct MoveInfo u8 powerOverride; } zMove; + union { + struct { + u16 stringId; + u16 status; + } twoTurnAttack; + struct { + u16 side; + u16 property; // can be used to remove the hardcoded values + } protect; + u32 status; + u16 moveProperty; + u16 holdEffect; + u16 type; + u16 fixedDamage; + u16 absorbPercentage; + u16 maxEffect; + } argument; + s32 priority:4; u32 recoil:7; u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit. @@ -548,8 +566,6 @@ struct MoveInfo u32 sketchBanned:1; u32 padding:5; // end of word - u32 argument; - // primary/secondary effects const struct AdditionalEffect *additionalEffects; @@ -564,8 +580,12 @@ struct MoveInfo #define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__} #define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ )) -// Just a hack to make a move boosted by Sheer Force despite having no secondary effects affected -#define SHEER_FORCE_HACK { .moveEffect = 0, .chance = 100, } +enum SheerForceBoost +{ + SHEER_FORCE_AUTO_BOOST, // This is the default state when a move has a move effect with a chance + SHEER_FORCE_BOOST, // If a move effect doesn't have an effect with a chance this can force a boost + SHEER_FORCE_NO_BOOST, // Prevents a Sheer Force boost +}; struct AdditionalEffect { @@ -573,6 +593,8 @@ struct AdditionalEffect u8 self:1; u8 onlyIfTargetRaisedStats:1; u8 onChargeTurnOnly:1; + u8 sheerForceBoost:2; // Handles edge cases for Sheer Force + u8 padding:3; u8 chance; // 0% = effect certain, primary effect }; @@ -885,6 +907,7 @@ u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg); u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg); bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method); u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove); +void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); bool32 SpeciesHasGenderDifferences(u16 species); bool32 TryFormChange(u32 monId, u32 side, u16 method); void TryToSetBattleFormChangeMoves(struct Pokemon *mon, u16 method); diff --git a/include/recorded_battle.h b/include/recorded_battle.h index c64a665b74..0945eefe92 100644 --- a/include/recorded_battle.h +++ b/include/recorded_battle.h @@ -2,6 +2,7 @@ #define GUARD_RECORDED_BATTLE_H #include "constants/battle.h" +#include "link.h" #include "random.h" #define BATTLER_RECORD_SIZE 664 @@ -10,13 +11,13 @@ struct RecordedBattleSave { struct Pokemon playerParty[PARTY_SIZE]; struct Pokemon opponentParty[PARTY_SIZE]; - u8 playersName[MAX_BATTLERS_COUNT][PLAYER_NAME_LENGTH + 1]; - u8 playersGender[MAX_BATTLERS_COUNT]; - u32 playersTrainerId[MAX_BATTLERS_COUNT]; - u8 playersLanguage[MAX_BATTLERS_COUNT]; + u8 playersName[MAX_LINK_PLAYERS][PLAYER_NAME_LENGTH + 1]; + u8 playersGender[MAX_LINK_PLAYERS]; + u32 playersTrainerId[MAX_LINK_PLAYERS]; + u8 playersLanguage[MAX_LINK_PLAYERS]; rng_value_t rngSeed; u32 battleFlags; - u8 playersBattlers[MAX_BATTLERS_COUNT]; + u8 playersBattlers[MAX_LINK_PLAYERS]; u16 opponentA; u16 opponentB; u16 partnerId; diff --git a/include/test/test.h b/include/test/test.h index 1a9d8a237e..ccfc589c21 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -95,7 +95,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...); #define ASSUMPTIONS \ static void Assumptions(void); \ - __attribute__((section(".tests"), used)) static const struct Test sAssumptions = \ + __attribute__((section(".tests"), used, no_reorder)) static const struct Test sAssumptions = \ { \ .name = "ASSUMPTIONS: " __FILE__, \ .filename = __FILE__, \ diff --git a/src/AgbRfu_LinkManager.c b/src/AgbRfu_LinkManager.c index d696c01d3c..b53b69c48b 100644 --- a/src/AgbRfu_LinkManager.c +++ b/src/AgbRfu_LinkManager.c @@ -59,7 +59,9 @@ void rfu_LMAN_REQ_sendData(bool8 clockChangeFlag) clockChangeFlag = FALSE; } else + { lman.parentAck_flag = 0; + } rfu_REQ_sendData(clockChangeFlag); } diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 033599154e..83182fe07c 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -433,7 +433,7 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3 if (move != 0 && move != 0xFFFF - //&& gMovesInfo[move].power != 0 /* we want to get effectiveness and accuracy of status moves */ + //&& !IS_MOVE_STATUS(gMovesInfo[move]) /* we want to get effectiveness and accuracy of status moves */ && !(aiData->moveLimitations[battlerAtk] & (1u << moveIndex))) { dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, rollType); @@ -2523,8 +2523,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-4); break; //TODO - //case EFFECT_PLASMA_FISTS: - //break; //case EFFECT_SHELL_TRAP: //break; //case EFFECT_BEAK_BLAST: @@ -2619,8 +2617,8 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) return score; - if (gMovesInfo[move].power == 0) - return score; // can't make anything faint with no power + if (IS_MOVE_STATUS(move)) + return score; // status moves aren't accounted here if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gMovesInfo[move].effect != EFFECT_EXPLOSION) { @@ -4327,7 +4325,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) ADJUST_SCORE(DECENT_EFFECT); break; case EFFECT_SOAK: - if (HasMoveWithType(battlerAtk, TYPE_ELECTRIC) || HasMoveWithType(battlerAtk, TYPE_GRASS) || (HasMoveEffect(battlerAtk, EFFECT_SUPER_EFFECTIVE_ON_ARG) && gMovesInfo[move].argument == TYPE_WATER) ) + if (HasMoveWithType(battlerAtk, TYPE_ELECTRIC) || HasMoveWithType(battlerAtk, TYPE_GRASS) || (HasMoveEffect(battlerAtk, EFFECT_SUPER_EFFECTIVE_ON_ARG) && gMovesInfo[move].argument.type == TYPE_WATER) ) ADJUST_SCORE(DECENT_EFFECT); // Get some super effective moves break; case EFFECT_THIRD_TYPE: @@ -4437,10 +4435,6 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) || gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & STATUS1_ANY) ADJUST_SCORE(GOOD_EFFECT); break; - case EFFECT_SALT_CURE: - if (IS_BATTLER_ANY_TYPE(battlerDef, TYPE_WATER, TYPE_STEEL)) - ADJUST_SCORE(DECENT_EFFECT); - break; } // move effect checks // check move additional effects that are likely to happen @@ -4685,6 +4679,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (!HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move)) ADJUST_SCORE(BEST_EFFECT); break; + case MOVE_EFFECT_SALT_CURE: + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_WATER) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL)) + ADJUST_SCORE(DECENT_EFFECT); + break; + } } } @@ -4937,7 +4936,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor { if (IS_TARGETING_PARTNER(battlerAtk, battlerDef) || CountUsablePartyMons(battlerAtk) == 0 - || gMovesInfo[move].power != 0 + || !IS_MOVE_STATUS(move) || !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS) || IsBattlerTrapped(battlerAtk, TRUE)) return score; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index fd09421ef3..5547351ec1 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -122,8 +122,8 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) hasStatusMove = TRUE; } - // Only check damage if move has power - if (gMovesInfo[aiMove].power != 0) + // Only check damage if it's a damaging move + if (!IS_MOVE_STATUS(aiMove)) { // Check if mon has a super effective move if (AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) >= AI_EFFECTIVENESS_x2) @@ -156,7 +156,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) for (i = 0; i < MAX_MON_MOVES; i++) { playerMove = gBattleMons[opposingBattler].moves[i]; - if (playerMove != MOVE_NONE && gMovesInfo[playerMove].power != 0) + if (playerMove != MOVE_NONE && !IS_MOVE_STATUS(playerMove)) { damageTaken = AI_CalcDamage(playerMove, opposingBattler, battler, &effectiveness, FALSE, weather, DMG_ROLL_HIGHEST).expected; if (damageTaken > maxDamageTaken) @@ -1242,7 +1242,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva for (j = 0; j < MAX_MON_MOVES; j++) { aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; - if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0) + if (aiMove != MOVE_NONE && !IS_MOVE_STATUS(aiMove)) { aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j); dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, rollType); @@ -1698,7 +1698,7 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle for (i = 0; i < MAX_MON_MOVES; i++) { playerMove = gBattleMons[opposingBattler].moves[i]; - if (playerMove != MOVE_NONE && gMovesInfo[playerMove].power != 0) + if (playerMove != MOVE_NONE && !IS_MOVE_STATUS(playerMove)) { damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, FALSE, DMG_ROLL_HIGHEST); if (damageTaken > maxDamageTaken) @@ -1826,7 +1826,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, { aiMove = AI_DATA->switchinCandidate.battleMon.moves[j]; - if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0) + if (aiMove != MOVE_NONE && !IS_MOVE_STATUS(aiMove)) { if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_CONSERVATIVE) damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_LOWEST); @@ -1856,7 +1856,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, } // Check for mon with resistance and super effective move for best type matchup mon with effective move - if (aiMove != MOVE_NONE && gMovesInfo[aiMove].power != 0) + if (aiMove != MOVE_NONE && !IS_MOVE_STATUS(aiMove)) { if (typeMatchup < bestResistEffective) { diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 0edef28450..dd1cd296da 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -470,11 +470,11 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy return TRUE; break; case EFFECT_FAIL_IF_NOT_ARG_TYPE: - if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[move].argument)) + if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[move].argument.type)) return TRUE; break; case EFFECT_HIT_SET_REMOVE_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && gMovesInfo[move].argument == ARG_TRY_REMOVE_TERRAIN_FAIL) + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && gMovesInfo[move].argument.moveProperty == ARG_TRY_REMOVE_TERRAIN_FAIL) return TRUE; break; case EFFECT_POLTERGEIST: @@ -566,7 +566,7 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal expected = minimum = gBattleMons[damageCalcData->battlerAtk].level * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_FIXED_DAMAGE_ARG: - expected = minimum = gMovesInfo[move].argument * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1); + expected = minimum = gMovesInfo[move].argument.fixedDamage * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1); break; case EFFECT_MULTI_HIT: if (move == MOVE_WATER_SHURIKEN && gBattleMons[damageCalcData->battlerAtk].species == SPECIES_GRENINJA_ASH) @@ -2027,7 +2027,7 @@ bool32 HasMoveEffect(u32 battlerId, u32 effect) return FALSE; } -bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument) +bool32 IsPowerBasedOnStatus(u32 battlerId, u32 effect, u32 argument) { s32 i; u16 *moves = GetMovesArray(battlerId); @@ -2036,7 +2036,7 @@ bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument) { if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].effect == effect - && (gMovesInfo[moves[i]].argument & argument)) + && (gMovesInfo[moves[i]].argument.status & argument)) return TRUE; } @@ -2419,7 +2419,7 @@ bool32 HasDamagingMove(u32 battlerId) for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].power != 0) + if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !IS_MOVE_STATUS(moves[i])) return TRUE; } @@ -2434,7 +2434,7 @@ bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE - && gMovesInfo[moves[i]].type == type && gMovesInfo[moves[i]].power != 0) + && gMovesInfo[moves[i]].type == type && !IS_MOVE_STATUS(moves[i])) return TRUE; } @@ -2477,7 +2477,7 @@ bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move) case EFFECT_SOLAR_BEAM: case EFFECT_TWO_TURNS_ATTACK: return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB - || (AI_GetWeather(AI_DATA) & gMovesInfo[move].argument)); + || (AI_GetWeather(AI_DATA) & gMovesInfo[move].argument.twoTurnAttack.status)); default: return FALSE; } @@ -3229,7 +3229,7 @@ bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage) if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move)) { // using item or user goes first - u32 healPercent = (gMovesInfo[move].argument == 0) ? 50 : gMovesInfo[move].argument; + u32 healPercent = (gMovesInfo[move].argument.absorbPercentage == 0) ? 50 : gMovesInfo[move].argument.absorbPercentage; s32 healDmg = (healPercent * damage) / 100; if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) @@ -3847,7 +3847,7 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT)) ADJUST_SCORE_PTR(WEAK_EFFECT); // stall tactic - if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY) + if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY) || HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH) || AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS) ADJUST_SCORE_PTR(DECENT_EFFECT); @@ -3874,8 +3874,8 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) ADJUST_SCORE_PTR(WEAK_EFFECT); } - if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN) - || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN)) + if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN) + || IsPowerBasedOnStatus(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN)) ADJUST_SCORE_PTR(WEAK_EFFECT); } } @@ -3892,7 +3892,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) u32 defSpeed = AI_DATA->speedStats[battlerDef]; if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe - || HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS) + || IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS) || (HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY)) // filter out Fake Out || gBattleMons[battlerDef].status2 & STATUS2_INFATUATION || gBattleMons[battlerDef].status2 & STATUS2_CONFUSION) @@ -3917,8 +3917,8 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) && !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK))) ADJUST_SCORE_PTR(WEAK_EFFECT); - if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP) - || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP)) + if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP) + || IsPowerBasedOnStatus(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP)) ADJUST_SCORE_PTR(WEAK_EFFECT); } @@ -3958,8 +3958,8 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score ADJUST_SCORE_PTR(WEAK_EFFECT); } - if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE) - || HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE)) + if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE) + || IsPowerBasedOnStatus(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE)) ADJUST_SCORE_PTR(WEAK_EFFECT); } } diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index d5efe499eb..a3104122d1 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -5413,7 +5413,9 @@ static void AnimMilkBottle_Step1(struct Sprite *sprite) sprite->data[6]++; } else if (sprite->data[7] > 0) + { sprite->data[7]--; + } SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(sprite->data[6], sprite->data[7])); if (sprite->data[6] == 16 && sprite->data[7] == 0) @@ -6642,6 +6644,79 @@ static void ReloadBattlerSprites(u32 battler, struct Pokemon *party) } } +static void TrySwapSkyDropTargets(u32 battlerAtk, u32 battlerPartner) +{ + u32 i, temp; + + // battlerAtk is using Ally Switch + // check if our partner is the target of sky drop + // If so, change that index to battlerAtk + for (i = 0; i < gBattlersCount; i++) { + if (gBattleStruct->skyDropTargets[i] == battlerPartner) { + gBattleStruct->skyDropTargets[i] = battlerAtk; + break; + } + } + + // Then swap our own sky drop targets with the partner in case our partner is mid-skydrop + SWAP(gBattleStruct->skyDropTargets[battlerAtk], gBattleStruct->skyDropTargets[battlerPartner], temp); +} + +#define TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, side, field) \ + if (gSideTimers[side].field == battlerAtk) \ + gSideTimers[side].field = battlerPartner; \ + else if (gSideTimers[side].field == battlerPartner) \ + gSideTimers[side].field = battlerAtk; + +static void TrySwapStickyWebBattlerId(u32 battlerAtk, u32 battlerPartner) +{ + u32 atkSide = GetBattlerSide(battlerAtk); + u32 oppSide = GetBattlerSide(BATTLE_OPPOSITE(battlerAtk)); + + // not all of these are needed to be swapped, but are done so to be robust to anything in the future that might care about them + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, reflectBattlerId); + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, lightscreenBattlerId); + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, mistBattlerId); + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, safeguardBattlerId); + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, auroraVeilBattlerId); + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, tailwindBattlerId); + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, atkSide, luckyChantBattlerId); + + // if we've set sticky web on the opposing side, need to swap stickyWebBattlerId for mirror armor + TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, oppSide, stickyWebBattlerId); +} +#undef TRY_SIDE_TIMER_BATTLER_ID_SWAP + +static void TrySwapWishBattlerIds(u32 battlerAtk, u32 battlerPartner) +{ + u32 i, temp; + u32 oppSide = GetBattlerSide(BATTLE_OPPOSITE(battlerAtk)); + + // if used future sight on opposing side, properly track who used it + if (gSideStatuses[oppSide] & SIDE_STATUS_FUTUREATTACK) { + for (i = 0; i < gBattlersCount; i++) { + if (IsAlly(i,battlerAtk)) + continue; // only on opposing side + if (gWishFutureKnock.futureSightBattlerIndex[i] == battlerAtk) { + // if target was attacked with future sight from us, now they'll be the partner slot + gWishFutureKnock.futureSightBattlerIndex[i] = battlerPartner; + gWishFutureKnock.futureSightPartyIndex[i] = gBattlerPartyIndexes[battlerPartner]; + break; + } else if (gWishFutureKnock.futureSightBattlerIndex[i] == battlerPartner) { + gWishFutureKnock.futureSightBattlerIndex[i] = battlerAtk; + gWishFutureKnock.futureSightPartyIndex[i] = gBattlerPartyIndexes[battlerAtk]; + break; + } + } + } + + // swap wish party indices + if (gWishFutureKnock.wishCounter[battlerAtk] > 0 + || gWishFutureKnock.wishCounter[battlerPartner] > 0) { + SWAP(gWishFutureKnock.wishPartyId[battlerAtk], gWishFutureKnock.wishPartyId[battlerPartner], temp); + } +} + static void AnimTask_AllySwitchDataSwap(u8 taskId) { s32 i, j; @@ -6661,6 +6736,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) SwapStructData(&gSpecialStatuses[battlerAtk], &gSpecialStatuses[battlerPartner], data, sizeof(struct SpecialStatus)); SwapStructData(&gProtectStructs[battlerAtk], &gProtectStructs[battlerPartner], data, sizeof(struct ProtectStruct)); SwapStructData(&gBattleSpritesDataPtr->battlerData[battlerAtk], &gBattleSpritesDataPtr->battlerData[battlerPartner], data, sizeof(struct BattleSpriteInfo)); + SwapStructData(&gBattleStruct->illusion[battlerAtk], &gBattleStruct->illusion[battlerPartner], data, sizeof(struct Illusion)); SWAP(gBattleSpritesDataPtr->battlerData[battlerAtk].invisible, gBattleSpritesDataPtr->battlerData[battlerPartner].invisible, temp); SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp); @@ -6684,6 +6760,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) break; } SWAP(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], temp); + SWAP(gActionsByTurnOrder[i], gActionsByTurnOrder[j], temp); break; } } @@ -6692,6 +6769,10 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId) SwitchTwoBattlersInParty(battlerAtk, battlerPartner); SWAP(gBattlerPartyIndexes[battlerAtk], gBattlerPartyIndexes[battlerPartner], temp); + TrySwapSkyDropTargets(battlerAtk, battlerPartner); + TrySwapStickyWebBattlerId(battlerAtk, battlerPartner); + TrySwapWishBattlerIds(battlerAtk, battlerPartner); + // For Snipe Shot and abilities Stalwart/Propeller Tail - keep the original target. for (i = 0; i < MAX_BATTLERS_COUNT; i++) { diff --git a/src/battle_anim_effects_2.c b/src/battle_anim_effects_2.c index 0a94cad2dc..e751a1ca51 100755 --- a/src/battle_anim_effects_2.c +++ b/src/battle_anim_effects_2.c @@ -2266,7 +2266,9 @@ static void AnimTask_Splash_Step(u8 taskId) task->data[4] -= 2; } else + { task->data[1]++; + } break; case 3: if (!RunAffineAnimFromTaskData(task)) @@ -3023,7 +3025,9 @@ static void AnimTask_SpeedDust_Step(u8 taskId) task->data[8] = 1; } else + { task->data[8] = 2; + } } } break; diff --git a/src/battle_anim_electric.c b/src/battle_anim_electric.c index 929dc972f0..6e7c1c1e0c 100644 --- a/src/battle_anim_electric.c +++ b/src/battle_anim_electric.c @@ -742,7 +742,9 @@ static void AnimZapCannonSpark_Step(struct Sprite *sprite) sprite->invisible ^= 1; } else + { DestroyAnimSprite(sprite); + } } static void AnimThunderboltOrb_Step(struct Sprite *sprite) @@ -1024,7 +1026,9 @@ static void AnimTask_ElectricChargingParticles_Step(u8 taskId) } } else if(task->data[7] == 0) + { DestroyAnimVisualTask(taskId); + } } static void AnimElectricChargingParticles_Step(struct Sprite *sprite) @@ -1145,7 +1149,9 @@ void AnimTask_VoltTackleAttackerReappear(u8 taskId) gSprites[task->data[15]].x2 = task->data[14]; } else + { task->data[0]++; + } } break; diff --git a/src/battle_anim_ghost.c b/src/battle_anim_ghost.c index e583e44635..f848cd794a 100644 --- a/src/battle_anim_ghost.c +++ b/src/battle_anim_ghost.c @@ -346,7 +346,9 @@ static void AnimConfuseRayBallBounce_Step2(struct Sprite *sprite) sprite->callback = DestroyAnimSpriteAndDisableBlend; } else + { UpdateConfuseRayBallBlend(sprite); + } } static void UpdateConfuseRayBallBlend(struct Sprite *sprite) diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 50bb83305f..38597b19b3 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -9244,7 +9244,7 @@ void AnimTask_DynamaxGrowth(u8 taskId) // from CFRU void AnimTask_GetWeatherToSet(u8 taskId) { - switch (gMovesInfo[gCurrentMove].argument) + switch (gMovesInfo[gCurrentMove].argument.maxEffect) { case MAX_EFFECT_SUN: gBattleAnimArgs[ARG_RET_ID] = 1; diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index 611d12be56..a8c6e4077e 100644 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -1339,7 +1339,9 @@ static void SpriteCB_Ball_Wobble_Step(struct Sprite *sprite) gBattleSpritesDataPtr->animationData->ballSubpx &= 0xFF; } else + { gBattleSpritesDataPtr->animationData->ballSubpx += 176; + } sprite->sTimer++; sprite->affineAnimPaused = FALSE; @@ -1364,7 +1366,9 @@ static void SpriteCB_Ball_Wobble_Step(struct Sprite *sprite) ChangeSpriteAffineAnim(sprite, BALL_ROTATE_RIGHT); } else + { sprite->affineAnimPaused = TRUE; + } break; case BALL_ROLL_2: if (gBattleSpritesDataPtr->animationData->ballSubpx > 255) @@ -1373,7 +1377,9 @@ static void SpriteCB_Ball_Wobble_Step(struct Sprite *sprite) gBattleSpritesDataPtr->animationData->ballSubpx &= 0xFF; } else + { gBattleSpritesDataPtr->animationData->ballSubpx += 176; + } sprite->sTimer++; sprite->affineAnimPaused = FALSE; @@ -1408,7 +1414,9 @@ static void SpriteCB_Ball_Wobble_Step(struct Sprite *sprite) gBattleSpritesDataPtr->animationData->ballSubpx &= 0xFF; } else + { gBattleSpritesDataPtr->animationData->ballSubpx += 176; + } sprite->sTimer++; sprite->affineAnimPaused = FALSE; @@ -1598,7 +1606,9 @@ static void SpriteCB_Ball_FadeOut(struct Sprite *sprite) static void DestroySpriteAfterOneFrame(struct Sprite *sprite) { if (sprite->sFrame == 0) + { sprite->sFrame = -1; + } else { FreeSpriteOamMatrix(sprite); @@ -1618,7 +1628,9 @@ static void MakeCaptureStars(struct Sprite *sprite) u8 subpriority; if (sprite->subpriority) + { subpriority = sprite->subpriority - 1; + } else { subpriority = 0; @@ -2555,7 +2567,9 @@ static void SpriteCB_ShinyStars_Diagonal(struct Sprite *sprite) { // Delayed four frames to de-sync from encircling stars if (sprite->sTimer < 4) + { sprite->sTimer++; + } else { sprite->invisible = FALSE; diff --git a/src/battle_arena.c b/src/battle_arena.c index 6d34278f86..4a6df309b5 100644 --- a/src/battle_arena.c +++ b/src/battle_arena.c @@ -360,7 +360,7 @@ void BattleArena_AddMindPoints(u8 battler) // All moves with power != 0 give 1 point, with the following exceptions: // - Counter, Mirror Coat, and Bide give 0 points // - Fake Out subtracts 1 point -// All moves with power == 0 give 0 points, with the following exceptions: +// All status moves give 0 points, with the following exceptions: // - Protect, Detect, and Endure subtract 1 point if (gMovesInfo[gCurrentMove].effect == EFFECT_FIRST_TURN_ONLY @@ -369,7 +369,7 @@ void BattleArena_AddMindPoints(u8 battler) { gBattleStruct->arenaMindPoints[battler]--; } - else if (gMovesInfo[gCurrentMove].power != 0 + else if (!IS_MOVE_STATUS(gCurrentMove) && gMovesInfo[gCurrentMove].effect != EFFECT_COUNTER && gMovesInfo[gCurrentMove].effect != EFFECT_MIRROR_COAT && gMovesInfo[gCurrentMove].effect != EFFECT_METAL_BURST diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index b6ffd67b75..2fbf8cf69f 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -185,7 +185,9 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); } else + { return; + } } else if (gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim) { @@ -198,13 +200,17 @@ static void Intro_WaitForShinyAnimAndHealthbox(u32 battler) FreeSpritePaletteByTag(ANIM_TAG_GOLD_STARS); } else + { return; + } } - gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; - gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; + gBattleSpritesDataPtr->healthBoxesData[battler].triedShinyMonAnim = FALSE; + gBattleSpritesDataPtr->healthBoxesData[battler].finishedShinyMonAnim = FALSE; } else + { return; + } gBattleSpritesDataPtr->healthBoxesData[battler].introEndDelay = 3; gBattlerControllerFuncs[battler] = Intro_DelayAndEnd; @@ -274,7 +280,9 @@ static void Intro_TryShinyAnimShowHealthbox(u32 battler) m4aMPlayContinue(&gMPlayInfo_BGM); } else + { m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 0x100); + } } gBattleSpritesDataPtr->healthBoxesData[battler].bgmRestored = TRUE; bgmRestored = TRUE; diff --git a/src/battle_dome.c b/src/battle_dome.c index 1d79333290..8b376c7e75 100644 --- a/src/battle_dome.c +++ b/src/battle_dome.c @@ -4326,7 +4326,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId) allocatedArray[k] = IsDomeStatusMoveEffect(move); break; case MOVE_POINTS_DMG: - allocatedArray[k] = (gMovesInfo[move].power != 0) ? 1 : 0; + allocatedArray[k] = (!IS_MOVE_STATUS(move)) ? 1 : 0; break; case MOVE_POINTS_DEF: allocatedArray[k] = IsDomeDefensiveMoveEffect(gMovesInfo[move].effect) ? 1 : 0; @@ -5108,7 +5108,7 @@ static u16 GetWinningMove(int winnerTournamentId, int loserTournamentId, u8 roun moveIds[i * MAX_MON_MOVES + j] = gFacilityTrainerMons[DOME_MONS[winnerTournamentId][i]].moves[j]; movePower = gMovesInfo[moveIds[i * MAX_MON_MOVES + j]].power; - if (movePower == 0) + if (IS_MOVE_STATUS(moveIds[i * MAX_MON_MOVES + j])) movePower = 40; else if (movePower == 1) movePower = 60; diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index 0c858c4179..f5c07f4e8e 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -320,7 +320,7 @@ u8 GetMaxMovePower(u32 move) { u8 tier; // G-Max Drum Solo, G-Max Hydrosnipe, and G-Max Fireball always have 160 base power. - if (gMovesInfo[GetMaxMove(gBattlerAttacker, move)].argument == MAX_EFFECT_FIXED_POWER) + if (gMovesInfo[GetMaxMove(gBattlerAttacker, move)].argument.maxEffect == MAX_EFFECT_FIXED_POWER) return 160; // Exceptions to all other rules below: @@ -470,7 +470,7 @@ void ChooseDamageNonTypesString(u8 type) // Returns the status effect that should be applied by a G-Max Move. static u32 GetMaxMoveStatusEffect(u32 move) { - u8 maxEffect = gMovesInfo[move].argument; + u8 maxEffect = gMovesInfo[move].argument.maxEffect; switch (maxEffect) { // Status 1 @@ -522,7 +522,7 @@ void BS_SetMaxMoveEffect(void) { NATIVE_ARGS(); u16 effect = 0; - u8 maxEffect = gMovesInfo[gCurrentMove].argument; + u8 maxEffect = gMovesInfo[gCurrentMove].argument.maxEffect; // Don't continue if the move didn't land. if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) @@ -541,7 +541,7 @@ void BS_SetMaxMoveEffect(void) if (!NoAliveMonsForEitherParty()) { // Max Effects are ordered by stat ID. - SET_STATCHANGER(gMovesInfo[gCurrentMove].argument, 1, FALSE); + SET_STATCHANGER(gMovesInfo[gCurrentMove].argument.maxEffect, 1, FALSE); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; effect++; @@ -569,7 +569,7 @@ void BS_SetMaxMoveEffect(void) break; default: // Max Effects are ordered by stat ID. - statId = gMovesInfo[gCurrentMove].argument - MAX_EFFECT_LOWER_ATTACK + 1; + statId = gMovesInfo[gCurrentMove].argument.maxEffect - MAX_EFFECT_LOWER_ATTACK + 1; break; } SET_STATCHANGER(statId, stage, TRUE); @@ -618,7 +618,7 @@ void BS_SetMaxMoveEffect(void) case MAX_EFFECT_PSYCHIC_TERRAIN: { u32 statusFlag = 0; - switch (gMovesInfo[gCurrentMove].argument) + switch (gMovesInfo[gCurrentMove].argument.moveProperty) { case MAX_EFFECT_MISTY_TERRAIN: statusFlag = STATUS_FIELD_MISTY_TERRAIN; diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index e2a583dcc9..611c1bec59 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -754,13 +754,21 @@ bool8 BattleLoadAllHealthBoxesGfx(u8 state) LoadCompressedSpriteSheet(&sSpriteSheet_SinglesPlayerHealthbox); } else if (state == 3) + { LoadCompressedSpriteSheet(&sSpriteSheet_SinglesOpponentHealthbox); + } else if (state == 4) + { LoadCompressedSpriteSheet(&sSpriteSheets_HealthBar[GetBattlerPosition(0)]); + } else if (state == 5) + { LoadCompressedSpriteSheet(&sSpriteSheets_HealthBar[GetBattlerPosition(1)]); + } else + { retVal = TRUE; + } } else { diff --git a/src/battle_main.c b/src/battle_main.c index 7c02c7abcf..c23fc30040 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1517,7 +1517,9 @@ static void CB2_HandleStartMultiBattle(void) gBattleCommunication[MULTIUSE_STATE]++; } else + { break; + } // fall through case 3: if (IsLinkTaskFinished()) @@ -3228,6 +3230,13 @@ void SwitchInClearSetData(u32 battler) gBattleStruct->boosterEnergyActivates &= ~(1u << battler); gBattleStruct->canPickupItem &= ~(1u << battler); + if (gBattleStruct->pursuitTarget & (1u << battler)) + { + gBattleStruct->pursuitTarget = 0; + gBattleStruct->pursuitSwitchByMove = FALSE; + gBattleStruct->pursuitStoredSwitch = 0; + } + for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) { // Switched into sticky web user slot, so reset stored battler ID @@ -3358,9 +3367,13 @@ const u8* FaintClearSetData(u32 battler) gBattleStruct->lastTakenMoveFrom[battler][1] = 0; gBattleStruct->lastTakenMoveFrom[battler][2] = 0; gBattleStruct->lastTakenMoveFrom[battler][3] = 0; - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; + + if (gBattleStruct->pursuitTarget & (1u << battler)) + { + gBattleStruct->pursuitTarget = 0; + gBattleStruct->pursuitSwitchByMove = FALSE; + gBattleStruct->pursuitStoredSwitch = 0; + } gBattleStruct->palaceFlags &= ~(1u << battler); gBattleStruct->boosterEnergyActivates &= ~(1u << battler); @@ -4844,7 +4857,7 @@ s8 GetMovePriority(u32 battler, u16 move) s8 priority; u16 ability = GetBattlerAbility(battler); - if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE && gMovesInfo[move].power != 0) + if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(move)) move = GetUsableZMove(battler, move); priority = gMovesInfo[move].priority; @@ -5944,7 +5957,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost) } break; case EFFECT_CHANGE_TYPE_ON_ITEM: - if (holdEffect == gMovesInfo[move].argument) + if (holdEffect == gMovesInfo[move].argument.holdEffect) return ItemId_GetSecondaryId(heldItem); break; case EFFECT_REVELATION_DANCE: diff --git a/src/battle_message.c b/src/battle_message.c index 8eae346b2d..8cb7092156 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -703,7 +703,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_NOONEWILLBEABLETORUNAWAY] = COMPOUND_STRING("No one will be able to run away during the next turn!"), [STRINGID_DESTINYKNOTACTIVATES] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} fell in love because of the {B_LAST_ITEM}!"), [STRINGID_CLOAKEDINAFREEZINGLIGHT] = COMPOUND_STRING("{B_ATK_NAME_WITH_PREFIX} became cloaked in a freezing light!"), - [STRINGID_CLEARAMULETWONTLOWERSTATS] = COMPOUND_STRING("The effects of the {B_LAST_ITEM} held by {B_DEF_NAME_WITH_PREFIX2} prevents its stats from being lowered!"), + [STRINGID_CLEARAMULETWONTLOWERSTATS] = COMPOUND_STRING("The effects of the {B_LAST_ITEM} held by {B_SCR_NAME_WITH_PREFIX2} prevents its stats from being lowered!"), [STRINGID_FERVENTWISHREACHED] = COMPOUND_STRING("{B_ATK_TRAINER_NAME}'s fervent wish has reached {B_ATK_NAME_WITH_PREFIX2}!"), [STRINGID_AIRLOCKACTIVATES] = COMPOUND_STRING("The effects of the weather disappeared."), [STRINGID_PRESSUREENTERS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} is exerting its pressure!"), @@ -1277,7 +1277,10 @@ const u16 gWeatherStartsStringIds[] = const u16 gTerrainStartsStringIds[] = { - STRINGID_MISTSWIRLSAROUND, STRINGID_ELECTRICCURRENTISRUNNING, STRINGID_ISCOVEREDWITHGRASS, STRINGID_SEEMSWEIRD, + [B_MSG_TERRAIN_SET_MISTY] = STRINGID_MISTSWIRLSAROUND, + [B_MSG_TERRAIN_SET_ELECTRIC] = STRINGID_ELECTRICCURRENTISRUNNING, + [B_MSG_TERRAIN_SET_PSYCHIC] = STRINGID_SEEMSWEIRD, + [B_MSG_TERRAIN_SET_GRASSY] = STRINGID_ISCOVEREDWITHGRASS, }; const u16 gPrimalWeatherBlocksStringIds[] = @@ -2630,7 +2633,9 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst, u32 dstSize) toCpy = gStringVar2; } else + { toCpy = gBattleTextBuff2; + } break; case B_TXT_BUFF3: if (gBattleTextBuff3[0] == B_BUFF_PLACEHOLDER_BEGIN) @@ -2639,7 +2644,9 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst, u32 dstSize) toCpy = gStringVar3; } else + { toCpy = gBattleTextBuff3; + } break; case B_TXT_COPY_VAR_1: toCpy = gStringVar1; @@ -2752,7 +2759,9 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst, u32 dstSize) toCpy = text; } else + { toCpy = sText_EnigmaBerry; + } } } else diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f6a7da6cf1..1f8b42801d 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1126,19 +1126,6 @@ static bool32 NoTargetPresent(u8 battler, u32 move) return FALSE; } -static bool32 TryFormChangeBeforeMove(void) -{ - bool32 result = TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_BEFORE_MOVE); - if (!result) - result = TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY); - if (!result) - return FALSE; - - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_AttackerFormChange; - return TRUE; -} - bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) { if ((ability == ABILITY_PROTEAN || ability == ABILITY_LIBERO) @@ -1177,8 +1164,6 @@ static void Cmd_attackcanceler(void) CMD_ARGS(); s32 i; - u16 attackerAbility = GetBattlerAbility(gBattlerAttacker); - u32 moveType = GetMoveType(gCurrentMove); if (gBattleStruct->usedEjectItem & (1u << gBattlerAttacker)) { @@ -1187,14 +1172,6 @@ static void Cmd_attackcanceler(void) return; } - // Weight-based moves are blocked by Dynamax. - if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove)) - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveBlockedByDynamax; - return; - } - if (gBattleOutcome != 0) { gCurrentActionFuncId = B_ACTION_FINISHED; @@ -1207,28 +1184,8 @@ static void Cmd_attackcanceler(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; return; } - if (B_STANCE_CHANGE_FAIL < GEN_7 && TryFormChangeBeforeMove()) + if (AtkCanceller_MoveSuccessOrder()) return; - if (AtkCanceller_UnableToUseMove(moveType)) - return; - - if (WEATHER_HAS_EFFECT && gMovesInfo[gCurrentMove].power) - { - if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove; - return; - } - else if (moveType == TYPE_WATER && (gBattleWeather & B_WEATHER_SUN_PRIMAL)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_EVAPORATED_IN_SUN; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove; - return; - } - } if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF && GetBattlerAbility(gBattlerAttacker) == ABILITY_PARENTAL_BOND @@ -1242,22 +1199,6 @@ static void Cmd_attackcanceler(void) return; } - // Check Protean activation. - if (ProteanTryChangeType(gBattlerAttacker, attackerAbility, gCurrentMove, moveType)) - { - if (B_PROTEAN_LIBERO == GEN_9) - gDisableStructs[gBattlerAttacker].usedProteanLibero = TRUE; - PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); - gBattlerAbility = gBattlerAttacker; - BattleScriptPushCursor(); - PrepareStringBattle(STRINGID_EMPTYSTRING3, gBattlerAttacker); - gBattleCommunication[MSG_DISPLAY] = 1; - gBattlescriptCurrInstr = BattleScript_ProteanActivates; - return; - } - - if (AtkCanceller_UnableToUseMove2()) - return; if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBattlerTarget, 0, 0, 0)) return; if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE @@ -1268,8 +1209,6 @@ static void Cmd_attackcanceler(void) gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; return; } - if (B_STANCE_CHANGE_FAIL >= GEN_7 && TryFormChangeBeforeMove()) - return; gHitMarker &= ~HITMARKER_ALLOW_NO_PP; @@ -2503,7 +2442,9 @@ static void Cmd_attackanimation(void) { u32 multihit; if (gBattleMons[gBattlerTarget].status2 & STATUS2_SUBSTITUTE) + { multihit = gMultiHitCounter; + } else if (gMultiHitCounter != 0 && gMultiHitCounter != 1) { if (gBattleMons[gBattlerTarget].hp <= gBattleStruct->moveDamage[gBattlerTarget]) @@ -2512,7 +2453,9 @@ static void Cmd_attackanimation(void) multihit = gMultiHitCounter; } else + { multihit = gMultiHitCounter; + } BtlController_EmitMoveAnimation(gBattlerAttacker, BUFFER_A, @@ -3133,17 +3076,26 @@ static void CheckSetUnburden(u8 battler) void StealTargetItem(u8 battlerStealer, u8 battlerItem) { gLastUsedItem = gBattleMons[battlerItem].item; - gBattleMons[battlerItem].item = 0; + gBattleMons[battlerItem].item = ITEM_NONE; - RecordItemEffectBattle(battlerItem, 0); - RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem)); - gBattleMons[battlerStealer].item = gLastUsedItem; + if (B_STEAL_WILD_ITEMS >= GEN_9 + && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE)) + && MoveHasAdditionalEffect(gCurrentMove, MOVE_EFFECT_STEAL_ITEM) + && battlerStealer == gBattlerAttacker) // ensure that Pickpocket isn't activating this + { + AddBagItem(gLastUsedItem, 1); + } + else + { + RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem)); + gBattleMons[battlerStealer].item = gLastUsedItem; + gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN; + BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item + MarkBattlerForControllerExec(battlerStealer); + } + RecordItemEffectBattle(battlerItem, ITEM_NONE); CheckSetUnburden(battlerItem); - gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN; - - BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item - MarkBattlerForControllerExec(battlerStealer); BtlController_EmitSetMonData(battlerItem, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item MarkBattlerForControllerExec(battlerItem); @@ -3172,7 +3124,8 @@ void SetMoveEffect(bool32 primary, bool32 certain) bool32 statusChanged = FALSE; bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); u32 flags = 0; - u16 battlerAbility; + u32 battlerAbility; + u32 side; bool8 activateAfterFaint = FALSE; // NULL move effect @@ -3395,7 +3348,9 @@ void SetMoveEffect(bool32 primary, bool32 certain) RESET_RETURN } else + { break; + } } if (B_STATUS_TYPE_IMMUNITY == GEN_1) { @@ -3826,8 +3781,13 @@ void SetMoveEffect(bool32 primary, bool32 certain) else { StealTargetItem(gBattlerAttacker, gBattlerTarget); // Attacker steals target item - gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS) - gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later + + if (!(B_STEAL_WILD_ITEMS >= GEN_9 + && !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_PALACE)))) + { + gBattleMons[gBattlerAttacker].item = ITEM_NONE; // Item assigned later on with thief (see MOVEEND_CHANGED_ITEMS) + gBattleStruct->changedItems[gBattlerAttacker] = gLastUsedItem; // Stolen item to be assigned later + } BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_ItemSteal; } @@ -4050,7 +4010,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) case MOVE_EFFECT_REMOVE_ARG_TYPE: // This seems unnecessary but is done to make it work properly with Parental Bond BattleScriptPush(gBattlescriptCurrInstr + 1); - switch (gMovesInfo[gCurrentMove].argument) + switch (gMovesInfo[gCurrentMove].argument.type) { case TYPE_FIRE: // Burn Up gBattlescriptCurrInstr = BattleScript_RemoveFireType; @@ -4062,7 +4022,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattlescriptCurrInstr = BattleScript_RemoveGenericType; break; } - RemoveBattlerType(gEffectBattler, gMovesInfo[gCurrentMove].argument); + RemoveBattlerType(gEffectBattler, gMovesInfo[gCurrentMove].argument.type); break; case MOVE_EFFECT_ROUND: TryUpdateRoundTurnOrder(); // If another Pokémon uses Round before the user this turn, the user will use Round directly after it @@ -4255,6 +4215,117 @@ void SetMoveEffect(bool32 primary, bool32 certain) } } break; + case MOVE_EFFECT_ION_DELUGE: + if (!(gFieldStatuses & STATUS_FIELD_ION_DELUGE)) + { + gFieldStatuses |= STATUS_FIELD_ION_DELUGE; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectIonDeluge; + } + break; + // TODO: The moves aromatherapy and heal bell need a refactor first + // case MOVE_EFFECT_AROMATHERAPY: + // break; + case MOVE_EFFECT_HAZE: + for (i = 0; i < gBattlersCount; i++) + TryResetBattlerStatChanges(i); + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectHaze; + break; + case MOVE_EFFECT_LEECH_SEED: + if (!IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) && !(gStatuses3[gBattlerTarget] & STATUS3_LEECHSEED)) + { + gStatuses3[gBattlerTarget] |= gBattlerAttacker; + gStatuses3[gBattlerTarget] |= STATUS3_LEECHSEED; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectLeechSeed; + } + break; + case MOVE_EFFECT_REFLECT: + side = GetBattlerSide(gBattlerAttacker); + if (!(gSideStatuses[side] & SIDE_STATUS_REFLECT)) + { + gSideStatuses[side] |= SIDE_STATUS_REFLECT; + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[side].reflectTimer = 8; + else + gSideTimers[side].reflectTimer = 5; + gSideTimers[side].reflectBattlerId = gBattlerAttacker; + + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_DOUBLE; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_REFLECT_SINGLE; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectReflect; + } + break; + case MOVE_EFFECT_LIGHT_SCREEN: + side = GetBattlerSide(gBattlerAttacker); + if (!(gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN)) + { + gSideStatuses[side] |= SIDE_STATUS_LIGHTSCREEN; + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIGHT_CLAY) + gSideTimers[side].lightscreenTimer = 8; + else + gSideTimers[side].lightscreenTimer = 5; + gSideTimers[side].lightscreenBattlerId = gBattlerAttacker; + + if (IsDoubleBattle() && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerAttacker) == 2) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_DOUBLE; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_LIGHTSCREEN_SINGLE; + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectLightScreen; + } + break; + case MOVE_EFFECT_SALT_CURE: + if (!(gStatuses4[gBattlerTarget] & STATUS4_SALT_CURE)) + { + gStatuses4[gBattlerTarget] |= STATUS4_SALT_CURE; + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectSaltCure; + } + break; + case MOVE_EFFECT_EERIE_SPELL: + if (gLastMoves[gBattlerTarget] != MOVE_NONE && gLastMoves[gBattlerTarget] != 0xFFFF) + { + u32 i; + + for (i = 0; i < MAX_MON_MOVES; i++) + { + if (gLastMoves[gBattlerTarget] == gBattleMons[gBattlerTarget].moves[i]) + break; + } + + if (i != MAX_MON_MOVES && gBattleMons[gBattlerTarget].pp[i] != 0) + { + u32 ppToDeduct = 3; + + if (gBattleMons[gBattlerTarget].pp[i] < ppToDeduct) + ppToDeduct = gBattleMons[gBattlerTarget].pp[i]; + + PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[gBattlerTarget]) + ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, STR_CONV_MODE_LEFT_ALIGN, 1); + PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) + gBattleMons[gBattlerTarget].pp[i] -= ppToDeduct; + if (!(gDisableStructs[gBattlerTarget].mimickedMoves & (1u << i)) + && !(gBattleMons[gBattlerTarget].status2 & STATUS2_TRANSFORMED)) + { + BtlController_EmitSetMonData(gBattlerTarget, BUFFER_A, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[gBattlerTarget].pp[i]), &gBattleMons[gBattlerTarget].pp[i]); + MarkBattlerForControllerExec(gBattlerTarget); + } + + if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF) + CancelMultiTurnMoves(gBattlerTarget); + + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_MoveEffectEerieSpell; + } + } + break; } } } @@ -4875,13 +4946,10 @@ static void Cmd_getexp(void) { if (gBattlerPartyIndexes[2] == *expMonId && !(gAbsentBattlerFlags & 4)) gBattleStruct->expGetterBattlerId = 2; + else if (!(gAbsentBattlerFlags & 1)) + gBattleStruct->expGetterBattlerId = 0; else - { - if (!(gAbsentBattlerFlags & 1)) - gBattleStruct->expGetterBattlerId = 0; - else - gBattleStruct->expGetterBattlerId = 2; - } + gBattleStruct->expGetterBattlerId = 2; } else { @@ -5959,7 +6027,9 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_ABSORB: - if (gMovesInfo[gCurrentMove].effect == EFFECT_ABSORB) + if (gMovesInfo[gCurrentMove].effect == EFFECT_ABSORB + && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) + && IsBattlerTurnDamaged(gBattlerTarget)) { if (gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && gMovesInfo[gCurrentMove].healingMove) { @@ -5968,7 +6038,7 @@ static void Cmd_moveend(void) } else if (IsBattlerAlive(gBattlerAttacker) && MoveResultHasEffect(gBattlerTarget)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * gMovesInfo[gCurrentMove].argument / 100)); + gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * gMovesInfo[gCurrentMove].argument.absorbPercentage / 100)); gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE; effect = TRUE; @@ -5997,7 +6067,7 @@ static void Cmd_moveend(void) && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget) && MoveResultHasEffect(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget) - && gMovesInfo[gCurrentMove].power != 0 + && !IS_MOVE_STATUS(gCurrentMove) && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) { SET_STATCHANGER(STAT_ATK, 1, FALSE); @@ -6186,18 +6256,18 @@ static void Cmd_moveend(void) } break; case MOVE_EFFECT_REMOVE_STATUS: // Smelling salts, Wake-Up Slap, Sparkling Aria - if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument) + if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument.status) && IsBattlerAlive(gBattlerTarget) && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)) { - gBattleMons[gBattlerTarget].status1 &= ~(gMovesInfo[gCurrentMove].argument); + gBattleMons[gBattlerTarget].status1 &= ~(gMovesInfo[gCurrentMove].argument.status); BtlController_EmitSetMonData(gBattlerTarget, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerTarget].status1); MarkBattlerForControllerExec(gBattlerTarget); effect = TRUE; BattleScriptPush(gBattlescriptCurrInstr); - switch (gMovesInfo[gCurrentMove].argument) + switch (gMovesInfo[gCurrentMove].argument.status) { case STATUS1_PARALYSIS: gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; @@ -6501,7 +6571,7 @@ static void Cmd_moveend(void) if (gMultiHitCounter == 0) { BattleScriptPushCursor(); - if (gMovesInfo[gCurrentMove].argument == MOVE_EFFECT_SCALE_SHOT && !NoAliveMonsForEitherParty()) + if (gMovesInfo[gCurrentMove].argument.moveProperty == MOVE_EFFECT_SCALE_SHOT && !NoAliveMonsForEitherParty()) gBattlescriptCurrInstr = BattleScript_ScaleShot; else gBattlescriptCurrInstr = BattleScript_MultiHitPrintStrings; @@ -9015,7 +9085,7 @@ static void Cmd_useitemonopponent(void) static bool32 HasAttackerFaintedTarget(void) { if (MoveResultHasEffect(gBattlerTarget) - && gMovesInfo[gCurrentMove].power != 0 + && !IS_MOVE_STATUS(gCurrentMove) && (gLastHitBy[gBattlerTarget] == 0xFF || gLastHitBy[gBattlerTarget] == gBattlerAttacker) && gBattleStruct->moveTarget[gBattlerAttacker] == gBattlerTarget && gBattlerTarget != gBattlerAttacker @@ -9174,8 +9244,8 @@ static bool32 TryDefogClear(u32 battlerAtk, bool32 clear) static bool32 TryTidyUpClear(u32 battlerAtk, bool32 clear) { - s32 i; - u8 saveBattler = gBattlerAttacker; + u32 i; + u32 saveBattler = gBattlerAttacker; for (i = 0; i < NUM_BATTLE_SIDES; i++) { @@ -9464,13 +9534,14 @@ static void Cmd_various(void) s32 i; u8 data[10]; u32 battler, bits; + enum CmdVarious variousId = cmd->id; if (gBattleControllerExecFlags) return; battler = GetBattlerForBattleScript(cmd->battler); - switch (cmd->id) + switch (variousId) { // Roar will fail in a double wild battle when used by the player against one of the two alive wild mons. // Also when an opposing wild mon uses it againt its partner. @@ -10399,7 +10470,7 @@ static void Cmd_various(void) case VARIOUS_SET_ARG_TO_BATTLE_DAMAGE: { VARIOUS_ARGS(); - gBattleStruct->moveDamage[gBattlerTarget] = gMovesInfo[gCurrentMove].argument; + gBattleStruct->moveDamage[gBattlerTarget] = gMovesInfo[gCurrentMove].argument.fixedDamage; break; } case VARIOUS_TRY_AUTOTOMIZE: @@ -10671,14 +10742,14 @@ static void Cmd_various(void) case VARIOUS_TRY_THIRD_TYPE: { VARIOUS_ARGS(const u8 *failInstr); - if (IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument) || GetActiveGimmick(battler) == GIMMICK_TERA) + if (IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument.type) || GetActiveGimmick(battler) == GIMMICK_TERA) { gBattlescriptCurrInstr = cmd->failInstr; } else { - gBattleMons[battler].types[2] = gMovesInfo[gCurrentMove].argument; - PREPARE_TYPE_BUFFER(gBattleTextBuff1, gMovesInfo[gCurrentMove].argument); + gBattleMons[battler].types[2] = gMovesInfo[gCurrentMove].argument.type; + PREPARE_TYPE_BUFFER(gBattleTextBuff1, gMovesInfo[gCurrentMove].argument.type); gBattlescriptCurrInstr = cmd->nextInstr; } return; @@ -10787,53 +10858,6 @@ static void Cmd_various(void) MarkBattlerForControllerExec(battler); break; } - case VARIOUS_EERIE_SPELL_PP_REDUCE: - { - VARIOUS_ARGS(const u8 *failInstr); - if (gLastMoves[battler] != 0 && gLastMoves[battler] != 0xFFFF) - { - s32 i; - - for (i = 0; i < MAX_MON_MOVES; i++) - { - if (gLastMoves[battler] == gBattleMons[battler].moves[i]) - break; - } - - if (i != MAX_MON_MOVES && gBattleMons[battler].pp[i] != 0) - { - s32 ppToDeduct = 3; - - if (gBattleMons[battler].pp[i] < ppToDeduct) - ppToDeduct = gBattleMons[battler].pp[i]; - - PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[battler]) - ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, STR_CONV_MODE_LEFT_ALIGN, 1); - PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct) - gBattleMons[battler].pp[i] -= ppToDeduct; - if (!(gDisableStructs[battler].mimickedMoves & (1u << i)) - && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) - { - BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[battler].pp[i]), &gBattleMons[battler].pp[i]); - MarkBattlerForControllerExec(battler); - } - - if (gBattleMons[battler].pp[i] == 0 && gBattleStruct->skyDropTargets[battler] == 0xFF) - CancelMultiTurnMoves(battler); - - gBattlescriptCurrInstr = cmd->nextInstr; // continue - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; // cant reduce pp - } - } - else - { - gBattlescriptCurrInstr = cmd->failInstr; // cant reduce pp - } - return; - } case VARIOUS_JUMP_IF_TEAM_HEALTHY: { VARIOUS_ARGS(const u8 *jumpInstr); @@ -11345,7 +11369,7 @@ static void Cmd_setprotectlike(void) || (gCurrentMove == MOVE_WIDE_GUARD && B_WIDE_GUARD != GEN_5) || (gCurrentMove == MOVE_QUICK_GUARD && B_QUICK_GUARD != GEN_5)) { - if (!gMovesInfo[gCurrentMove].argument) // Protects one mon only. + if (!gMovesInfo[gCurrentMove].argument.protect.side) // Protects one mon only. { if (gMovesInfo[gCurrentMove].effect == EFFECT_ENDURE) { @@ -11902,8 +11926,8 @@ static void Cmd_setdrainedhp(void) { CMD_ARGS(); - if (gMovesInfo[gCurrentMove].argument != 0) - gBattleStruct->moveDamage[gBattlerAttacker] = (gHpDealt * gMovesInfo[gCurrentMove].argument / 100); + if (gMovesInfo[gCurrentMove].argument.absorbPercentage != 0) + gBattleStruct->moveDamage[gBattlerAttacker] = (gHpDealt * gMovesInfo[gCurrentMove].argument.absorbPercentage / 100); else gBattleStruct->moveDamage[gBattlerAttacker] = (gHpDealt / 2); @@ -12267,7 +12291,10 @@ static void Cmd_statbuffchange(void) const u8 *ptrBefore = gBattlescriptCurrInstr; const u8 *failInstr = cmd->failInstr; - if (ChangeStatBuffs(GET_STAT_BUFF_VALUE_WITH_SIGN(gBattleScripting.statChanger), GET_STAT_BUFF_ID(gBattleScripting.statChanger), flags, failInstr) == STAT_CHANGE_WORKED) + if (ChangeStatBuffs(GET_STAT_BUFF_VALUE_WITH_SIGN(gBattleScripting.statChanger), + GET_STAT_BUFF_ID(gBattleScripting.statChanger), + flags, + failInstr) == STAT_CHANGE_WORKED) gBattlescriptCurrInstr = cmd->nextInstr; else if (gBattlescriptCurrInstr == ptrBefore) // Prevent infinite looping. gBattlescriptCurrInstr = failInstr; @@ -12320,7 +12347,7 @@ static void Cmd_twoturnmoveschargestringandanimation(void) { CMD_ARGS(const u8 *animationThenStringPtr); - gBattleScripting.savedStringId = LOHALF(gMovesInfo[gCurrentMove].argument); + gBattleScripting.savedStringId = gMovesInfo[gCurrentMove].argument.twoTurnAttack.stringId; if (B_UPDATED_MOVE_DATA < GEN_5 || MoveHasChargeTurnAdditionalEffect(gCurrentMove)) gBattlescriptCurrInstr = cmd->animationThenStringPtr; else @@ -12988,7 +13015,10 @@ static void Cmd_setsubstitute(void) gBattleMons[gBattlerAttacker].status2 |= STATUS2_SUBSTITUTE; gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_WRAPPED; - gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker]; + if (factor == 2) + gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker] / 2; + else + gDisableStructs[gBattlerAttacker].substituteHP = gBattleStruct->moveDamage[gBattlerAttacker]; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_SUBSTITUTE; gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE; } @@ -13560,7 +13590,7 @@ static void Cmd_tryspiteppreduce(void) { s32 ppToDeduct = B_PP_REDUCED_BY_SPITE >= GEN_4 ? 4 : (Random() & 3) + 2; // G-Max Depletion only deducts 2 PP. - if (IsMaxMove(gCurrentMove) && gMovesInfo[gCurrentMove].argument == MAX_EFFECT_SPITE) + if (IsMaxMove(gCurrentMove) && gMovesInfo[gCurrentMove].argument.maxEffect == MAX_EFFECT_SPITE) ppToDeduct = 2; if (gBattleMons[gBattlerTarget].pp[i] < ppToDeduct) @@ -14277,6 +14307,7 @@ static void Cmd_trydobeatup(void) && !GetMonData(&party[gBattleCommunication[0]], MON_DATA_STATUS)) break; } + if (gBattleCommunication[0] < PARTY_SIZE) { PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gBattlerAttacker, gBattleCommunication[0]) @@ -14294,9 +14325,13 @@ static void Cmd_trydobeatup(void) gBattleCommunication[0]++; } else if (beforeLoop != 0) + { gBattlescriptCurrInstr = cmd->endInstr; + } else + { gBattlescriptCurrInstr = cmd->failInstr; + } } #endif } @@ -14307,7 +14342,7 @@ static void Cmd_setsemiinvulnerablebit(void) if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == TRUE) { - u32 semiInvulnerableEffect = UNCOMPRESS_BITS(HIHALF(gMovesInfo[gCurrentMove].argument)); + u32 semiInvulnerableEffect = UNCOMPRESS_BITS(gMovesInfo[gCurrentMove].argument.twoTurnAttack.status); if (cmd->clear) gStatuses3[gBattlerAttacker] &= ~semiInvulnerableEffect; else @@ -14331,7 +14366,7 @@ static bool32 CheckIfCanFireTwoTurnMoveNow(u8 battler, bool8 checkChargeTurnEffe // Certain two-turn moves may fire on the first turn in the right weather (Solar Beam, Electro Shot) // By default, all two-turn moves have the option of adding weather to their argument - if (IsBattlerWeatherAffected(battler, HIHALF(gMovesInfo[gCurrentMove].argument))) + if (IsBattlerWeatherAffected(battler, gMovesInfo[gCurrentMove].argument.twoTurnAttack.status)) return TRUE; return FALSE; @@ -15090,10 +15125,10 @@ static void Cmd_switchoutabilities(void) break; case ABILITY_REGENERATOR: { - u32 regenerate = GetNonDynamaxMaxHP(gBattlerAttacker) / 3; + u32 regenerate = GetNonDynamaxMaxHP(battler) / 3; regenerate += gBattleMons[battler].hp; - if (gBattleStruct->moveDamage[gBattlerAttacker] > gBattleMons[battler].maxHP) - gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[battler].maxHP; + if (regenerate > gBattleMons[battler].maxHP) + regenerate = gBattleMons[battler].maxHP; BtlController_EmitSetMonData(battler, BUFFER_A, REQUEST_HP_BATTLE, 1u << *(gBattleStruct->battlerPartyIndexes + battler), sizeof(regenerate), @@ -15126,7 +15161,7 @@ static void Cmd_jumpifnotcurrentmoveargtype(void) u8 battler = GetBattlerForBattleScript(cmd->battler); const u8 *failInstr = cmd->failInstr; - if (!IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument)) + if (!IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument.type)) gBattlescriptCurrInstr = failInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -16885,20 +16920,11 @@ void BS_JumpIfElectricAbilityAffected(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_ApplySaltCure(void) -{ - NATIVE_ARGS(u8 battler); - - u8 battler = GetBattlerForBattleScript(cmd->battler); - gStatuses4[battler] |= STATUS4_SALT_CURE; - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_JumpIfArgument(void) { NATIVE_ARGS(u8 argument, const u8 *jumpInstr); - if (gMovesInfo[gCurrentMove].argument == cmd->argument) + if (gMovesInfo[gCurrentMove].argument.moveProperty == cmd->argument) gBattlescriptCurrInstr = cmd->jumpInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -16928,7 +16954,7 @@ void BS_SetRemoveTerrain(void) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; break; case EFFECT_HIT_SET_REMOVE_TERRAIN: - switch (gMovesInfo[gCurrentMove].argument) + switch (gMovesInfo[gCurrentMove].argument.moveProperty) { case ARG_SET_PSYCHIC_TERRAIN: // Genesis Supernova statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; @@ -17245,7 +17271,7 @@ void BS_TryHealPulse(void) { if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MEGA_LAUNCHER && gMovesInfo[gCurrentMove].pulseMove) gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 75 / 100); - else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && gMovesInfo[gCurrentMove].argument == MOVE_EFFECT_FLORAL_HEALING) + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && gMovesInfo[gCurrentMove].argument.moveProperty == MOVE_EFFECT_FLORAL_HEALING) gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 2 / 3); else gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) / 2); diff --git a/src/battle_util.c b/src/battle_util.c index 7efd58f659..2323a28ce7 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -56,6 +56,7 @@ match the ROM; this is also why sSoundMovesTable's declaration is in the middle functions instead of at the top of the file with the other declarations. */ +typedef void (*MoveSuccessOrderCancellers)(u32 *effect); static bool32 TryRemoveScreens(u32 battler); static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler); static u32 GetFlingPowerFromItemId(u32 itemId); @@ -230,7 +231,7 @@ void HandleAction_UseMove(void) else if (IsDoubleBattle() && gSideTimers[side].followmeTimer == 0 && !(gBattleStruct->pursuitTarget & (1u << *(gBattleStruct->moveTarget + gBattlerAttacker))) - && (gMovesInfo[gCurrentMove].power != 0 || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) + && (!IS_MOVE_STATUS(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { @@ -574,7 +575,8 @@ void HandleAction_ThrowBall(void) gBattle_BG0_X = 0; gBattle_BG0_Y = 0; gLastUsedItem = gBallToDisplay; - RemoveBagItem(gLastUsedItem, 1); + if (!ItemId_GetImportance(gLastUsedItem)) + RemoveBagItem(gLastUsedItem, 1); gBattlescriptCurrInstr = BattleScript_BallThrow; gCurrentActionFuncId = B_ACTION_EXEC_SCRIPT; } @@ -1716,17 +1718,12 @@ u8 DoFieldEndTurnEffects(void) switch (gBattleStruct->turnCountersTracker) { case ENDTURN_ORDER: - for (i = 0; i < gBattlersCount; i++) - { - gBattlerByTurnOrder[i] = i; - } for (i = 0; i < gBattlersCount - 1; i++) { s32 j; for (j = i + 1; j < gBattlersCount; j++) { - if (!gProtectStructs[i].quash - && !gProtectStructs[j].quash + if (!(gProtectStructs[i].quash && gProtectStructs[j].quash) && GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1) SwapTurnOrder(i, j); } @@ -3121,638 +3118,747 @@ void TryClearRageAndFuryCutter(void) } } +static inline bool32 TryFormChangeBeforeMove(void) +{ + bool32 result = TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_BEFORE_MOVE); + if (!result) + result = TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_BEFORE_MOVE_CATEGORY); + if (!result) + return FALSE; + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AttackerFormChange; + return TRUE; +} + void SetAtkCancellerForCalledMove(void) { gBattleStruct->atkCancellerTracker = CANCELLER_HEAL_BLOCKED; gBattleStruct->isAtkCancelerForCalledMove = TRUE; } -u8 AtkCanceller_UnableToUseMove(u32 moveType) +static void CancellerFlags(u32 *effect) { - u32 effect = 0; - u32 obedienceResult; - do + gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_DESTINY_BOND; + gStatuses3[gBattlerAttacker] &= ~STATUS3_GRUDGE; + gStatuses4[gBattlerAttacker] &= ~STATUS4_GLAIVE_RUSH; +} + +static void CancellerStanceChangeOne(u32 *effect) +{ + if (B_STANCE_CHANGE_FAIL < GEN_7 && TryFormChangeBeforeMove()) + *effect = 1; +} + +static void CancellerSkyDrop(u32 *effect) +{ + // If Pokemon is being held in Sky Drop + if (gStatuses3[gBattlerAttacker] & STATUS3_SKY_DROPPED) { - switch (gBattleStruct->atkCancellerTracker) + gBattlescriptCurrInstr = BattleScript_MoveEnd; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerRecharge(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) + { + gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RECHARGE; + gDisableStructs[gBattlerAttacker].rechargeTimer = 0; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerAsleep(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) + { + if (UproarWakeUpCheck(gBattlerAttacker)) { - case CANCELLER_FLAGS: // flags clear - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_DESTINY_BOND; - gStatuses3[gBattlerAttacker] &= ~STATUS3_GRUDGE; - gStatuses4[gBattlerAttacker] &= ~STATUS4_GLAIVE_RUSH; - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_SKY_DROP: - // If Pokemon is being held in Sky Drop - if (gStatuses3[gBattlerAttacker] & STATUS3_SKY_DROPPED) - { - gBattlescriptCurrInstr = BattleScript_MoveEnd; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_ASLEEP: // check being asleep + TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); + gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; + gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; + BattleScriptPushCursor(); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR; + gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; + *effect = 2; + } + else + { + u8 toSub; + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_EARLY_BIRD) + toSub = 2; + else + toSub = 1; + if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) < toSub) + gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; + else + gBattleMons[gBattlerAttacker].status1 -= toSub; if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) { - if (UproarWakeUpCheck(gBattlerAttacker)) + if (gChosenMove != MOVE_SNORE && gChosenMove != MOVE_SLEEP_TALK) { - TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; - BattleScriptPushCursor(); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP_UPROAR; - gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; - effect = 2; - } - else - { - u8 toSub; - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_EARLY_BIRD) - toSub = 2; - else - toSub = 1; - if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) < toSub) - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_SLEEP; - else - gBattleMons[gBattlerAttacker].status1 -= toSub; - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) - { - if (gChosenMove != MOVE_SNORE && gChosenMove != MOVE_SLEEP_TALK) - { - gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 2; - } - } - else - { - TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; - BattleScriptPushCursor(); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP; - gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; - effect = 2; - } - } - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_FROZEN: // check being frozen - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE && !(gMovesInfo[gCurrentMove].thawsUser)) - { - if (!RandomPercentage(RNG_FROZEN, 20)) - { - gBattlescriptCurrInstr = BattleScript_MoveUsedIsFrozen; - gHitMarker |= (HITMARKER_NO_ATTACKSTRING | HITMARKER_UNABLE_TO_USE_MOVE); - } - else // unfreeze - { - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED; - } - effect = 2; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_OBEDIENCE: - obedienceResult = GetAttackerObedienceForAction(); - if (obedienceResult != OBEYS - && !(gHitMarker & HITMARKER_NO_PPDEDUCT) // Don't check obedience after first hit of multi target move or multi hit moves - && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) - { - switch (obedienceResult) - { - case DISOBEYS_LOAFS: - // Randomly select, then print a disobedient string - // B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE - gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS); - gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - break; - case DISOBEYS_HITS_SELF: - gBattlerTarget = gBattlerAttacker; - struct DamageCalculationData damageCalcData; - damageCalcData.battlerAtk = damageCalcData.battlerDef = gBattlerAttacker; - damageCalcData.move = MOVE_NONE; - damageCalcData.moveType = TYPE_MYSTERY; - damageCalcData.isCrit = FALSE; - damageCalcData.randomFactor = FALSE; - damageCalcData.updateFlags = TRUE; - gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&damageCalcData, 40); - gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself; + gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - gHitMarker |= HITMARKER_OBEYS; - break; - case DISOBEYS_FALL_ASLEEP: - if (IsSleepClauseEnabled()) - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - break; - case DISOBEYS_WHILE_ASLEEP: - gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - break; - case DISOBEYS_RANDOM_MOVE: - gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - SetAtkCancellerForCalledMove(); - gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; - gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); - gHitMarker |= HITMARKER_DISOBEDIENT_MOVE; - gHitMarker |= HITMARKER_OBEYS; - break; + *effect = 2; } - effect = 1; } else { - gHitMarker |= HITMARKER_OBEYS; + TryDeactivateSleepClause(GetBattlerSide(gBattlerAttacker), gBattlerPartyIndexes[gBattlerAttacker]); + gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_NIGHTMARE; + BattleScriptPushCursor(); + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WOKE_UP; + gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp; + *effect = 2; } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_TRUANT: // truant - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) - { - CancelMultiTurnMoves(gBattlerAttacker); - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING; - gBattlerAbility = gBattlerAttacker; - gBattlescriptCurrInstr = BattleScript_TruantLoafingAround; - gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_RECHARGE: // recharge - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) - { - gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RECHARGE; - gDisableStructs[gBattlerAttacker].rechargeTimer = 0; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_FLINCH: // flinch - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED) - { - gProtectStructs[gBattlerAttacker].flinchImmobility = TRUE; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_DISABLED: // disabled move - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].disabledMove == gCurrentMove && gDisableStructs[gBattlerAttacker].disabledMove != MOVE_NONE) - { - gProtectStructs[gBattlerAttacker].usedDisabledMove = TRUE; - gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_HEAL_BLOCKED: - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(gBattlerAttacker, gCurrentMove)) - { - gProtectStructs[gBattlerAttacker].usedHealBlockedMove = TRUE; - gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_GRAVITY: - if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(gCurrentMove)) - { - gProtectStructs[gBattlerAttacker].usedGravityPreventedMove = TRUE; - gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_TAUNTED: // taunt - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IS_MOVE_STATUS(gCurrentMove)) - { - gProtectStructs[gBattlerAttacker].usedTauntedMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_IMPRISONED: // imprisoned - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove)) - { - gProtectStructs[gBattlerAttacker].usedImprisonedMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_CONFUSED: // confusion - if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) - { - if (!(gStatuses4[gBattlerAttacker] & STATUS4_INFINITE_CONFUSION)) - gBattleMons[gBattlerAttacker].status2 -= STATUS2_CONFUSION_TURN(1); - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) - { - // confusion dmg - if (RandomPercentage(RNG_CONFUSION, (B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50))) - { - gBattleCommunication[MULTISTRING_CHOOSER] = TRUE; - gBattlerTarget = gBattlerAttacker; - struct DamageCalculationData damageCalcData; - damageCalcData.battlerAtk = damageCalcData.battlerDef = gBattlerAttacker; - damageCalcData.move = MOVE_NONE; - damageCalcData.moveType = TYPE_MYSTERY; - damageCalcData.isCrit = FALSE; - damageCalcData.randomFactor = FALSE; - damageCalcData.updateFlags = TRUE; - gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&damageCalcData, 40); - gProtectStructs[gBattlerAttacker].confusionSelfDmg = TRUE; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = FALSE; - BattleScriptPushCursor(); - } - gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused; - } - else // snapped out of confusion - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfusedNoMore; - } - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_PARALYSED: // paralysis - if (!gBattleStruct->isAtkCancelerForCalledMove && (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && !RandomPercentage(RNG_PARALYSIS, 75)) - { - gProtectStructs[gBattlerAttacker].prlzImmobility = TRUE; - // This is removed in FRLG and Emerald for some reason - //CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_IN_LOVE: // infatuation - if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) - { - gBattleScripting.battler = CountTrailingZeroBits((gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) >> 0x10); - if (!RandomPercentage(RNG_INFATUATION, 50)) - { - BattleScriptPushCursor(); - } - else - { - BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack); - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - gProtectStructs[gBattlerAttacker].loveImmobility = TRUE; - CancelMultiTurnMoves(gBattlerAttacker); - } - gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_BIDE: // bide - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) - { - gBattleMons[gBattlerAttacker].status2 -= STATUS2_BIDE_TURN(1); - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) - { - gBattlescriptCurrInstr = BattleScript_BideStoringEnergy; - } - else - { - // This is removed in FRLG and Emerald for some reason - //gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_MULTIPLETURNS; - if (gBideDmg[gBattlerAttacker]) - { - gCurrentMove = MOVE_BIDE; - gBattlerTarget = gBideTarget[gBattlerAttacker]; - if (gAbsentBattlerFlags & (1u << gBattlerTarget)) - gBattlerTarget = GetMoveTarget(MOVE_BIDE, MOVE_TARGET_SELECTED + 1); - gBattlescriptCurrInstr = BattleScript_BideAttack; - } - else - { - gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack; - } - } - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_THAW: // move thawing - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE) - { - if (!(MoveHasAdditionalEffectSelfArg(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) - { - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED_BY_MOVE; - } - effect = 2; - } - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && gMovesInfo[gCurrentMove].thawsUser) - { - if (!(MoveHasAdditionalEffectSelfArg(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) - { - gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FROSTBITE; - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MoveUsedUnfrostbite; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FROSTBITE_HEALED_BY_MOVE; - } - effect = 2; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_POWDER_MOVE: - if ((gMovesInfo[gCurrentMove].powderMove) && (gBattlerAttacker != gBattlerTarget)) - { - if (B_POWDER_GRASS >= GEN_6 - && (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) || GetBattlerAbility(gBattlerTarget) == ABILITY_OVERCOAT)) - { - gBattlerAbility = gBattlerTarget; - effect = 1; - } - else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_SAFETY_GOGGLES) - { - RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_SAFETY_GOGGLES); - gLastUsedItem = gBattleMons[gBattlerTarget].item; - effect = 1; - } + } + } +} - if (effect != 0) - gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_POWDER_STATUS: - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER) - { - u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; - if ((moveType == TYPE_FIRE && !gBattleStruct->pledgeMove) - || (gCurrentMove == MOVE_FIRE_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE) - || (gCurrentMove == MOVE_GRASS_PLEDGE && partnerMove == MOVE_FIRE_PLEDGE && gBattleStruct->pledgeMove)) - { - gProtectStructs[gBattlerAttacker].powderSelfDmg = TRUE; - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD - && (B_POWDER_RAIN < GEN_7 || !IsBattlerWeatherAffected(gBattlerAttacker, B_WEATHER_RAIN_PRIMAL))) - gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; - - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE - || HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE)) - gBattlescriptCurrInstr = BattleScript_MoveUsedPowder; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_THROAT_CHOP: - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer && gMovesInfo[gCurrentMove].soundMove) - { - gProtectStructs[gBattlerAttacker].usedThroatChopPreventedMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_Z_MOVES: - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) - { - // For Z-Mirror Move, so it doesn't play the animation twice. - bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE); - - // attacker has a queued z move - RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_Z_CRYSTAL); - SetGimmickAsActivated(gBattlerAttacker, GIMMICK_Z_MOVE); - - gBattleScripting.battler = gBattlerAttacker; - if (gProtectStructs[gBattlerAttacker].powderSelfDmg) - { - if (!alreadyUsed) - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ZMoveActivatePowder; - } - } - else if (gMovesInfo[gCurrentMove].category == DAMAGE_CATEGORY_STATUS) - { - if (!alreadyUsed) - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ZMoveActivateStatus; - } - } - else - { - if (!alreadyUsed) - { - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_ZMoveActivateDamaging; - } - } - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_EXPLODING_DAMP: +static void CancellerFrozen(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE && !(gMovesInfo[gCurrentMove].thawsUser)) + { + if (!RandomPercentage(RNG_FROZEN, 20)) { - u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); - if (dampBattler && (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION - || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN)) - { - gBattleScripting.battler = dampBattler - 1; - gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; + gBattlescriptCurrInstr = BattleScript_MoveUsedIsFrozen; + gHitMarker |= (HITMARKER_NO_ATTACKSTRING | HITMARKER_UNABLE_TO_USE_MOVE); + } + else // unfreeze + { + gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED; + } + *effect = 2; + } +} + +static void CancellerObedience(u32 *effect) +{ + u32 obedienceResult = GetAttackerObedienceForAction(); + if (obedienceResult != OBEYS + && !(gHitMarker & HITMARKER_NO_PPDEDUCT) // Don't check obedience after first hit of multi target move or multi hit moves + && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) + { + switch (obedienceResult) + { + case DISOBEYS_LOAFS: + // Randomly select, then print a disobedient string + // B_MSG_LOAFING, B_MSG_WONT_OBEY, B_MSG_TURNED_AWAY, or B_MSG_PRETEND_NOT_NOTICE + gBattleCommunication[MULTISTRING_CHOOSER] = MOD(Random(), NUM_LOAF_STRINGS); + gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; + gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; + break; + case DISOBEYS_HITS_SELF: + gBattlerTarget = gBattlerAttacker; + struct DamageCalculationData damageCalcData; + damageCalcData.battlerAtk = damageCalcData.battlerDef = gBattlerAttacker; + damageCalcData.move = MOVE_NONE; + damageCalcData.moveType = TYPE_MYSTERY; + damageCalcData.isCrit = FALSE; + damageCalcData.randomFactor = FALSE; + damageCalcData.updateFlags = TRUE; + gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&damageCalcData, 40); + gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gHitMarker |= HITMARKER_OBEYS; + break; + case DISOBEYS_FALL_ASLEEP: + if (IsSleepClauseEnabled()) + gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep; + gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; + break; + case DISOBEYS_WHILE_ASLEEP: + gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep; + gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; + break; + case DISOBEYS_RANDOM_MOVE: + gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + SetAtkCancellerForCalledMove(); + gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; + gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + gHitMarker |= HITMARKER_DISOBEDIENT_MOVE; + gHitMarker |= HITMARKER_OBEYS; break; } - case CANCELLER_MULTIHIT_MOVES: - if (gMovesInfo[gCurrentMove].effect == EFFECT_MULTI_HIT) + *effect = 1; + } + else + { + gHitMarker |= HITMARKER_OBEYS; + } +} + +static void CancellerTruant(u32 *effect) +{ + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) + { + CancelMultiTurnMoves(gBattlerAttacker); + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING; + gBattlerAbility = gBattlerAttacker; + gBattlescriptCurrInstr = BattleScript_TruantLoafingAround; + gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; + *effect = 1; + } +} + +static void CancellerFlinch(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED) + { + gProtectStructs[gBattlerAttacker].flinchImmobility = TRUE; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerInLove(u32 *effect) +{ + if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) + { + gBattleScripting.battler = CountTrailingZeroBits((gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) >> 0x10); + if (!RandomPercentage(RNG_INFATUATION, 50)) + { + BattleScriptPushCursor(); + } + else + { + BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack); + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + gProtectStructs[gBattlerAttacker].loveImmobility = TRUE; + CancelMultiTurnMoves(gBattlerAttacker); + } + gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove; + *effect = 1; + } +} + +static void CancellerDisabled(u32 *effect) +{ + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].disabledMove == gCurrentMove && gDisableStructs[gBattlerAttacker].disabledMove != MOVE_NONE) + { + gProtectStructs[gBattlerAttacker].usedDisabledMove = TRUE; + gBattleScripting.battler = gBattlerAttacker; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerHealBlocked(u32 *effect) +{ + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(gBattlerAttacker, gCurrentMove)) + { + gProtectStructs[gBattlerAttacker].usedHealBlockedMove = TRUE; + gBattleScripting.battler = gBattlerAttacker; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerGravity(u32 *effect) +{ + if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(gCurrentMove)) + { + gProtectStructs[gBattlerAttacker].usedGravityPreventedMove = TRUE; + gBattleScripting.battler = gBattlerAttacker; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerThroatChop(u32 *effect) +{ + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer && gMovesInfo[gCurrentMove].soundMove) + { + gProtectStructs[gBattlerAttacker].usedThroatChopPreventedMove = TRUE; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerTaunted(u32 *effect) +{ + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IS_MOVE_STATUS(gCurrentMove)) + { + gProtectStructs[gBattlerAttacker].usedTauntedMove = TRUE; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerImprisoned(u32 *effect) +{ + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove)) + { + gProtectStructs[gBattlerAttacker].usedImprisonedMove = TRUE; + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerConfused(u32 *effect) +{ + if (gBattleStruct->isAtkCancelerForCalledMove) + return; + + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) + { + if (!(gStatuses4[gBattlerAttacker] & STATUS4_INFINITE_CONFUSION)) + gBattleMons[gBattlerAttacker].status2 -= STATUS2_CONFUSION_TURN(1); + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION) + { + // confusion dmg + if (RandomPercentage(RNG_CONFUSION, (B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50))) { - u32 ability = GetBattlerAbility(gBattlerAttacker); - - if (ability == ABILITY_SKILL_LINK) - { - gMultiHitCounter = 5; - } - else if (ability == ABILITY_BATTLE_BOND - && gCurrentMove == MOVE_WATER_SHURIKEN - && gBattleMons[gBattlerAttacker].species == SPECIES_GRENINJA_ASH) - { - gMultiHitCounter = 3; - } - else - { - SetRandomMultiHitCounter(); - } - - PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) - } - else if (gMovesInfo[gCurrentMove].strikeCount > 1) - { - if (gMovesInfo[gCurrentMove].effect == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) - { - gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10); - } - else - { - gMultiHitCounter = gMovesInfo[gCurrentMove].strikeCount; - - if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS - && CanTargetPartner(gBattlerAttacker, gBattlerTarget) - && TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget)) - gBattlerTarget = BATTLE_PARTNER(gBattlerTarget); - } - - PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0) - } - else if (B_BEAT_UP >= GEN_5 && gMovesInfo[gCurrentMove].effect == EFFECT_BEAT_UP) - { - struct Pokemon* party = GetBattlerParty(gBattlerAttacker); - int i; - - for (i = 0; i < PARTY_SIZE; i++) - { - if (GetMonData(&party[i], MON_DATA_HP) - && GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE - && !GetMonData(&party[i], MON_DATA_IS_EGG) - && !GetMonData(&party[i], MON_DATA_STATUS)) - gMultiHitCounter++; - } - - gBattleStruct->beatUpSlot = 0; - PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) + gBattleCommunication[MULTISTRING_CHOOSER] = TRUE; + gBattlerTarget = gBattlerAttacker; + struct DamageCalculationData damageCalcData; + damageCalcData.battlerAtk = damageCalcData.battlerDef = gBattlerAttacker; + damageCalcData.move = MOVE_NONE; + damageCalcData.moveType = TYPE_MYSTERY; + damageCalcData.isCrit = FALSE; + damageCalcData.randomFactor = FALSE; + damageCalcData.updateFlags = TRUE; + gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&damageCalcData, 40); + gProtectStructs[gBattlerAttacker].confusionSelfDmg = TRUE; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; } else { - gMultiHitCounter = 0; + gBattleCommunication[MULTISTRING_CHOOSER] = FALSE; + BattleScriptPushCursor(); } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_MULTI_TARGET_MOVES: - if (!IsDoubleBattle()) + gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused; + } + else // snapped out of confusion + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfusedNoMore; + } + *effect = 1; + } +} + +static void CancellerParalysed(u32 *effect) +{ + if (!gBattleStruct->isAtkCancelerForCalledMove && (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && !RandomPercentage(RNG_PARALYSIS, 75)) + { + gProtectStructs[gBattlerAttacker].prlzImmobility = TRUE; + // This is removed in FRLG and Emerald for some reason + //CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerBide(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) + { + gBattleMons[gBattlerAttacker].status2 -= STATUS2_BIDE_TURN(1); + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE) + { + gBattlescriptCurrInstr = BattleScript_BideStoringEnergy; + } + else + { + // This is removed in FRLG and Emerald for some reason + //gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_MULTIPLETURNS; + if (gBideDmg[gBattlerAttacker]) { - gBattleStruct->atkCancellerTracker++; - break; + gCurrentMove = MOVE_BIDE; + gBattlerTarget = gBideTarget[gBattlerAttacker]; + if (gAbsentBattlerFlags & (1u << gBattlerTarget)) + gBattlerTarget = GetMoveTarget(MOVE_BIDE, MOVE_TARGET_SELECTED + 1); + gBattlescriptCurrInstr = BattleScript_BideAttack; } - - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - if (IsSpreadMove(moveTarget)) + else { - for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) - { - if (gBattleStruct->bouncedMoveIsUsed && B_SIDE_OPPONENT == GetBattlerSide(battlerDef)) - continue; - - if (gBattlerAttacker == battlerDef - || !IsBattlerAlive(battlerDef) - || (moveTarget == MOVE_TARGET_BOTH && gBattlerAttacker == BATTLE_PARTNER(battlerDef)) - || IsBattlerProtected(gBattlerAttacker, battlerDef, gCurrentMove)) // Missing Invulnerable check - { - gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_NO_EFFECT; - gBattleStruct->noResultString[battlerDef] = TRUE; - } - else if (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, battlerDef, 0, 0, 0) - || (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetMovePriority(gBattlerAttacker, gCurrentMove) > 0)) - { - gBattleStruct->moveResultFlags[battlerDef] = 0; - gBattleStruct->noResultString[battlerDef] = TRUE; - } - else if (AbilityBattleEffects(ABILITYEFFECT_WOULD_ABSORB, battlerDef, 0, 0, gCurrentMove)) - { - gBattleStruct->moveResultFlags[battlerDef] = 0; - gBattleStruct->noResultString[battlerDef] = DO_ACCURACY_CHECK; - } - else - { - CalcTypeEffectivenessMultiplier(gCurrentMove, gMovesInfo[gCurrentMove].type, gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); - } - } - if (moveTarget == MOVE_TARGET_BOTH) - gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER_SIDE, gBattlerAttacker); - else - gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER, gBattlerAttacker); - + gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack; } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_END: - break; + } + *effect = 1; + } +} + +static void CancellerThaw(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE) + { + if (!(IsMoveEffectRemoveSpeciesType(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) + { + gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FREEZE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DEFROSTED_BY_MOVE; + } + *effect = 2; + } + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && gMovesInfo[gCurrentMove].thawsUser) + { + if (!(IsMoveEffectRemoveSpeciesType(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) + { + gBattleMons[gBattlerAttacker].status1 &= ~STATUS1_FROSTBITE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveUsedUnfrostbite; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FROSTBITE_HEALED_BY_MOVE; + } + *effect = 2; + } +} + +static void CancellerStanceChangeTwo(u32 *effect) +{ + if (B_STANCE_CHANGE_FAIL >= GEN_7 && TryFormChangeBeforeMove()) + *effect = 1; +} + +static void CancellerWeatherPrimal(u32 *effect) +{ + if (WEATHER_HAS_EFFECT && gMovesInfo[gCurrentMove].power) + { + u32 moveType = GetMoveType(gCurrentMove); + if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN; + *effect = 1; + } + else if (moveType == TYPE_WATER && (gBattleWeather & B_WEATHER_SUN_PRIMAL)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_EVAPORATED_IN_SUN; + *effect = 1; + } + if (*effect == 1) + { + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove; + } + } +} + +static void CancellerDynamaxBlocked(u32 *effect) +{ + if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove)) + { + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MoveBlockedByDynamax; + *effect = 1; + } +} + +static void CancellerPowderMove(u32 *effect) +{ + if ((gMovesInfo[gCurrentMove].powderMove) && (gBattlerAttacker != gBattlerTarget)) + { + if (B_POWDER_GRASS >= GEN_6 + && (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) || GetBattlerAbility(gBattlerTarget) == ABILITY_OVERCOAT)) + { + gBattlerAbility = gBattlerTarget; + *effect = 1; + } + else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_SAFETY_GOGGLES) + { + RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_SAFETY_GOGGLES); + gLastUsedItem = gBattleMons[gBattlerTarget].item; + *effect = 1; } - } while (gBattleStruct->atkCancellerTracker != CANCELLER_END && gBattleStruct->atkCancellerTracker != CANCELLER_END2 && effect == 0); + if (*effect != 0) + gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; + } +} + +static void CancellerPowderStatus(u32 *effect) +{ + if (gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER) + { + u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; + if ((GetMoveType(gCurrentMove) == TYPE_FIRE && !gBattleStruct->pledgeMove) + || (gCurrentMove == MOVE_FIRE_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE) + || (gCurrentMove == MOVE_GRASS_PLEDGE && partnerMove == MOVE_FIRE_PLEDGE && gBattleStruct->pledgeMove)) + { + gProtectStructs[gBattlerAttacker].powderSelfDmg = TRUE; + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD + && (B_POWDER_RAIN < GEN_7 || !IsBattlerWeatherAffected(gBattlerAttacker, B_WEATHER_RAIN_PRIMAL))) + gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; + + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE + || HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE)) + gBattlescriptCurrInstr = BattleScript_MoveUsedPowder; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } + } +} + +static void CancellerProtean(u32 *effect) +{ + u32 moveType = GetMoveType(gCurrentMove); + if (ProteanTryChangeType(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), gCurrentMove, moveType)) + { + if (B_PROTEAN_LIBERO == GEN_9) + gDisableStructs[gBattlerAttacker].usedProteanLibero = TRUE; + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); + gBattlerAbility = gBattlerAttacker; + BattleScriptPushCursor(); + PrepareStringBattle(STRINGID_EMPTYSTRING3, gBattlerAttacker); + gBattleCommunication[MSG_DISPLAY] = 1; + gBattlescriptCurrInstr = BattleScript_ProteanActivates; + *effect = 1; + } +} + +static void CancellerPsychicTerrain(u32 *effect) +{ + if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN + && IsBattlerGrounded(gBattlerTarget) + && GetChosenMovePriority(gBattlerAttacker) > 0 + && gMovesInfo[gCurrentMove].target != MOVE_TARGET_ALL_BATTLERS + && gMovesInfo[gCurrentMove].target != MOVE_TARGET_OPPONENTS_FIELD + && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) + { + CancelMultiTurnMoves(gBattlerAttacker); + gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerExplodingDamp(u32 *effect) +{ + u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); + if (dampBattler && (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION + || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN)) + { + gBattleScripting.battler = dampBattler - 1; + gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + *effect = 1; + } +} + +static void CancellerMultihitMoves(u32 *effect) +{ + if (gMovesInfo[gCurrentMove].effect == EFFECT_MULTI_HIT) + { + u32 ability = GetBattlerAbility(gBattlerAttacker); + + if (ability == ABILITY_SKILL_LINK) + { + gMultiHitCounter = 5; + } + else if (ability == ABILITY_BATTLE_BOND + && gCurrentMove == MOVE_WATER_SHURIKEN + && gBattleMons[gBattlerAttacker].species == SPECIES_GRENINJA_ASH) + { + gMultiHitCounter = 3; + } + else + { + SetRandomMultiHitCounter(); + } + + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) + } + else if (gMovesInfo[gCurrentMove].strikeCount > 1) + { + if (gMovesInfo[gCurrentMove].effect == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) + { + gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10); + } + else + { + gMultiHitCounter = gMovesInfo[gCurrentMove].strikeCount; + + if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS + && CanTargetPartner(gBattlerAttacker, gBattlerTarget) + && TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget)) + gBattlerTarget = BATTLE_PARTNER(gBattlerTarget); + } + + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0) + } + else if (B_BEAT_UP >= GEN_5 && gMovesInfo[gCurrentMove].effect == EFFECT_BEAT_UP) + { + struct Pokemon* party = GetBattlerParty(gBattlerAttacker); + int i; + + for (i = 0; i < PARTY_SIZE; i++) + { + if (GetMonData(&party[i], MON_DATA_HP) + && GetMonData(&party[i], MON_DATA_SPECIES) != SPECIES_NONE + && !GetMonData(&party[i], MON_DATA_IS_EGG) + && !GetMonData(&party[i], MON_DATA_STATUS)) + gMultiHitCounter++; + } + + gBattleStruct->beatUpSlot = 0; + PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) + } + else + { + gMultiHitCounter = 0; + } +} + +static void CancellerZMoves(u32 *effect) +{ + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) + { + // For Z-Mirror Move, so it doesn't play the animation twice. + bool32 alreadyUsed = HasTrainerUsedGimmick(gBattlerAttacker, GIMMICK_Z_MOVE); + + // attacker has a queued z move + RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_Z_CRYSTAL); + SetGimmickAsActivated(gBattlerAttacker, GIMMICK_Z_MOVE); + + gBattleScripting.battler = gBattlerAttacker; + if (gProtectStructs[gBattlerAttacker].powderSelfDmg) + { + if (!alreadyUsed) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ZMoveActivatePowder; + } + } + else if (gMovesInfo[gCurrentMove].category == DAMAGE_CATEGORY_STATUS) + { + if (!alreadyUsed) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ZMoveActivateStatus; + } + } + else + { + if (!alreadyUsed) + { + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ZMoveActivateDamaging; + } + } + *effect = 1; + } +} + +static void CancellerMultiTargetMoves(u32 *effect) +{ + u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); + if (IsSpreadMove(moveTarget)) + { + for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) + { + if (gBattleStruct->bouncedMoveIsUsed && B_SIDE_OPPONENT == GetBattlerSide(battlerDef)) + continue; + + if (gBattlerAttacker == battlerDef + || !IsBattlerAlive(battlerDef) + || (moveTarget == MOVE_TARGET_BOTH && gBattlerAttacker == BATTLE_PARTNER(battlerDef)) + || IsBattlerProtected(gBattlerAttacker, battlerDef, gCurrentMove)) // Missing Invulnerable check + { + gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_NO_EFFECT; + gBattleStruct->noResultString[battlerDef] = TRUE; + } + else if (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, battlerDef, 0, 0, 0) + || (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetMovePriority(gBattlerAttacker, gCurrentMove) > 0)) + { + gBattleStruct->moveResultFlags[battlerDef] = 0; + gBattleStruct->noResultString[battlerDef] = TRUE; + } + else if (AbilityBattleEffects(ABILITYEFFECT_WOULD_ABSORB, battlerDef, 0, 0, gCurrentMove)) + { + gBattleStruct->moveResultFlags[battlerDef] = 0; + gBattleStruct->noResultString[battlerDef] = DO_ACCURACY_CHECK; + } + else + { + CalcTypeEffectivenessMultiplier(gCurrentMove, gMovesInfo[gCurrentMove].type, gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); + } + } + if (moveTarget == MOVE_TARGET_BOTH) + gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER_SIDE, gBattlerAttacker); + else + gBattleStruct->numSpreadTargets = CountAliveMonsInBattle(BATTLE_ALIVE_EXCEPT_BATTLER, gBattlerAttacker); + } +} + +static const MoveSuccessOrderCancellers sMoveSuccessOrderCancellers[] = +{ + [CANCELLER_FLAGS] = CancellerFlags, + [CANCELLER_STANCE_CHANGE_1] = CancellerStanceChangeOne, + [CANCELLER_SKY_DROP] = CancellerSkyDrop, + [CANCELLER_RECHARGE] = CancellerRecharge, + [CANCELLER_ASLEEP] = CancellerAsleep, + [CANCELLER_FROZEN] = CancellerFrozen, + [CANCELLER_OBEDIENCE] = CancellerObedience, + [CANCELLER_TRUANT] = CancellerTruant, + [CANCELLER_FLINCH] = CancellerFlinch, + [CANCELLER_IN_LOVE] = CancellerInLove, + [CANCELLER_DISABLED] = CancellerDisabled, + [CANCELLER_HEAL_BLOCKED] = CancellerHealBlocked, + [CANCELLER_GRAVITY] = CancellerGravity, + [CANCELLER_THROAT_CHOP] = CancellerThroatChop, + [CANCELLER_TAUNTED] = CancellerTaunted, + [CANCELLER_IMPRISONED] = CancellerImprisoned, + [CANCELLER_CONFUSED] = CancellerConfused, + [CANCELLER_PARALYSED] = CancellerParalysed, + [CANCELLER_BIDE] = CancellerBide, + [CANCELLER_THAW] = CancellerThaw, + [CANCELLER_STANCE_CHANGE_2] = CancellerStanceChangeTwo, + [CANCELLER_WEATHER_PRIMAL] = CancellerWeatherPrimal, + [CANCELLER_DYNAMAX_BLOCKED] = CancellerDynamaxBlocked, + [CANCELLER_POWDER_MOVE] = CancellerPowderMove, + [CANCELLER_POWDER_STATUS] = CancellerPowderStatus, + [CANCELLER_PROTEAN] = CancellerProtean, + [CANCELLER_PSYCHIC_TERRAIN] = CancellerPsychicTerrain, + [CANCELLER_EXPLODING_DAMP] = CancellerExplodingDamp, + [CANCELLER_MULTIHIT_MOVES] = CancellerMultihitMoves, + [CANCELLER_Z_MOVES] = CancellerZMoves, + [CANCELLER_MULTI_TARGET_MOVES] = CancellerMultiTargetMoves, +}; + +u32 AtkCanceller_MoveSuccessOrder(void) +{ + u32 effect = 0; + + while (gBattleStruct->atkCancellerTracker < CANCELLER_END && effect == 0) + { + sMoveSuccessOrderCancellers[gBattleStruct->atkCancellerTracker](&effect); + gBattleStruct->atkCancellerTracker++; + } if (effect == 2) { BtlController_EmitSetMonData(gBattlerAttacker, BUFFER_A, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerAttacker].status1); MarkBattlerForControllerExec(gBattlerAttacker); } - return effect; -} - -// After Protean Activation. -u8 AtkCanceller_UnableToUseMove2(void) -{ - u8 effect = 0; - - do - { - switch (gBattleStruct->atkCancellerTracker) - { - case CANCELLER_END: - gBattleStruct->atkCancellerTracker++; - case CANCELLER_PSYCHIC_TERRAIN: - if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN - && IsBattlerGrounded(gBattlerTarget) - && GetChosenMovePriority(gBattlerAttacker) > 0 - && gMovesInfo[gCurrentMove].target != MOVE_TARGET_ALL_BATTLERS - && gMovesInfo[gCurrentMove].target != MOVE_TARGET_OPPONENTS_FIELD - && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) - { - CancelMultiTurnMoves(gBattlerAttacker); - gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents; - gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; - effect = 1; - } - gBattleStruct->atkCancellerTracker++; - break; - case CANCELLER_END2: - break; - } - - } while (gBattleStruct->atkCancellerTracker != CANCELLER_END2 && effect == 0); return effect; } @@ -5658,7 +5764,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_COLOR_CHANGE: if (MoveResultHasEffect(battler) && move != MOVE_STRUGGLE - && gMovesInfo[move].power != 0 + && !IS_MOVE_STATUS(move) && IsBattlerTurnDamaged(gBattlerTarget) && !IS_BATTLER_OF_TYPE(battler, moveType) && moveType != TYPE_STELLAR @@ -8593,7 +8699,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) bool32 isProtected = FALSE; if ((IsZMove(move) || IsMaxMove(move)) - && (!gProtectStructs[battlerDef].maxGuarded || gMovesInfo[move].argument == MAX_EFFECT_BYPASS_PROTECT)) + && (!gProtectStructs[battlerDef].maxGuarded || gMovesInfo[move].argument.maxEffect == MAX_EFFECT_BYPASS_PROTECT)) isProtected = FALSE; // Z-Moves and Max Moves bypass protection (except Max Guard). else if (gProtectStructs[battlerDef].maxGuarded && IsMoveBlockedByMaxGuard(move)) isProtected = TRUE; @@ -8618,7 +8724,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) isProtected = TRUE; else if (gProtectStructs[battlerDef].spikyShielded) isProtected = TRUE; - else if (gProtectStructs[battlerDef].kingsShielded && gMovesInfo[move].power != 0) + else if (gProtectStructs[battlerDef].kingsShielded && !IS_MOVE_STATUS(move)) isProtected = TRUE; else if (gProtectStructs[battlerDef].maxGuarded) isProtected = TRUE; @@ -8966,7 +9072,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData break; case EFFECT_DOUBLE_POWER_ON_ARG_STATUS: // Comatose targets treated as if asleep - if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument + if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument.status && !((gMovesInfo[move].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) { basePower *= 2; @@ -10429,7 +10535,7 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move if (moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (gMovesInfo[move].effect == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == gMovesInfo[move].argument) + if (gMovesInfo[move].effect == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == gMovesInfo[move].argument.type) mod = UQ_4_12(2.0); if (moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(battlerDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); @@ -10567,7 +10673,7 @@ uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, { modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); if (gMovesInfo[move].effect == EFFECT_TWO_TYPED_MOVE) - modifier = CalcTypeEffectivenessMultiplierInternal(move, gMovesInfo[move].argument, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); + modifier = CalcTypeEffectivenessMultiplierInternal(move, gMovesInfo[move].argument.type, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); } if (recordAbilities) @@ -11537,7 +11643,7 @@ u16 GetUsedHeldItem(u32 battler) bool32 CantPickupItem(u32 battler) { // Used by RandomUniformExcept() for RNG_PICKUP - if (battler == gBattlerAttacker && gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK)) + if (battler == gBattlerAttacker && (B_PICKUP_WILD < GEN_9 || gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK))) return TRUE; return !(IsBattlerAlive(battler) && GetUsedHeldItem(battler) && gBattleStruct->canPickupItem & (1u << battler)); } @@ -11742,9 +11848,9 @@ bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect) return FALSE; } -bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument) +bool32 IsMoveEffectRemoveSpeciesType(u32 move, u32 moveEffect, u32 argument) { - return (gMovesInfo[move].argument == argument) && MoveHasAdditionalEffectSelf(move, moveEffect); + return (gMovesInfo[move].argument.type == argument) && MoveHasAdditionalEffectSelf(move, moveEffect); } bool32 MoveHasChargeTurnAdditionalEffect(u32 move) @@ -11763,8 +11869,13 @@ bool32 MoveIsAffectedBySheerForce(u32 move) u32 i; for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) { + if (gMovesInfo[move].additionalEffects[i].sheerForceBoost == SHEER_FORCE_NO_BOOST) + continue; + if (gMovesInfo[move].additionalEffects[i].chance > 0) return TRUE; + if (gMovesInfo[move].additionalEffects[i].sheerForceBoost == SHEER_FORCE_BOOST) + return TRUE; } return FALSE; } diff --git a/src/berry.c b/src/berry.c index 88278db47b..a287073df1 100644 --- a/src/berry.c +++ b/src/berry.c @@ -1711,11 +1711,13 @@ bool32 IsEnigmaBerryValid(void) const struct Berry *GetBerryInfo(u8 berry) { if (berry == ITEM_TO_BERRY(ITEM_ENIGMA_BERRY_E_READER) && IsEnigmaBerryValid()) + { #if FREE_ENIGMA_BERRY == FALSE return (struct Berry *)(&gSaveBlock1Ptr->enigmaBerry.berry); #else return &gBerries[0]; //never reached, but will appease the compiler gods #endif //FREE_ENIGMA_BERRY + } else { if (berry == BERRY_NONE || berry > ITEM_TO_BERRY(LAST_BERRY_INDEX)) @@ -2037,7 +2039,9 @@ static u8 CalcBerryYieldInternal(u16 max, u16 min, u8 water) u32 extraYield; if (water == 0 || OW_BERRY_MOISTURE) + { return min; + } else { randMin = (max - min) * (water - 1); diff --git a/src/berry_crush.c b/src/berry_crush.c index 2bb03e60a3..1f997708a7 100755 --- a/src/berry_crush.c +++ b/src/berry_crush.c @@ -3398,7 +3398,9 @@ static u32 Cmd_StopGame(struct BerryCrushGame *game, u8 *args) break; case 2: if (game->gfx.counter != 0) + { game->gfx.counter--; + } else { RunOrScheduleCommand(CMD_CLOSE_LINK, SCHEDULE_CMD, NULL); diff --git a/src/bike.c b/src/bike.c index b369883093..5bbf647ce9 100644 --- a/src/bike.c +++ b/src/bike.c @@ -389,7 +389,9 @@ static u8 AcroBikeHandleInputWheelieStanding(u8 *newDirection, u16 newKeys, u16 gPlayerAvatar.runningState = NOT_MOVING; if (heldKeys & B_BUTTON) + { gPlayerAvatar.bikeFrameCounter++; + } else { // B button was released. diff --git a/src/caps.c b/src/caps.c index 9c30e55527..941509c2a4 100644 --- a/src/caps.c +++ b/src/caps.c @@ -54,7 +54,7 @@ u32 GetSoftLevelCapExpValue(u32 level, u32 expValue) if (B_LEVEL_CAP_EXP_UP) { levelDifference = currentLevelCap - level; - if (levelDifference > ARRAY_COUNT(sExpScalingUp)) + if (levelDifference > ARRAY_COUNT(sExpScalingUp) - 1) return expValue + (expValue / sExpScalingUp[ARRAY_COUNT(sExpScalingUp) - 1]); else return expValue + (expValue / sExpScalingUp[levelDifference]); @@ -71,7 +71,7 @@ u32 GetSoftLevelCapExpValue(u32 level, u32 expValue) else if (B_EXP_CAP_TYPE == EXP_CAP_SOFT) { levelDifference = level - currentLevelCap; - if (levelDifference > ARRAY_COUNT(sExpScalingDown)) + if (levelDifference > ARRAY_COUNT(sExpScalingDown) - 1) return expValue / sExpScalingDown[ARRAY_COUNT(sExpScalingDown) - 1]; else return expValue / sExpScalingDown[levelDifference]; diff --git a/src/contest.c b/src/contest.c index e03d5e8b3b..f740b46b62 100644 --- a/src/contest.c +++ b/src/contest.c @@ -2767,7 +2767,9 @@ static void Task_EndAppeals(u8 taskId) CalculateFinalScores(); ContestClearGeneralTextWindow(); if (!(gLinkContestFlags & LINK_CONTEST_FLAG_IS_LINK)) + { BravoTrainerPokemonProfile_BeforeInterview1(eContestantStatus[gContestPlayerMonIndex].prevMove); + } else { CalculateContestLiveUpdateData(); diff --git a/src/contest_effect.c b/src/contest_effect.c index aa22f1d13d..0de31339f4 100644 --- a/src/contest_effect.c +++ b/src/contest_effect.c @@ -619,15 +619,18 @@ static void ContestEffect_QualityDependsOnTiming(void) { appeal = 10; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_NOT_VERY_WELL); - } else if (rval < 6) + } + else if (rval < 6) { appeal = 20; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_SLIGHTLY_WELL2); - } else if (rval < 8) + } + else if (rval < 8) { appeal = 40; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_PRETTY_WELL2); - } else if (rval < 9) + } + else if (rval < 9) { appeal = 60; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_APPEAL_VERY_WELL); @@ -868,7 +871,9 @@ static void ContestEffect_ScrambleNextTurnOrder(void) break; } else + { rval--; + } } } } @@ -908,7 +913,9 @@ static void ContestEffect_BadlyStartleMonsWithGoodAppeals(void) eContestAppealResults.jam = RoundUp(eContestAppealResults.jam); } else + { eContestAppealResults.jam = 10; + } eContestAppealResults.jamQueue[0] = i; eContestAppealResults.jamQueue[1] = CONTESTANT_NONE; if (WasAtLeastOneOpponentJammed()) @@ -1071,7 +1078,9 @@ static s16 RoundTowardsZero(s16 score) score -= 10 - absScore; } else + { score -= absScore; + } return score; } diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index ab70de3681..b9fcdd59f6 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1832,12 +1832,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_EERIE_SPELL] = - { - .battleScript = BattleScript_EffectEerieSpell, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_JUNGLE_HEALING] = { .battleScript = BattleScript_EffectJungleHealing, @@ -1901,42 +1895,12 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_GLITZY_GLOW] = - { - .battleScript = BattleScript_EffectGlitzyGlow, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_BADDY_BAD] = - { - .battleScript = BattleScript_EffectBaddyBad, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_SAPPY_SEED] = - { - .battleScript = BattleScript_EffectSappySeed, - .battleTvScore = 0, // TODO: Assign points - }, - - [EFFECT_FREEZY_FROST] = - { - .battleScript = BattleScript_EffectFreezyFrost, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_SPARKLY_SWIRL] = { .battleScript = BattleScript_EffectSparklySwirl, .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_PLASMA_FISTS] = - { - .battleScript = BattleScript_EffectPlasmaFists, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_HYPERSPACE_FURY] = { .battleScript = BattleScript_EffectHyperspaceFury, @@ -2134,12 +2098,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_SALT_CURE] = - { - .battleScript = BattleScript_EffectSaltCure, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_CHILLY_RECEPTION] = { .battleScript = BattleScript_EffectChillyReception, diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 8801942e53..726a0414f4 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -14459,11 +14459,11 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_ #endif //P_FAMILY_SHIELDON #if P_FAMILY_BURMY - const u32 gMonFrontPic_BurmyPlantCloak[] = INCBIN_U32("graphics/pokemon/burmy/anim_front.4bpp.lz"); - const u32 gMonPalette_BurmyPlantCloak[] = INCBIN_U32("graphics/pokemon/burmy/normal.gbapal.lz"); - const u32 gMonBackPic_BurmyPlantCloak[] = INCBIN_U32("graphics/pokemon/burmy/back.4bpp.lz"); - const u32 gMonShinyPalette_BurmyPlantCloak[] = INCBIN_U32("graphics/pokemon/burmy/shiny.gbapal.lz"); - const u8 gMonIcon_BurmyPlantCloak[] = INCBIN_U8("graphics/pokemon/burmy/icon.4bpp"); + const u32 gMonFrontPic_BurmyPlant[] = INCBIN_U32("graphics/pokemon/burmy/anim_front.4bpp.lz"); + const u32 gMonPalette_BurmyPlant[] = INCBIN_U32("graphics/pokemon/burmy/normal.gbapal.lz"); + const u32 gMonBackPic_BurmyPlant[] = INCBIN_U32("graphics/pokemon/burmy/back.4bpp.lz"); + const u32 gMonShinyPalette_BurmyPlant[] = INCBIN_U32("graphics/pokemon/burmy/shiny.gbapal.lz"); + const u8 gMonIcon_BurmyPlant[] = INCBIN_U8("graphics/pokemon/burmy/icon.4bpp"); #if P_FOOTPRINTS const u8 gMonFootprint_Burmy[] = INCBIN_U8("graphics/pokemon/burmy/footprint.1bpp"); #endif //P_FOOTPRINTS @@ -14481,24 +14481,24 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_ const u8 gMonIcon_BurmyTrash[] = INCBIN_U8("graphics/pokemon/burmy/trash/icon.4bpp"); #if OW_POKEMON_OBJECT_EVENTS - const u32 gObjectEventPic_BurmyPlantCloak[] = INCBIN_COMP("graphics/pokemon/burmy/overworld.4bpp"); + const u32 gObjectEventPic_BurmyPlant[] = INCBIN_COMP("graphics/pokemon/burmy/overworld.4bpp"); const u32 gObjectEventPic_BurmySandy[] = INCBIN_COMP("graphics/pokemon/burmy/sandy/overworld.4bpp"); const u32 gObjectEventPic_BurmyTrash[] = INCBIN_COMP("graphics/pokemon/burmy/trash/overworld.4bpp"); #if OW_PKMN_OBJECTS_SHARE_PALETTES == FALSE - const u32 gOverworldPalette_BurmyPlantCloak[] = INCBIN_U32("graphics/pokemon/burmy/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_BurmyPlant[] = INCBIN_U32("graphics/pokemon/burmy/overworld_normal.gbapal.lz"); const u32 gOverworldPalette_BurmySandy[] = INCBIN_U32("graphics/pokemon/burmy/sandy/overworld_normal.gbapal.lz"); const u32 gOverworldPalette_BurmyTrash[] = INCBIN_U32("graphics/pokemon/burmy/trash/overworld_normal.gbapal.lz"); - const u32 gShinyOverworldPalette_BurmyPlantCloak[] = INCBIN_U32("graphics/pokemon/burmy/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_BurmyPlant[] = INCBIN_U32("graphics/pokemon/burmy/overworld_shiny.gbapal.lz"); const u32 gShinyOverworldPalette_BurmySandy[] = INCBIN_U32("graphics/pokemon/burmy/sandy/overworld_shiny.gbapal.lz"); const u32 gShinyOverworldPalette_BurmyTrash[] = INCBIN_U32("graphics/pokemon/burmy/trash/overworld_shiny.gbapal.lz"); #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_WormadamPlantCloak[] = INCBIN_U32("graphics/pokemon/wormadam/anim_front.4bpp.lz"); - const u32 gMonPalette_WormadamPlantCloak[] = INCBIN_U32("graphics/pokemon/wormadam/normal.gbapal.lz"); - const u32 gMonBackPic_WormadamPlantCloak[] = INCBIN_U32("graphics/pokemon/wormadam/back.4bpp.lz"); - const u32 gMonShinyPalette_WormadamPlantCloak[] = INCBIN_U32("graphics/pokemon/wormadam/shiny.gbapal.lz"); - const u8 gMonIcon_WormadamPlantCloak[] = INCBIN_U8("graphics/pokemon/wormadam/icon.4bpp"); + const u32 gMonFrontPic_WormadamPlant[] = INCBIN_U32("graphics/pokemon/wormadam/anim_front.4bpp.lz"); + const u32 gMonPalette_WormadamPlant[] = INCBIN_U32("graphics/pokemon/wormadam/normal.gbapal.lz"); + const u32 gMonBackPic_WormadamPlant[] = INCBIN_U32("graphics/pokemon/wormadam/back.4bpp.lz"); + const u32 gMonShinyPalette_WormadamPlant[] = INCBIN_U32("graphics/pokemon/wormadam/shiny.gbapal.lz"); + const u8 gMonIcon_WormadamPlant[] = INCBIN_U8("graphics/pokemon/wormadam/icon.4bpp"); #if P_FOOTPRINTS const u8 gMonFootprint_Wormadam[] = INCBIN_U8("graphics/pokemon/wormadam/footprint.1bpp"); #endif //P_FOOTPRINTS @@ -14516,14 +14516,14 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_ const u8 gMonIcon_WormadamTrash[] = INCBIN_U8("graphics/pokemon/wormadam/trash/icon.4bpp"); #if OW_POKEMON_OBJECT_EVENTS - const u32 gObjectEventPic_WormadamPlantCloak[] = INCBIN_COMP("graphics/pokemon/wormadam/overworld.4bpp"); + const u32 gObjectEventPic_WormadamPlant[] = INCBIN_COMP("graphics/pokemon/wormadam/overworld.4bpp"); const u32 gObjectEventPic_WormadamSandy[] = INCBIN_COMP("graphics/pokemon/wormadam/sandy/overworld.4bpp"); const u32 gObjectEventPic_WormadamTrash[] = INCBIN_COMP("graphics/pokemon/wormadam/trash/overworld.4bpp"); #if OW_PKMN_OBJECTS_SHARE_PALETTES == FALSE - const u32 gOverworldPalette_WormadamPlantCloak[] = INCBIN_U32("graphics/pokemon/wormadam/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_WormadamPlant[] = INCBIN_U32("graphics/pokemon/wormadam/overworld_normal.gbapal.lz"); const u32 gOverworldPalette_WormadamSandy[] = INCBIN_U32("graphics/pokemon/wormadam/sandy/overworld_normal.gbapal.lz"); const u32 gOverworldPalette_WormadamTrash[] = INCBIN_U32("graphics/pokemon/wormadam/trash/overworld_normal.gbapal.lz"); - const u32 gShinyOverworldPalette_WormadamPlantCloak[] = INCBIN_U32("graphics/pokemon/wormadam/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_WormadamPlant[] = INCBIN_U32("graphics/pokemon/wormadam/overworld_shiny.gbapal.lz"); const u32 gShinyOverworldPalette_WormadamSandy[] = INCBIN_U32("graphics/pokemon/wormadam/sandy/overworld_shiny.gbapal.lz"); const u32 gShinyOverworldPalette_WormadamTrash[] = INCBIN_U32("graphics/pokemon/wormadam/trash/overworld_shiny.gbapal.lz"); #endif //OW_PKMN_OBJECTS_SHARE_PALETTES diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 49d35c0897..2c28621286 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -17,11 +17,6 @@ #define BINDING_TURNS "2 to 5" #endif -/* First arg is the charge turn string id, second arg depends on effect -EFFECT_SEMI_INVULNERABLE/EFFECT_SKY_DROP: semi-invulnerable STATUS3 to apply to battler -EFFECT_TWO_TURNS_ATTACK/EFFECT_SOLAR_BEAM: weather in which to skip charge turn */ -#define TWO_TURN_ARG(stringid, ...) (stringid) __VA_OPT__(| ((__VA_ARGS__) << 16)) - // Shared Move Description entries const u8 gNotDoneYetDescription[] = _( @@ -438,7 +433,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .windMove = B_EXTRAPOLATED_MOVE_FLAGS, - .argument = TWO_TURN_ARG(STRINGID_PKMNWHIPPEDWHIRLWIND), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNWHIPPEDWHIRLWIND }, .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -586,7 +581,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNFLEWHIGH, COMPRESS_BITS(STATUS3_ON_AIR)), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNFLEWHIGH, .status = COMPRESS_BITS(STATUS3_ON_AIR) }, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -1332,7 +1327,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 20, + .argument = { .fixedDamage = 20 }, .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -1874,7 +1869,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, .contestEffect = CONTEST_EFFECT_STARTLE_PREV_MON, @@ -1896,7 +1891,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .zMove = { .powerOverride = 120 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, @@ -1999,7 +1994,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .sleepTalkBanned = TRUE, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNTOOKSUNLIGHT, B_WEATHER_SUN), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKSUNLIGHT, .status = B_WEATHER_SUN }, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -2151,7 +2146,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_4) || (B_UPDATED_MOVE_FLAGS < GEN_3), - .argument = 40, + .argument = { .fixedDamage = 40 }, .contestEffect = CONTEST_EFFECT_BETTER_WHEN_LATER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = COMBO_STARTER_DRAGON_RAGE, @@ -2370,7 +2365,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .instructBanned = TRUE, .assistBanned = TRUE, .skyBattleBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNDUGHOLE, COMPRESS_BITS(STATUS3_UNDERGROUND)), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNDUGHOLE, .status = COMPRESS_BITS(STATUS3_UNDERGROUND) }, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -2986,7 +2981,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, - .argument = STATUS2_FOCUS_ENERGY, + .argument = { .status = STATUS2_FOCUS_ENERGY }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, @@ -3343,7 +3338,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .makesContact = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNLOWEREDHEAD), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNLOWEREDHEAD }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_DEF_PLUS_1, .self = TRUE, @@ -3622,7 +3617,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .makesContact = TRUE, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, @@ -3673,7 +3668,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .criticalHitStage = B_UPDATED_MOVE_DATA >= GEN_3, .sleepTalkBanned = TRUE, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(B_UPDATED_MOVE_DATA >= GEN_4 ? STRINGID_CLOAKEDINAHARSHLIGHT : STRINGID_PKMNISGLOWING), + .argument.twoTurnAttack = { .stringId = B_UPDATED_MOVE_DATA >= GEN_4 ? STRINGID_CLOAKEDINAHARSHLIGHT : STRINGID_PKMNISGLOWING }, #if B_UPDATED_MOVE_DATA >= GEN_3 .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FLINCH, @@ -5155,7 +5150,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .ignoresKingsRock = (B_UPDATED_MOVE_FLAGS == GEN_3 || B_UPDATED_MOVE_FLAGS == GEN_4), .healingMove = B_HEAL_BLOCKING >= GEN_6, .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, @@ -6735,7 +6730,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = STATUS1_PARALYSIS, + .argument = { .status = STATUS1_PARALYSIS }, .makesContact = TRUE, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_STATUS, @@ -7391,7 +7386,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .instructBanned = TRUE, .assistBanned = TRUE, .skyBattleBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNHIDUNDERWATER, COMPRESS_BITS(STATUS3_UNDERWATER)), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNHIDUNDERWATER, .status = COMPRESS_BITS(STATUS3_UNDERWATER) }, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_DIVE, @@ -8599,7 +8594,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNSPRANGUP, COMPRESS_BITS(STATUS3_ON_AIR)), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNSPRANGUP, .status = COMPRESS_BITS(STATUS3_ON_AIR) }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, @@ -9048,7 +9043,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = STATUS1_SLEEP, + .argument = { .status = STATUS1_SLEEP }, .makesContact = TRUE, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_STATUS, @@ -10268,7 +10263,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .makesContact = TRUE, .punchingMove = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, @@ -11272,7 +11267,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = HOLD_EFFECT_PLATE, + .argument = { .holdEffect = HOLD_EFFECT_PLATE }, .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -11702,7 +11697,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_VANISHEDINSTANTLY, COMPRESS_BITS(STATUS3_PHANTOM_FORCE)), + .argument.twoTurnAttack = { .stringId = STRINGID_VANISHEDINSTANTLY, .status = COMPRESS_BITS(STATUS3_PHANTOM_FORCE) }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), @@ -11752,7 +11747,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_USER, .priority = 3, .category = DAMAGE_CATEGORY_STATUS, - .argument = TRUE, // Protects the whole side. + .argument = { .protect.side = TRUE, }, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .snatchAffected = TRUE, .ignoresProtect = TRUE, @@ -11867,7 +11862,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = STATUS1_PSN_ANY, + .argument = { .status = STATUS1_PSN_ANY }, .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, @@ -12513,7 +12508,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_USER, .priority = 3, .category = DAMAGE_CATEGORY_STATUS, - .argument = TRUE, // Protects the whole side. + .argument = { .protect.side = TRUE, }, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .snatchAffected = TRUE, .ignoresProtect = TRUE, @@ -12642,7 +12637,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .zMove = { .powerOverride = 160 }, - .argument = STATUS1_ANY, + .argument = { .status = STATUS1_ANY }, .contestEffect = CONTEST_EFFECT_BETTER_IF_SAME_TYPE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -12669,7 +12664,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNTOOKTARGETHIGH, COMPRESS_BITS(STATUS3_ON_AIR)), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKTARGETHIGH, .status = COMPRESS_BITS(STATUS3_ON_AIR) }, .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -13249,7 +13244,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .makesContact = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, @@ -13585,7 +13580,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = HOLD_EFFECT_DRIVE, + .argument = { .holdEffect = HOLD_EFFECT_DRIVE }, .metronomeBanned = TRUE, .contestEffect = CONTEST_EFFECT_EXCITE_AUDIENCE_IN_ANY_CONTEST, .contestCategory = CONTEST_CATEGORY_COOL, @@ -13608,7 +13603,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = STATUS1_SLEEP, + .argument = { .status = STATUS1_SLEEP }, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, .metronomeBanned = TRUE, @@ -13766,7 +13761,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .metronomeBanned = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_CLOAKEDINAFREEZINGLIGHT), + .argument.twoTurnAttack = { .stringId = STRINGID_CLOAKEDINAFREEZINGLIGHT }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, @@ -13795,7 +13790,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .metronomeBanned = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_CLOAKEDINAFREEZINGLIGHT), + .argument.twoTurnAttack = { .stringId = STRINGID_CLOAKEDINAFREEZINGLIGHT }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BURN, .chance = 30, @@ -13946,7 +13941,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .zMove = { .powerOverride = 170 }, - .argument = TYPE_FLYING, + .argument = { .type = TYPE_FLYING }, .makesContact = TRUE, .minimizeDoubleDamage = TRUE, .gravityBanned = TRUE, @@ -13972,7 +13967,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_USER, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, - .argument = TRUE, // Protects the whole side. + .argument = { .protect.side = TRUE }, .zMove = { .effect = Z_EFFECT_DEF_UP_1 }, .snatchAffected = TRUE, .ignoresProtect = TRUE, @@ -14108,7 +14103,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_VANISHEDINSTANTLY, COMPRESS_BITS(STATUS3_PHANTOM_FORCE)), + .argument.twoTurnAttack = { .stringId = STRINGID_VANISHEDINSTANTLY, .status = COMPRESS_BITS(STATUS3_PHANTOM_FORCE) }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), @@ -14133,7 +14128,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, - .argument = TYPE_GHOST, + .argument = { .type = TYPE_GHOST }, .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .magicCoatAffected = TRUE, .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, @@ -14206,7 +14201,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_FOES_AND_ALLY, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .healingMove = B_HEAL_BLOCKING >= GEN_6, .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_BEAUTY, @@ -14229,7 +14224,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, - .argument = TYPE_GRASS, + .argument = { .type = TYPE_GRASS }, .zMove = { .effect = Z_EFFECT_ALL_STATS_UP_1 }, .magicCoatAffected = TRUE, .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, @@ -14279,7 +14274,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = TYPE_WATER, + .argument = { .type = TYPE_WATER }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FREEZE_OR_FROSTBITE, .chance = 10, @@ -14374,7 +14369,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 75, // restores 75% HP instead of 50% HP + .argument = { .absorbPercentage = 75 }, .makesContact = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, @@ -14398,7 +14393,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_USER, .priority = 3, .category = DAMAGE_CATEGORY_STATUS, - .argument = TRUE, // Protects the whole side. + .argument = { .protect.side = TRUE, }, .zMove = { .effect = Z_EFFECT_SPDEF_UP_1 }, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, @@ -14970,7 +14965,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .skyBattleBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKNMABSORBINGPOWER), + .argument.twoTurnAttack = { .stringId = STRINGID_PKNMABSORBINGPOWER }, .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, @@ -15268,7 +15263,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 75, // restores 75% HP instead of 50% HP + .argument = { .absorbPercentage = 75 }, .healingMove = B_HEAL_BLOCKING >= GEN_6, .contestEffect = CONTEST_EFFECT_STARTLE_MON_WITH_JUDGES_ATTENTION, .contestCategory = CONTEST_CATEGORY_COOL, @@ -15510,7 +15505,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 2, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MOVE_FIRST_IMPRESSION, + .argument = { .moveProperty = MOVE_FIRST_IMPRESSION }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_BETTER_IF_FIRST, .contestCategory = CONTEST_CATEGORY_COOL, @@ -15608,7 +15603,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_FOES_AND_ALLY, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = STATUS1_BURN, + .argument = { .status = STATUS1_BURN }, .ignoresSubstitute = B_UPDATED_MOVE_FLAGS >= GEN_6, .soundMove = TRUE, .additionalEffects = ADDITIONAL_EFFECTS({ @@ -15664,7 +15659,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_RESET_STATS }, - .argument = MOVE_EFFECT_FLORAL_HEALING, + .argument = { .moveProperty = MOVE_EFFECT_FLORAL_HEALING }, .mirrorMoveBanned = TRUE, .healingMove = TRUE, .magicCoatAffected = TRUE, @@ -15739,7 +15734,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .slicingMove = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_PKMNTOOKSUNLIGHT, B_WEATHER_SUN), + .argument.twoTurnAttack = { .stringId = STRINGID_PKMNTOOKSUNLIGHT, .status = B_WEATHER_SUN }, .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, @@ -16056,7 +16051,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .thawsUser = TRUE, - .argument = TYPE_FIRE, + .argument = { .type = TYPE_FIRE }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_ARG_TYPE, .self = TRUE, @@ -16720,7 +16715,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = HOLD_EFFECT_MEMORY, + .argument = { .holdEffect = HOLD_EFFECT_MEMORY }, .makesContact = TRUE, .contestEffect = CONTEST_EFFECT_SCRAMBLE_NEXT_TURN_ORDER, .contestCategory = CONTEST_CATEGORY_BEAUTY, @@ -16757,7 +16752,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Hits with electrical fists.\n" "Normal moves turn Electric."), - .effect = EFFECT_PLASMA_FISTS, + .effect = EFFECT_HIT, .power = 100, .type = TYPE_ELECTRIC, .accuracy = 100, @@ -16772,6 +16767,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, .contestComboMoves = {0}, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_ION_DELUGE, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_PlasmaFists, }, @@ -16820,6 +16820,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_EVS_PLUS_1, .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), #endif .battleAnimScript = gBattleAnimMove_ZippyZap, @@ -16869,6 +16870,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FLINCH, .chance = 30, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), .battleAnimScript = gBattleAnimMove_FloatyFall, }, @@ -16910,7 +16912,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = B_UPDATED_MOVE_DATA >= GEN_8 ? 100 : 50, // restores 100% HP instead of 50% HP + .argument = { .absorbPercentage = B_UPDATED_MOVE_DATA >= GEN_8 ? 100 : 50 }, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, .healingMove = B_HEAL_BLOCKING >= GEN_6, @@ -16936,6 +16938,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), .battleAnimScript = gBattleAnimMove_BuzzyBuzz, }, @@ -16961,6 +16964,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BURN, .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, }), .battleAnimScript = gBattleAnimMove_SizzlySlide, }, @@ -16971,7 +16975,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Telekinetic force that sets\n" "wall, lowering Sp. Atk damage."), - .effect = EFFECT_GLITZY_GLOW, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 80 : 90, .type = TYPE_PSYCHIC, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 95 : 100, @@ -16981,6 +16985,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_LIGHT_SCREEN, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_GlitzyGlow, }, @@ -16990,7 +16999,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Acting badly, attacks. Sets\n" "wall, lowering Attack damage."), - .effect = EFFECT_BADDY_BAD, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 80 : 90, .type = TYPE_DARK, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 95 : 100, @@ -17000,6 +17009,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_REFLECT, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_BaddyBad, }, @@ -17009,7 +17023,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Giant stalk scatters seeds\n" "that drain HP every turn."), - .effect = EFFECT_SAPPY_SEED, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 100 : 90, .type = TYPE_GRASS, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 90 : 100, @@ -17020,6 +17034,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .magicCoatAffected = TRUE, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_LEECH_SEED, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_SappySeed, }, @@ -17029,7 +17048,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Crystal from cold haze hits.\n" "Eliminates all stat changes."), - .effect = EFFECT_FREEZY_FROST, + .effect = EFFECT_HIT, .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 100 : 90, .type = TYPE_ICE, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 90 : 100, @@ -17039,6 +17058,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_HAZE, + .chance = 100, + .sheerForceBoost = SHEER_FORCE_NO_BOOST, + }), .battleAnimScript = gBattleAnimMove_FreezyFrost, }, @@ -17048,7 +17072,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Wrap foe with whirlwind of\n" "scent. Heals party's status."), - .effect = EFFECT_SPARKLY_SWIRL, + .effect = EFFECT_SPARKLY_SWIRL, // Temprorary .power = B_UPDATED_MOVE_DATA >= GEN_8 ? 120 : 90, .type = TYPE_FAIRY, .accuracy = B_UPDATED_MOVE_DATA >= GEN_8 ? 85 : 100, @@ -17058,6 +17082,11 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .mirrorMoveBanned = B_UPDATED_MOVE_FLAGS < GEN_8, .metronomeBanned = TRUE, + // .additionalEffects = ADDITIONAL_EFFECTS({ + // .moveEffect = 0, // MOVE_EFFECT_AROMATHERAPY, Added 0 for Sheer Force boost + // .chance = 100, + // .sheerForceBoost = SHEER_FORCE_NO_BOOST, + // }), .battleAnimScript = gBattleAnimMove_SparklySwirl, }, @@ -17273,7 +17302,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_STATUS, - .argument = TYPE_PSYCHIC, + .argument = { .type = TYPE_PSYCHIC }, .magicCoatAffected = TRUE, .powderMove = TRUE, .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, @@ -18019,7 +18048,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .argument = ARG_TRY_REMOVE_TERRAIN_FAIL, // Remove a field terrain if there is one and hit, otherwise fail. + .argument = { .moveProperty = ARG_TRY_REMOVE_TERRAIN_FAIL }, // Remove a field terrain if there is one and hit, otherwise fail. .skyBattleBanned = TRUE, .contestEffect = CONTEST_EFFECT_WORSEN_CONDITION_OF_PREV_MONS, .contestCategory = CONTEST_CATEGORY_TOUGH, @@ -18042,7 +18071,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MOVE_EFFECT_SCALE_SHOT, + .argument = { .moveProperty = MOVE_EFFECT_SCALE_SHOT }, .contestEffect = CONTEST_EFFECT_NEXT_APPEAL_EARLIER, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -18065,7 +18094,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .instructBanned = TRUE, - .argument = TWO_TURN_ARG(STRINGID_METEORBEAMCHARGING), + .argument.twoTurnAttack = { .stringId = STRINGID_METEORBEAMCHARGING }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_SP_ATK_PLUS_1, .self = TRUE, @@ -18682,7 +18711,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Attacks with psychic power.\n" "Foe's last move has 3 PP cut."), - .effect = EFFECT_EERIE_SPELL, + .effect = EFFECT_HIT, .power = 80, .type = TYPE_PSYCHIC, .accuracy = 100, @@ -18696,6 +18725,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, .contestComboMoves = {0}, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_EERIE_SPELL, + .chance = 100, + }), .battleAnimScript = gBattleAnimMove_EerieSpell, }, @@ -18971,7 +19004,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = STATUS1_PSN_ANY, + .argument = { .status = STATUS1_PSN_ANY }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_POISON, .chance = 50, @@ -19083,7 +19116,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = STATUS1_ANY, + .argument = { .status = STATUS1_ANY }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BURN, .chance = 30, @@ -19446,7 +19479,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, - .argument = ARG_TRY_REMOVE_TERRAIN_HIT, // Remove the active field terrain if there is one. + .argument = { .moveProperty = ARG_TRY_REMOVE_TERRAIN_HIT }, // Remove the active field terrain if there is one. .skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS, .battleAnimScript = gBattleAnimMove_IceSpinner, }, @@ -19497,7 +19530,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Hurts foe every turn. Double\n" "damage to Steel and Water."), - .effect = EFFECT_SALT_CURE, + .effect = EFFECT_HIT, .power = 40, .type = TYPE_ROCK, .accuracy = 100, @@ -19506,6 +19539,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, .metronomeBanned = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_SALT_CURE, + .chance = 100, + }), .battleAnimScript = gBattleAnimMove_SaltCure, }, @@ -20028,7 +20065,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .makesContact = TRUE, .slicingMove = TRUE, .healingMove = TRUE, @@ -20051,7 +20088,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_PHYSICAL, .makesContact = TRUE, .metronomeBanned = TRUE, - .argument = TYPE_ELECTRIC, + .argument = { .type = TYPE_ELECTRIC }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_REMOVE_ARG_TYPE, .self = TRUE, @@ -20330,7 +20367,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_BOTH, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = 50, + .argument = { .absorbPercentage = 50 }, .thawsUser = TRUE, .metronomeBanned = TRUE, .healingMove = B_EXTRAPOLATED_MOVE_FLAGS, @@ -20397,12 +20434,13 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = TWO_TURN_ARG(STRINGID_ELECTROSHOTCHARGING, B_WEATHER_RAIN), + .argument.twoTurnAttack = { .stringId = STRINGID_ELECTROSHOTCHARGING, .status = B_WEATHER_RAIN }, .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_SP_ATK_PLUS_1, .self = TRUE, .onChargeTurnOnly = TRUE, - }, SHEER_FORCE_HACK), + .sheerForceBoost = SHEER_FORCE_BOOST, + }), .battleAnimScript = gBattleAnimMove_ElectroShot, }, @@ -20676,6 +20714,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_TOXIC, .chance = 50, + .sheerForceBoost = SHEER_FORCE_BOOST, }), .battleAnimScript = gBattleAnimMove_MalignantChain, }, @@ -21021,7 +21060,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, - .argument = ARG_SET_PSYCHIC_TERRAIN, // Set Psychic Terrain. If there's a different field terrain active, overwrite it. + .argument = { .moveProperty = ARG_SET_PSYCHIC_TERRAIN }, // Set Psychic Terrain. If there's a different field terrain active, overwrite it. .battleAnimScript = gBattleAnimMove_GenesisSupernova, }, [MOVE_SINISTER_ARROW_RAID] = @@ -21078,7 +21117,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = ARG_TRY_REMOVE_TERRAIN_HIT, // Remove the active field terrain if there is one. + .argument = { .moveProperty = ARG_TRY_REMOVE_TERRAIN_HIT }, // Remove the active field terrain if there is one. .battleAnimScript = gBattleAnimMove_SplinteredStormshards, }, [MOVE_LETS_SNUGGLE_FOREVER] = @@ -21217,7 +21256,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_SUN, + .argument = { .maxEffect = MAX_EFFECT_SUN }, .battleAnimScript = gBattleAnimMove_MaxFlare, }, @@ -21233,7 +21272,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_SP_ATK, + .argument = { .maxEffect = MAX_EFFECT_LOWER_SP_ATK }, .battleAnimScript = gBattleAnimMove_MaxFlutterby, }, @@ -21249,7 +21288,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_ELECTRIC_TERRAIN, + .argument = { .maxEffect = MAX_EFFECT_ELECTRIC_TERRAIN }, .battleAnimScript = gBattleAnimMove_MaxLightning, }, @@ -21265,7 +21304,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_SPEED, + .argument = { .maxEffect = MAX_EFFECT_LOWER_SPEED }, .battleAnimScript = gBattleAnimMove_MaxStrike, }, @@ -21281,7 +21320,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RAISE_TEAM_ATTACK, + .argument = { .maxEffect = MAX_EFFECT_RAISE_TEAM_ATTACK }, .battleAnimScript = gBattleAnimMove_MaxKnuckle, }, @@ -21297,7 +21336,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_DEFENSE, + .argument = { .maxEffect = MAX_EFFECT_LOWER_DEFENSE }, .battleAnimScript = gBattleAnimMove_MaxPhantasm, }, @@ -21313,7 +21352,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_HAIL, + .argument = { .maxEffect = MAX_EFFECT_HAIL }, .battleAnimScript = gBattleAnimMove_MaxHailstorm, }, @@ -21329,7 +21368,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RAISE_TEAM_SP_ATK, + .argument = { .maxEffect = MAX_EFFECT_RAISE_TEAM_SP_ATK }, .battleAnimScript = gBattleAnimMove_MaxOoze, }, @@ -21345,7 +21384,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RAIN, + .argument = { .maxEffect = MAX_EFFECT_RAIN }, .battleAnimScript = gBattleAnimMove_MaxGeyser, }, @@ -21361,7 +21400,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RAISE_TEAM_SPEED, + .argument = { .maxEffect = MAX_EFFECT_RAISE_TEAM_SPEED }, .battleAnimScript = gBattleAnimMove_MaxAirstream, }, @@ -21377,7 +21416,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_MISTY_TERRAIN, + .argument = { .maxEffect = MAX_EFFECT_MISTY_TERRAIN }, .battleAnimScript = gBattleAnimMove_MaxStarfall, }, @@ -21393,7 +21432,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_ATTACK, + .argument = { .maxEffect = MAX_EFFECT_LOWER_ATTACK }, .battleAnimScript = gBattleAnimMove_MaxWyrmwind, }, @@ -21409,7 +21448,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_PSYCHIC_TERRAIN, + .argument = { .maxEffect = MAX_EFFECT_PSYCHIC_TERRAIN }, .battleAnimScript = gBattleAnimMove_MaxMindstorm, }, @@ -21425,7 +21464,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_SANDSTORM, + .argument = { .maxEffect = MAX_EFFECT_SANDSTORM }, .battleAnimScript = gBattleAnimMove_MaxRockfall, }, @@ -21441,7 +21480,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RAISE_TEAM_SP_DEF, + .argument = { .maxEffect = MAX_EFFECT_RAISE_TEAM_SP_DEF }, .skyBattleBanned = B_EXTRAPOLATED_MOVE_FLAGS, .battleAnimScript = gBattleAnimMove_MaxQuake, }, @@ -21458,7 +21497,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_SP_DEF, + .argument = { .maxEffect = MAX_EFFECT_LOWER_SP_DEF }, .battleAnimScript = gBattleAnimMove_MaxDarkness, }, @@ -21474,7 +21513,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_GRASSY_TERRAIN, + .argument = { .maxEffect = MAX_EFFECT_GRASSY_TERRAIN }, .battleAnimScript = gBattleAnimMove_MaxOvergrowth, }, @@ -21490,7 +21529,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RAISE_TEAM_DEFENSE, + .argument = { .maxEffect = MAX_EFFECT_RAISE_TEAM_DEFENSE }, .battleAnimScript = gBattleAnimMove_MaxSteelspike, }, @@ -21506,7 +21545,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_VINE_LASH, + .argument = { .maxEffect = MAX_EFFECT_VINE_LASH }, .battleAnimScript = gBattleAnimMove_GMaxVineLash, }, @@ -21522,7 +21561,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_WILDFIRE, + .argument = { .maxEffect = MAX_EFFECT_WILDFIRE }, .battleAnimScript = gBattleAnimMove_GMaxWildfire, }, @@ -21538,7 +21577,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_CANNONADE, + .argument = { .maxEffect = MAX_EFFECT_CANNONADE }, .battleAnimScript = gBattleAnimMove_GMaxCannonade, }, @@ -21554,7 +21593,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_EFFECT_SPORE_FOES, + .argument = { .maxEffect = MAX_EFFECT_EFFECT_SPORE_FOES }, .battleAnimScript = gBattleAnimMove_GMaxBefuddle, }, @@ -21570,7 +21609,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_PARALYZE_FOES, + .argument = { .maxEffect = MAX_EFFECT_PARALYZE_FOES }, .battleAnimScript = gBattleAnimMove_GMaxVoltCrash, }, @@ -21586,7 +21625,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_CONFUSE_FOES_PAY_DAY, + .argument = { .maxEffect = MAX_EFFECT_CONFUSE_FOES_PAY_DAY }, .battleAnimScript = gBattleAnimMove_GMaxGoldRush, }, @@ -21602,7 +21641,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_CRIT_PLUS, + .argument = { .maxEffect = MAX_EFFECT_CRIT_PLUS }, .battleAnimScript = gBattleAnimMove_GMaxChiStrike, }, @@ -21618,7 +21657,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_MEAN_LOOK, + .argument = { .maxEffect = MAX_EFFECT_MEAN_LOOK }, .battleAnimScript = gBattleAnimMove_GMaxTerror, }, @@ -21634,7 +21673,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_SPEED_2_FOES, + .argument = { .maxEffect = MAX_EFFECT_LOWER_SPEED_2_FOES }, .battleAnimScript = gBattleAnimMove_GMaxFoamBurst, }, @@ -21650,7 +21689,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_AURORA_VEIL, + .argument = { .maxEffect = MAX_EFFECT_AURORA_VEIL }, .battleAnimScript = gBattleAnimMove_GMaxResonance, }, @@ -21666,7 +21705,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_INFATUATE_FOES, + .argument = { .maxEffect = MAX_EFFECT_INFATUATE_FOES }, .battleAnimScript = gBattleAnimMove_GMaxCuddle, }, @@ -21682,7 +21721,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_RECYCLE_BERRIES, + .argument = { .maxEffect = MAX_EFFECT_RECYCLE_BERRIES }, .battleAnimScript = gBattleAnimMove_GMaxReplenish, }, @@ -21698,7 +21737,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_POISON_FOES, + .argument = { .maxEffect = MAX_EFFECT_POISON_FOES }, .battleAnimScript = gBattleAnimMove_GMaxMalodor, }, @@ -21714,7 +21753,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_TORMENT_FOES, + .argument = { .maxEffect = MAX_EFFECT_TORMENT_FOES }, .battleAnimScript = gBattleAnimMove_GMaxMeltdown, }, @@ -21730,7 +21769,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_FIXED_POWER, + .argument = { .maxEffect = MAX_EFFECT_FIXED_POWER }, .ignoresTargetAbility = TRUE, .battleAnimScript = gBattleAnimMove_GMaxDrumSolo, }, @@ -21747,7 +21786,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_FIXED_POWER, + .argument = { .maxEffect = MAX_EFFECT_FIXED_POWER }, .ignoresTargetAbility = TRUE, .battleAnimScript = gBattleAnimMove_GMaxFireball, }, @@ -21764,7 +21803,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_FIXED_POWER, + .argument = { .maxEffect = MAX_EFFECT_FIXED_POWER }, .ignoresTargetAbility = TRUE, .battleAnimScript = gBattleAnimMove_GMaxHydrosnipe, }, @@ -21781,7 +21820,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_DEFOG, + .argument = { .maxEffect = MAX_EFFECT_DEFOG }, .battleAnimScript = gBattleAnimMove_GMaxWindRage, }, @@ -21797,7 +21836,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_GRAVITY, + .argument = { .maxEffect = MAX_EFFECT_GRAVITY }, .battleAnimScript = gBattleAnimMove_GMaxGravitas, }, @@ -21813,7 +21852,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_STEALTH_ROCK, + .argument = { .maxEffect = MAX_EFFECT_STEALTH_ROCK }, .battleAnimScript = gBattleAnimMove_GMaxStonesurge, }, @@ -21829,7 +21868,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_VOLCALITH, + .argument = { .maxEffect = MAX_EFFECT_VOLCALITH }, .battleAnimScript = gBattleAnimMove_GMaxVolcalith, }, @@ -21845,7 +21884,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_LOWER_EVASIVENESS_FOES, + .argument = { .maxEffect = MAX_EFFECT_LOWER_EVASIVENESS_FOES }, .battleAnimScript = gBattleAnimMove_GMaxTartness, }, @@ -21861,7 +21900,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_AROMATHERAPY, + .argument = { .maxEffect = MAX_EFFECT_AROMATHERAPY }, .battleAnimScript = gBattleAnimMove_GMaxSweetness, }, @@ -21877,7 +21916,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_SANDBLAST_FOES, + .argument = { .maxEffect = MAX_EFFECT_SANDBLAST_FOES }, .battleAnimScript = gBattleAnimMove_GMaxSandblast, }, @@ -21893,7 +21932,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_POISON_PARALYZE_FOES, + .argument = { .maxEffect = MAX_EFFECT_POISON_PARALYZE_FOES }, .battleAnimScript = gBattleAnimMove_GMaxStunShock, }, @@ -21909,7 +21948,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_FIRE_SPIN_FOES, + .argument = { .maxEffect = MAX_EFFECT_FIRE_SPIN_FOES }, .battleAnimScript = gBattleAnimMove_GMaxCentiferno, }, @@ -21925,7 +21964,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_CONFUSE_FOES, + .argument = { .maxEffect = MAX_EFFECT_CONFUSE_FOES }, .battleAnimScript = gBattleAnimMove_GMaxSmite, }, @@ -21942,7 +21981,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_YAWN_FOE, + .argument = { .maxEffect = MAX_EFFECT_YAWN_FOE }, .battleAnimScript = gBattleAnimMove_GMaxSnooze, }, @@ -21958,7 +21997,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_HEAL_TEAM, + .argument = { .maxEffect = MAX_EFFECT_HEAL_TEAM }, .battleAnimScript = gBattleAnimMove_GMaxFinale, }, @@ -21974,7 +22013,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_STEELSURGE, + .argument = { .maxEffect = MAX_EFFECT_STEELSURGE }, .battleAnimScript = gBattleAnimMove_GMaxSteelsurge, }, @@ -21990,7 +22029,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_SPITE, + .argument = { .maxEffect = MAX_EFFECT_SPITE }, .battleAnimScript = gBattleAnimMove_GMaxDepletion, }, @@ -22006,7 +22045,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_BYPASS_PROTECT, + .argument = { .maxEffect = MAX_EFFECT_BYPASS_PROTECT }, .battleAnimScript = gBattleAnimMove_GMaxOneBlow, }, @@ -22022,7 +22061,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .argument = MAX_EFFECT_BYPASS_PROTECT, + .argument = { .maxEffect = MAX_EFFECT_BYPASS_PROTECT }, .battleAnimScript = gBattleAnimMove_GMaxRapidFlow, }, diff --git a/src/data/object_events/object_event_pic_tables_followers.h b/src/data/object_events/object_event_pic_tables_followers.h index 276e8fcf65..07193cedc7 100644 --- a/src/data/object_events/object_event_pic_tables_followers.h +++ b/src/data/object_events/object_event_pic_tables_followers.h @@ -3136,8 +3136,8 @@ static const struct SpriteFrameImage sPicTable_Bastiodon[] = { #endif //P_FAMILY_SHIELDON #if P_FAMILY_BURMY -static const struct SpriteFrameImage sPicTable_BurmyPlantCloak[] = { - overworld_ascending_frames(gObjectEventPic_BurmyPlantCloak, 4, 4), +static const struct SpriteFrameImage sPicTable_BurmyPlant[] = { + overworld_ascending_frames(gObjectEventPic_BurmyPlant, 4, 4), }; static const struct SpriteFrameImage sPicTable_BurmySandy[] = { overworld_ascending_frames(gObjectEventPic_BurmySandy, 4, 4), @@ -3145,8 +3145,8 @@ static const struct SpriteFrameImage sPicTable_BurmySandy[] = { static const struct SpriteFrameImage sPicTable_BurmyTrash[] = { overworld_ascending_frames(gObjectEventPic_BurmyTrash, 4, 4), }; -static const struct SpriteFrameImage sPicTable_WormadamPlantCloak[] = { - overworld_ascending_frames(gObjectEventPic_WormadamPlantCloak, 4, 4), +static const struct SpriteFrameImage sPicTable_WormadamPlant[] = { + overworld_ascending_frames(gObjectEventPic_WormadamPlant, 4, 4), }; static const struct SpriteFrameImage sPicTable_WormadamSandy[] = { overworld_ascending_frames(gObjectEventPic_WormadamSandy, 4, 4), diff --git a/src/data/pokemon/level_up_learnsets/gen_1.h b/src/data/pokemon/level_up_learnsets/gen_1.h index 8470b1b14e..f1e7cd32ff 100644 --- a/src/data/pokemon/level_up_learnsets/gen_1.h +++ b/src/data/pokemon/level_up_learnsets/gen_1.h @@ -7717,7 +7717,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 1, MOVE_TACKLE), LEVEL_UP_MOVE(10, MOVE_PROTECT), LEVEL_UP_MOVE(15, MOVE_BUG_BITE), diff --git a/src/data/pokemon/level_up_learnsets/gen_2.h b/src/data/pokemon/level_up_learnsets/gen_2.h index 0f39631c4f..3d74d70b23 100644 --- a/src/data/pokemon/level_up_learnsets/gen_2.h +++ b/src/data/pokemon/level_up_learnsets/gen_2.h @@ -7961,7 +7961,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 1, MOVE_TACKLE), LEVEL_UP_MOVE(10, MOVE_PROTECT), LEVEL_UP_MOVE(15, MOVE_BUG_BITE), diff --git a/src/data/pokemon/level_up_learnsets/gen_3.h b/src/data/pokemon/level_up_learnsets/gen_3.h index 81e6d06b46..cedd09b308 100644 --- a/src/data/pokemon/level_up_learnsets/gen_3.h +++ b/src/data/pokemon/level_up_learnsets/gen_3.h @@ -8187,7 +8187,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 1, MOVE_TACKLE), LEVEL_UP_MOVE(10, MOVE_PROTECT), LEVEL_UP_MOVE(15, MOVE_BUG_BITE), diff --git a/src/data/pokemon/level_up_learnsets/gen_4.h b/src/data/pokemon/level_up_learnsets/gen_4.h index 5c9f6872b5..4b302539b2 100644 --- a/src/data/pokemon/level_up_learnsets/gen_4.h +++ b/src/data/pokemon/level_up_learnsets/gen_4.h @@ -9461,7 +9461,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 1, MOVE_TACKLE), LEVEL_UP_MOVE(10, MOVE_PROTECT), LEVEL_UP_MOVE(15, MOVE_BUG_BITE), diff --git a/src/data/pokemon/level_up_learnsets/gen_5.h b/src/data/pokemon/level_up_learnsets/gen_5.h index cb99b6375d..2403f17b96 100644 --- a/src/data/pokemon/level_up_learnsets/gen_5.h +++ b/src/data/pokemon/level_up_learnsets/gen_5.h @@ -9920,7 +9920,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 1, MOVE_TACKLE), LEVEL_UP_MOVE(10, MOVE_PROTECT), LEVEL_UP_MOVE(15, MOVE_BUG_BITE), diff --git a/src/data/pokemon/level_up_learnsets/gen_6.h b/src/data/pokemon/level_up_learnsets/gen_6.h index 32e5849cda..c5a3a39acf 100644 --- a/src/data/pokemon/level_up_learnsets/gen_6.h +++ b/src/data/pokemon/level_up_learnsets/gen_6.h @@ -10382,7 +10382,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 1, MOVE_TACKLE), LEVEL_UP_MOVE(10, MOVE_PROTECT), LEVEL_UP_MOVE(15, MOVE_BUG_BITE), diff --git a/src/data/pokemon/level_up_learnsets/gen_7.h b/src/data/pokemon/level_up_learnsets/gen_7.h index f88e4bcba7..77d2fc2deb 100644 --- a/src/data/pokemon/level_up_learnsets/gen_7.h +++ b/src/data/pokemon/level_up_learnsets/gen_7.h @@ -10610,7 +10610,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 0, MOVE_QUIVER_DANCE), LEVEL_UP_MOVE( 1, MOVE_QUIVER_DANCE), LEVEL_UP_MOVE( 1, MOVE_SUCKER_PUNCH), diff --git a/src/data/pokemon/level_up_learnsets/gen_8.h b/src/data/pokemon/level_up_learnsets/gen_8.h index 67d263c859..65b557a486 100644 --- a/src/data/pokemon/level_up_learnsets/gen_8.h +++ b/src/data/pokemon/level_up_learnsets/gen_8.h @@ -10633,7 +10633,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 0, MOVE_QUIVER_DANCE), LEVEL_UP_MOVE( 1, MOVE_QUIVER_DANCE), LEVEL_UP_MOVE( 1, MOVE_SUCKER_PUNCH), diff --git a/src/data/pokemon/level_up_learnsets/gen_9.h b/src/data/pokemon/level_up_learnsets/gen_9.h index 9f6985bc9a..0bdfbe1eb3 100644 --- a/src/data/pokemon/level_up_learnsets/gen_9.h +++ b/src/data/pokemon/level_up_learnsets/gen_9.h @@ -10291,7 +10291,7 @@ static const struct LevelUpMove sBurmyLevelUpLearnset[] = { LEVEL_UP_END }; -static const struct LevelUpMove sWormadamPlantCloakLevelUpLearnset[] = { +static const struct LevelUpMove sWormadamPlantLevelUpLearnset[] = { LEVEL_UP_MOVE( 0, MOVE_QUIVER_DANCE), LEVEL_UP_MOVE( 1, MOVE_QUIVER_DANCE), LEVEL_UP_MOVE( 1, MOVE_SUCKER_PUNCH), diff --git a/src/data/pokemon/species_info/gen_1_families.h b/src/data/pokemon/species_info/gen_1_families.h index ba9f845395..314b5bd73f 100644 --- a/src/data/pokemon/species_info/gen_1_families.h +++ b/src/data/pokemon/species_info/gen_1_families.h @@ -2533,7 +2533,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .frontPicSize = MON_COORDS_SIZE(32, 40), .frontPicYOffset = 13, .frontAnimFrames = sAnims_PichuSpikyEared, - //.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .frontAnimId = ANIM_V_JUMPS_H_JUMPS, .backPic = gMonBackPic_PichuSpikyEared, .backPicSize = MON_COORDS_SIZE(48, 56), .backPicYOffset = 8, @@ -2544,11 +2544,12 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = .iconPalIndex = 1, SHADOW(2, 0, SHADOW_SIZE_S) FOOTPRINT(Pichu) - OVERWORLD( + OVERWORLD_SET_ANIM( sPicTable_PichuSpikyEared, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, + sAnimTable_Following_Asym, gOverworldPalette_PichuSpikyEared, gShinyOverworldPalette_PichuSpikyEared ) diff --git a/src/data/pokemon/species_info/gen_4_families.h b/src/data/pokemon/species_info/gen_4_families.h index b84284de29..be0cfba99e 100644 --- a/src/data/pokemon/species_info/gen_4_families.h +++ b/src/data/pokemon/species_info/gen_4_families.h @@ -1656,29 +1656,29 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = .pokemonOffset = 24, .trainerScale = 256, .trainerOffset = 0, - .frontPic = gMonFrontPic_BurmyPlantCloak, + .frontPic = gMonFrontPic_BurmyPlant, .frontPicSize = MON_COORDS_SIZE(32, 56), .frontPicYOffset = 13, .frontAnimFrames = sAnims_Burmy, .frontAnimId = ANIM_V_STRETCH, .enemyMonElevation = 10, - .backPic = gMonBackPic_BurmyPlantCloak, + .backPic = gMonBackPic_BurmyPlant, .backPicSize = MON_COORDS_SIZE(40, 56), .backPicYOffset = 6, .backAnimId = BACK_ANIM_H_SHAKE, - .palette = gMonPalette_BurmyPlantCloak, - .shinyPalette = gMonShinyPalette_BurmyPlantCloak, - .iconSprite = gMonIcon_BurmyPlantCloak, + .palette = gMonPalette_BurmyPlant, + .shinyPalette = gMonShinyPalette_BurmyPlant, + .iconSprite = gMonIcon_BurmyPlant, .iconPalIndex = 1, SHADOW(-1, 8, SHADOW_SIZE_S) FOOTPRINT(Burmy) OVERWORLD( - sPicTable_BurmyPlantCloak, + sPicTable_BurmyPlant, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, - gOverworldPalette_BurmyPlantCloak, - gShinyOverworldPalette_BurmyPlantCloak + gOverworldPalette_BurmyPlant, + gShinyOverworldPalette_BurmyPlant ) .tmIlliterate = TRUE, .levelUpLearnset = sBurmyLevelUpLearnset, @@ -1858,32 +1858,32 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = .pokemonOffset = 13, .trainerScale = 256, .trainerOffset = 0, - .frontPic = gMonFrontPic_WormadamPlantCloak, + .frontPic = gMonFrontPic_WormadamPlant, .frontPicSize = MON_COORDS_SIZE(48, 56), .frontPicYOffset = 10, .frontAnimFrames = sAnims_Wormadam, .frontAnimId = ANIM_SWING_CONVEX_FAST_SHORT, .enemyMonElevation = 8, - .backPic = gMonBackPic_WormadamPlantCloak, + .backPic = gMonBackPic_WormadamPlant, .backPicSize = MON_COORDS_SIZE(56, 64), .backPicYOffset = 2, .backAnimId = BACK_ANIM_V_SHAKE, - .palette = gMonPalette_WormadamPlantCloak, - .shinyPalette = gMonShinyPalette_WormadamPlantCloak, - .iconSprite = gMonIcon_WormadamPlantCloak, + .palette = gMonPalette_WormadamPlant, + .shinyPalette = gMonShinyPalette_WormadamPlant, + .iconSprite = gMonIcon_WormadamPlant, .iconPalIndex = 1, SHADOW(0, 9, SHADOW_SIZE_S) FOOTPRINT(Wormadam) OVERWORLD( - sPicTable_WormadamPlantCloak, + sPicTable_WormadamPlant, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, - gOverworldPalette_WormadamPlantCloak, - gShinyOverworldPalette_WormadamPlantCloak + gOverworldPalette_WormadamPlant, + gShinyOverworldPalette_WormadamPlant ) - .levelUpLearnset = sWormadamPlantCloakLevelUpLearnset, - .teachableLearnset = sWormadamPlantCloakTeachableLearnset, + .levelUpLearnset = sWormadamPlantLevelUpLearnset, + .teachableLearnset = sWormadamPlantTeachableLearnset, .formSpeciesIdTable = sWormadamFormSpeciesIdTable, }, diff --git a/src/data/pokemon/teachable_learnsets.h b/src/data/pokemon/teachable_learnsets.h index 46354db5a0..b0755d6039 100644 --- a/src/data/pokemon/teachable_learnsets.h +++ b/src/data/pokemon/teachable_learnsets.h @@ -18903,7 +18903,7 @@ static const u16 sBurmyTeachableLearnset[] = { MOVE_UNAVAILABLE, }; -static const u16 sWormadamPlantCloakTeachableLearnset[] = { +static const u16 sWormadamPlantTeachableLearnset[] = { MOVE_ATTRACT, MOVE_BULLET_SEED, MOVE_DIG, diff --git a/src/data/pokemon_graphics/front_pic_anims.h b/src/data/pokemon_graphics/front_pic_anims.h index 56ec319a57..adf64468aa 100644 --- a/src/data/pokemon_graphics/front_pic_anims.h +++ b/src/data/pokemon_graphics/front_pic_anims.h @@ -340,7 +340,17 @@ static const union AnimCmd sAnim_Pichu_1[] = ANIMCMD_END, }; -PLACEHOLDER_ANIM_SINGLE_FRAME(PichuSpikyEared); +static const union AnimCmd sAnim_PichuSpikyEared_1[] = +{ + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 1), + ANIMCMD_END, +}; #endif //P_GEN_2_CROSS_EVOS static const union AnimCmd sAnim_Pikachu_1[] = diff --git a/src/daycare.c b/src/daycare.c index 013e0b05ba..4997f4efe9 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -590,27 +590,6 @@ static void UNUSED TriggerPendingDaycareMaleEgg(void) _TriggerPendingDaycareMaleEgg(&gSaveBlock1Ptr->daycare); } -// Removes the selected index from the given IV list and shifts the remaining -// elements to the left. -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) -{ - s32 i, j; - u8 temp[NUM_STATS]; - - ivs[selectedIv] = 0xFF; - for (i = 0; i < NUM_STATS; i++) - { - temp[i] = ivs[i]; - } - - j = 0; - for (i = 0; i < NUM_STATS; i++) - { - if (temp[i] != 0xFF) - ivs[j++] = temp[i]; - } -} - static void InheritIVs(struct Pokemon *egg, struct DayCare *daycare) { u16 motherItem = GetBoxMonData(&daycare->mons[0].mon, MON_DATA_HELD_ITEM); @@ -1154,11 +1133,17 @@ static bool8 TryProduceOrHatchEgg(struct DayCare *daycare) } // Try to hatch Egg - if (++daycare->stepCounter == ((P_EGG_CYCLE_LENGTH >= GEN_8) ? 127 : 255)) + daycare->stepCounter++; + if (((P_EGG_CYCLE_LENGTH <= GEN_3 || P_EGG_CYCLE_LENGTH == GEN_7) && daycare->stepCounter >= 256) + || (P_EGG_CYCLE_LENGTH == GEN_4 && daycare->stepCounter >= 255) + || ((P_EGG_CYCLE_LENGTH == GEN_5 || P_EGG_CYCLE_LENGTH == GEN_6) && daycare->stepCounter >= 257) + || (P_EGG_CYCLE_LENGTH >= GEN_8 && daycare->stepCounter >= 128)) { u32 eggCycles; u8 toSub = GetEggCyclesToSubtract(); + daycare->stepCounter = 0; + for (i = 0; i < gPlayerPartyCount; i++) { if (!GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) diff --git a/src/evolution_graphics.c b/src/evolution_graphics.c index 96ff1b52df..1568c18d5f 100644 --- a/src/evolution_graphics.c +++ b/src/evolution_graphics.c @@ -150,7 +150,9 @@ static void SpriteCB_Sparkle_SpiralUpward(struct Sprite *sprite) sprite->oam.matrixNum = matrixNum; } else + { DestroySprite(sprite); + } } static void CreateSparkle_SpiralUpward(u8 trigIdx) @@ -178,7 +180,9 @@ static void SpriteCB_Sparkle_ArcDown(struct Sprite *sprite) sprite->sTimer++; } else + { DestroySprite(sprite); + } } static void CreateSparkle_ArcDown(u8 trigIdx) @@ -206,7 +210,9 @@ static void SpriteCB_Sparkle_CircleInward(struct Sprite *sprite) sprite->sTrigIdx += 4; } else + { DestroySprite(sprite); + } } static void CreateSparkle_CircleInward(u8 trigIdx, u8 speed) @@ -238,7 +244,9 @@ static void SpriteCB_Sparkle_Spray(struct Sprite *sprite) sprite->sTrigIdx++; matrixNum = 31 - (sprite->sTrigIdx * 12 / 128); if (sprite->sTrigIdx > 64) + { sprite->subpriority = 1; + } else { sprite->invisible = FALSE; @@ -252,7 +260,9 @@ static void SpriteCB_Sparkle_Spray(struct Sprite *sprite) sprite->sTimer++; } else + { DestroySprite(sprite); + } } static void CreateSparkle_Spray(u8 id) @@ -348,7 +358,9 @@ static void Task_Sparkles_ArcDown(u8 taskId) gTasks[taskId].tTimer++; } else + { gTasks[taskId].func = Task_Sparkles_ArcDown_End; + } } static void Task_Sparkles_ArcDown_End(u8 taskId) @@ -388,7 +400,9 @@ static void Task_Sparkles_CircleInward(u8 taskId) gTasks[taskId].tTimer++; } else + { gTasks[taskId].func = Task_Sparkles_CircleInward_End; + } } static void Task_Sparkles_CircleInward_End(u8 taskId) @@ -437,7 +451,9 @@ static void Task_Sparkles_SprayAndFlash(u8 taskId) gTasks[taskId].tTimer++; } else + { gTasks[taskId].func = Task_Sparkles_SprayAndFlash_End; + } } static void Task_Sparkles_SprayAndFlash_End(u8 taskId) @@ -486,7 +502,9 @@ static void Task_Sparkles_SprayAndFlashTrade(u8 taskId) gTasks[taskId].tTimer++; } else + { gTasks[taskId].func = Task_Sparkles_SprayAndFlash_End; + } } #undef tTimer @@ -560,9 +578,13 @@ static void Task_CycleEvolutionMonSprite_Init(u8 taskId) static void Task_CycleEvolutionMonSprite_TryEnd(u8 taskId) { if (gTasks[taskId].tEvoStopped) + { EndOnPreEvoMon(taskId); + } else if (gTasks[taskId].tScaleSpeed == 128) + { EndOnPostEvoMon(taskId); + } else { gTasks[taskId].tScaleSpeed += 2; @@ -574,7 +596,9 @@ static void Task_CycleEvolutionMonSprite_TryEnd(u8 taskId) static void Task_CycleEvolutionMonSprite_UpdateSize(u8 taskId) { if (gTasks[taskId].tEvoStopped) + { gTasks[taskId].func = EndOnPreEvoMon; + } else { u16 oamMatrixArg; @@ -583,7 +607,9 @@ static void Task_CycleEvolutionMonSprite_UpdateSize(u8 taskId) { // Set pre-evo sprite growth if (gTasks[taskId].tPreEvoScale < MON_MAX_SCALE - gTasks[taskId].tScaleSpeed) + { gTasks[taskId].tPreEvoScale += gTasks[taskId].tScaleSpeed; + } else { gTasks[taskId].tPreEvoScale = MON_MAX_SCALE; @@ -592,7 +618,9 @@ static void Task_CycleEvolutionMonSprite_UpdateSize(u8 taskId) // Set post-evo sprite shrink if (gTasks[taskId].tPostEvoScale > MON_MIN_SCALE + gTasks[taskId].tScaleSpeed) + { gTasks[taskId].tPostEvoScale -= gTasks[taskId].tScaleSpeed; + } else { gTasks[taskId].tPostEvoScale = MON_MIN_SCALE; @@ -603,7 +631,9 @@ static void Task_CycleEvolutionMonSprite_UpdateSize(u8 taskId) { // Set post-evo sprite growth if (gTasks[taskId].tPostEvoScale < MON_MAX_SCALE - gTasks[taskId].tScaleSpeed) + { gTasks[taskId].tPostEvoScale += gTasks[taskId].tScaleSpeed; + } else { gTasks[taskId].tPostEvoScale = MON_MAX_SCALE; @@ -612,7 +642,9 @@ static void Task_CycleEvolutionMonSprite_UpdateSize(u8 taskId) // Set pre-evo sprite shrink if (gTasks[taskId].tPreEvoScale > MON_MIN_SCALE + gTasks[taskId].tScaleSpeed) + { gTasks[taskId].tPreEvoScale -= gTasks[taskId].tScaleSpeed; + } else { gTasks[taskId].tPreEvoScale = MON_MIN_SCALE; diff --git a/src/field_camera.c b/src/field_camera.c index 290ddddaf1..e76ba3d855 100644 --- a/src/field_camera.c +++ b/src/field_camera.c @@ -231,7 +231,9 @@ static void DrawMetatileAt(const struct MapLayout *mapLayout, u16 offset, int x, if (metatileId > NUM_METATILES_TOTAL) metatileId = 0; if (metatileId < NUM_METATILES_IN_PRIMARY) + { metatiles = mapLayout->primaryTileset->metatiles; + } else { metatiles = mapLayout->secondaryTileset->metatiles; diff --git a/src/field_door.c b/src/field_door.c index b922c939b7..1810811191 100644 --- a/src/field_door.c +++ b/src/field_door.c @@ -437,7 +437,9 @@ static const struct DoorGraphics *GetDoorGraphics(const struct DoorGraphics *gfx static s8 StartDoorAnimationTask(const struct DoorGraphics *gfx, const struct DoorAnimFrame *frames, u32 x, u32 y) { if (FuncIsActiveTask(Task_AnimateDoor) == TRUE) + { return -1; + } else { u8 taskId = CreateTask(Task_AnimateDoor, 0x50); diff --git a/src/field_effect.c b/src/field_effect.c index 898f19c291..501a249ee4 100644 --- a/src/field_effect.c +++ b/src/field_effect.c @@ -1300,7 +1300,8 @@ static void CreateHofMonitorSprite(s16 taskId, s16 x, s16 y, bool8 isSmallMonito { spriteId = CreateSpriteAtEnd(&sSpriteTemplate_HofMonitorBig, x, y, 0); SetSubspriteTables(&gSprites[spriteId], &sSubspriteTable_HofMonitorBig); - } else + } + else { spriteId = CreateSpriteAtEnd(&sSpriteTemplate_HofMonitorSmall, x, y, 0); } @@ -2022,7 +2023,8 @@ static bool8 LavaridgeGymB1FWarpEffect_Rise(struct Task *task, struct ObjectEven { task->data[1] <<= 1; } - } else if (!(task->data[2] & 4) && (task->data[1] > 0)) + } + else if (!(task->data[2] & 4) && (task->data[1] > 0)) { task->data[1] >>= 1; } @@ -2036,7 +2038,8 @@ static bool8 LavaridgeGymB1FWarpEffect_Rise(struct Task *task, struct ObjectEven { task->data[3]++; } - } else + } + else { task->data[4] = 1; } @@ -2190,7 +2193,8 @@ static bool8 LavaridgeGym1FWarpEffect_AshPuff(struct Task *task, struct ObjectEv gFieldEffectArguments[3] = sprite->oam.priority; task->data[1] = FieldEffectStart(FLDEFF_ASH_PUFF); task->data[0]++; - } else + } + else { task->data[1]++; ObjectEventSetHeldMovement(objectEvent, GetWalkInPlaceFasterMovementAction(objectEvent->facingDirection)); @@ -2521,7 +2525,8 @@ static void TeleportWarpInFieldEffect_SpinEnter(struct Task *task) objectEvent->triggerGroundEffectsOnMove = TRUE; sprite->subspriteMode = task->data[14]; } - } else + } + else { sprite->oam.priority = 1; if (sprite->subspriteMode != SUBSPRITES_OFF) diff --git a/src/field_screen_effect.c b/src/field_screen_effect.c index 073c92f3e0..e07d067afc 100644 --- a/src/field_screen_effect.c +++ b/src/field_screen_effect.c @@ -1374,7 +1374,6 @@ static void Task_RushInjuredPokemonToCenter(u8 taskId) ClearWindowTilemap(windowId); CopyWindowToVram(windowId, COPYWIN_MAP); RemoveWindow(windowId); - FillPalBufferBlack(); FadeInFromBlack(); gTasks[taskId].tState = FRLG_WHITEOUT_HEAL_SCRIPT; break; diff --git a/src/field_specials.c b/src/field_specials.c index 680b527dc7..e04a8011fe 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -2775,10 +2775,12 @@ static void ScrollableMultichoice_UpdateScrollArrows(u8 taskId) struct ScrollArrowsTemplate template = sScrollableMultichoice_ScrollArrowsTemplate; if (task->tMaxItemsOnScreen != task->tNumItems) { + u32 y0 = (8 * (task->tTop - 1)); + template.firstX = (task->tWidth / 2) * 8 + 12 + (task->tLeft - 1) * 8; - template.firstY = 8; + template.firstY = 8 + y0; template.secondX = (task->tWidth / 2) * 8 + 12 + (task->tLeft - 1) * 8; - template.secondY = task->tHeight * 8 + 10; + template.secondY = task->tHeight * 8 + 10 + y0; template.fullyUpThreshold = 0; template.fullyDownThreshold = task->tNumItems - task->tMaxItemsOnScreen; task->tScrollArrowId = AddScrollIndicatorArrowPair(&template, &gScrollableMultichoice_ScrollOffset); diff --git a/src/item_use.c b/src/item_use.c index 2dc33b164c..64db57a16d 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -147,7 +147,9 @@ static void SetUpItemUseOnFieldCallback(u8 taskId) SetUpItemUseCallback(taskId); } else + { sItemUseOnFieldCB(taskId); + } } static void FieldCB_UseItemOnField(void) @@ -173,7 +175,9 @@ static void DisplayCannotUseItemMessage(u8 taskId, bool8 isUsingRegisteredKeyIte DisplayItemMessageInBattlePyramid(taskId, gText_DadsAdvice, Task_CloseBattlePyramidBagMessage); } else + { DisplayItemMessageOnField(taskId, gStringVar4, Task_CloseCantUseKeyItemMessage); + } } void DisplayDadsAdviceCannotUseItemMessage(u8 taskId, bool8 isUsingRegisteredKeyItemOnField) @@ -254,7 +258,9 @@ void ItemUseOutOfBattle_Bike(u8 taskId) PlayerGetDestCoords(&coordsX, &coordsY); behavior = MapGridGetMetatileBehaviorAt(coordsX, coordsY); if (FlagGet(FLAG_SYS_CYCLING_ROAD) == TRUE || MetatileBehavior_IsVerticalRail(behavior) == TRUE || MetatileBehavior_IsHorizontalRail(behavior) == TRUE || MetatileBehavior_IsIsolatedVerticalRail(behavior) == TRUE || MetatileBehavior_IsIsolatedHorizontalRail(behavior) == TRUE) + { DisplayCannotDismountBikeMessage(taskId, tUsingRegisteredKeyItem); + } else { if (Overworld_IsBikingAllowed() == TRUE && IsBikingDisallowedByPlayer() == 0) @@ -263,7 +269,9 @@ void ItemUseOutOfBattle_Bike(u8 taskId) SetUpItemUseOnFieldCallback(taskId); } else + { DisplayDadsAdviceCannotUseItemMessage(taskId, tUsingRegisteredKeyItem); + } } } @@ -316,7 +324,9 @@ void ItemUseOutOfBattle_Rod(u8 taskId) SetUpItemUseOnFieldCallback(taskId); } else + { DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem); + } } static void ItemUseOnFieldCB_Rod(u8 taskId) @@ -1415,9 +1425,17 @@ void ItemUseOutOfBattle_ZygardeCube(u8 taskId) void ItemUseOutOfBattle_Fusion(u8 taskId) { - gItemUseCB = ItemUseCB_Fusion; - gTasks[taskId].data[0] = FALSE; - SetUpItemUseCallback(taskId); + if (!gTasks[taskId].tUsingRegisteredKeyItem) + { + gItemUseCB = ItemUseCB_Fusion; + gTasks[taskId].data[0] = FALSE; + SetUpItemUseCallback(taskId); + } + else + { + // TODO: handle key items with callbacks to menus allow to be used by registering them. + DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem); + } } void Task_UseHoneyOnField(u8 taskId) @@ -1567,10 +1585,18 @@ static void ItemUseOnFieldCB_TownMap(u8 taskId) void ItemUseOutOfBattle_TownMap(u8 taskId) { - sItemUseOnFieldCB = ItemUseOnFieldCB_TownMap; - gFieldCallback = FieldCB_UseItemOnField; - gBagMenu->newScreenCallback = CB2_ReturnToField; - Task_FadeAndCloseBagMenu(taskId); + if (!gTasks[taskId].tUsingRegisteredKeyItem) + { + sItemUseOnFieldCB = ItemUseOnFieldCB_TownMap; + gFieldCallback = FieldCB_UseItemOnField; + gBagMenu->newScreenCallback = CB2_ReturnToField; + Task_FadeAndCloseBagMenu(taskId); + } + else + { + // TODO: handle key items with callbacks to menus allow to be used by registering them. + DisplayDadsAdviceCannotUseItemMessage(taskId, gTasks[taskId].tUsingRegisteredKeyItem); + } } #undef tUsingRegisteredKeyItem diff --git a/src/librfu_sio32id.c b/src/librfu_sio32id.c index 2a1b0c94c4..45b1bc33de 100644 --- a/src/librfu_sio32id.c +++ b/src/librfu_sio32id.c @@ -145,7 +145,9 @@ static void Sio32IDIntr(void) } } else + { gRfuSIO32Id.lastId = regSIODATA32; + } } else { diff --git a/src/link_rfu_2.c b/src/link_rfu_2.c index 4c4323c1ed..6b20cf9678 100644 --- a/src/link_rfu_2.c +++ b/src/link_rfu_2.c @@ -1175,7 +1175,9 @@ static void RfuHandleReceiveCommand(u8 unused) gRfu.numBlocksReceived[i] = 0; } else + { gRfu.numBlocksReceived[i]++; + } } } } @@ -1302,7 +1304,9 @@ bool32 Rfu_InitBlockSend(const u8 *src, size_t size) gRfu.sendBlock.count = (size / 12) + r4; gRfu.sendBlock.next = 0; if (size > BLOCK_BUFFER_SIZE) + { gRfu.sendBlock.payload = src; + } else { if (src != gBlockSendBuffer) @@ -1629,9 +1633,8 @@ static bool8 CheckForLeavingGroupMembers(void) } else if (gRfuSlotStatusNI[gRfu.childSlot]->recv.state == SLOT_STATE_RECV_FAILED) - rfu_clearSlot(TYPE_NI_RECV, i); { - + rfu_clearSlot(TYPE_NI_RECV, i); } } } @@ -1777,7 +1780,9 @@ static void Task_PlayerExchange(u8 taskId) gTasks[taskId].tState = 101; } else + { gTasks[taskId].tState = 2; + } break; case 101: if (gSendCmd[0] == 0) @@ -1798,7 +1803,9 @@ static void Task_PlayerExchange(u8 taskId) } } else + { gTasks[taskId].tState++; + } break; case 4: if (AreAllPlayersFinishedReceiving()) diff --git a/src/lottery_corner.c b/src/lottery_corner.c index 4e58c22858..1f2b3a4052 100644 --- a/src/lottery_corner.c +++ b/src/lottery_corner.c @@ -74,7 +74,9 @@ void PickLotteryCornerTicket(void) } } else // Pokémon are always arranged from populated spots first to unpopulated, so the moment a NONE species is found, that's the end of the list. + { break; + } } for (i = 0; i < TOTAL_BOXES_COUNT; i++) @@ -132,7 +134,9 @@ static u8 GetMatchingDigits(u16 winNumber, u16 otId) matchingDigits++; } else + { break; + } } return matchingDigits; } diff --git a/src/main_menu.c b/src/main_menu.c index 504fbfb186..bae80e543a 100644 --- a/src/main_menu.c +++ b/src/main_menu.c @@ -255,7 +255,6 @@ static const u16 sBirchSpeechBgPals[][16] = { static const u32 sBirchSpeechShadowGfx[] = INCBIN_U32("graphics/birch_speech/shadow.4bpp.lz"); static const u32 sBirchSpeechBgMap[] = INCBIN_U32("graphics/birch_speech/map.bin.lz"); static const u16 sBirchSpeechBgGradientPal[] = INCBIN_U16("graphics/birch_speech/bg2.gbapal"); -static const u16 sBirchSpeechPlatformBlackPal[] = {RGB_BLACK, RGB_BLACK, RGB_BLACK, RGB_BLACK, RGB_BLACK, RGB_BLACK, RGB_BLACK, RGB_BLACK}; static const u8 gText_SaveFileCorrupted[] = _("The save file is corrupted. The\nprevious save file will be loaded."); static const u8 gText_SaveFileErased[] = _("The save file has been erased\ndue to corruption or damage."); @@ -1298,7 +1297,7 @@ static void Task_NewGameBirchSpeech_Init(u8 taskId) LZ77UnCompVram(sBirchSpeechShadowGfx, (void *)VRAM); LZ77UnCompVram(sBirchSpeechBgMap, (void *)(BG_SCREEN_ADDR(7))); LoadPalette(sBirchSpeechBgPals, BG_PLTT_ID(0), 2 * PLTT_SIZE_4BPP); - LoadPalette(sBirchSpeechPlatformBlackPal, BG_PLTT_ID(0) + 1, PLTT_SIZEOF(8)); + LoadPalette(&sBirchSpeechBgGradientPal[8], BG_PLTT_ID(0) + 1, PLTT_SIZEOF(8)); ScanlineEffect_Stop(); ResetSpriteData(); FreeAllSpritePalettes(); diff --git a/src/mauville_old_man.c b/src/mauville_old_man.c index efadd4de1f..8b8bfb2db5 100644 --- a/src/mauville_old_man.c +++ b/src/mauville_old_man.c @@ -477,7 +477,9 @@ static void BardSing(struct Task *task, struct BardSong *song) GetWordPhonemes(song, MACRO1(word)); song->currWord++; if (song->sound->songLengthId != 0xFF) + { song->state = 0; + } else { song->state = 3; @@ -527,7 +529,9 @@ static void BardSing(struct Task *task, struct BardSong *song) { song->currPhoneme++; if (song->currPhoneme != 6 && song->sound[song->currPhoneme].songLengthId != 0xFF) + { song->state = 0; + } else { song->state = 3; @@ -846,7 +850,9 @@ void SanitizeReceivedRubyOldMan(union OldMan * oldMan, u32 version, u32 language trader->language[i] = LANGUAGE_JAPANESE; } else + { trader->language[i] = language; + } } } else diff --git a/src/mini_printf.c b/src/mini_printf.c index 9332a270a4..c2e35354f1 100644 --- a/src/mini_printf.c +++ b/src/mini_printf.c @@ -274,7 +274,8 @@ s32 mini_vpprintf(void* buf, const char *fmt, va_list va) { len = 1; len = _putsAscii(&ch, len, buf); - } else + } + else { char pad_char = ' '; s32 pad_to = 0; @@ -310,7 +311,8 @@ s32 mini_vpprintf(void* buf, const char *fmt, va_list va) if(l) { len = mini_itoa(va_arg(va, u32), 10, 0, (ch=='u'), bf2); - } else + } + else { if(ch == 'u') { @@ -352,7 +354,8 @@ s32 mini_vpprintf(void* buf, const char *fmt, va_list va) { len = mini_pad(ptr, len, pad_char, pad_to, bf); len = _putsAscii(bf, len, buf); - } else + } + else { len = _putsAscii(ptr, len, buf); } @@ -364,7 +367,8 @@ s32 mini_vpprintf(void* buf, const char *fmt, va_list va) { len = mini_pad(ptr, len, pad_char, pad_to, bf); len = _putsEncoded(bf, len, buf); - } else + } + else { len = _putsEncoded(ptr, len, buf); } diff --git a/src/party_menu.c b/src/party_menu.c index 285ad5e839..064a0eec16 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -5367,7 +5367,9 @@ static void Task_LearnNextMoveOrClosePartyMenu(u8 taskId) if (IsFanfareTaskInactive() && ((JOY_NEW(A_BUTTON)) || (JOY_NEW(B_BUTTON)))) { if (gPartyMenu.learnMoveState == 1) + { Task_TryLearningNextMove(taskId); + } else { if (gPartyMenu.learnMoveState == 2) // never occurs diff --git a/src/player_pc.c b/src/player_pc.c index b44799223c..352a7a11f8 100644 --- a/src/player_pc.c +++ b/src/player_pc.c @@ -891,7 +891,9 @@ static void Mailbox_CancelMoveToBag(u8 taskId) static void Mailbox_Give(u8 taskId) { if (CalculatePlayerPartyCount() == 0) + { Mailbox_NoPokemonForMail(taskId); + } else { FadeScreen(FADE_TO_BLACK, 0); diff --git a/src/pokedex.c b/src/pokedex.c index 87702d3371..e4b5076e59 100644 --- a/src/pokedex.c +++ b/src/pokedex.c @@ -2416,7 +2416,9 @@ static void CreateMonListEntry(u8 position, u16 b, u16 ignored) if (vOffset >= LIST_SCROLL_STEP) vOffset -= LIST_SCROLL_STEP; if (entryNum < 0 || entryNum >= NATIONAL_DEX_COUNT || sPokedexView->pokedexList[entryNum].dexNum == 0xFFFF) + { ClearMonListEntry(17, vOffset * 2, ignored); + } else { ClearMonListEntry(17, vOffset * 2, ignored); @@ -2711,7 +2713,9 @@ static bool8 TryDoInfoScreenScroll(void) } if (sPokedexView->selectedPokemon == selectedPokemon) + { return FALSE; + } else { sPokedexView->selectedPokemon = selectedPokemon; @@ -2734,7 +2738,9 @@ static bool8 TryDoInfoScreenScroll(void) } if (sPokedexView->selectedPokemon == selectedPokemon) + { return FALSE; + } else { sPokedexView->selectedPokemon = selectedPokemon; diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 74b57fa3a5..8782044769 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -2560,11 +2560,11 @@ static void CreatePokedexList(u8 dexMode, u8 order) } break; case ORDER_ALPHABETICAL: - for (i = 0; i < NUM_SPECIES - 1; i++) + for (i = 0; i < NATIONAL_DEX_COUNT; i++) { temp_dexNum = gPokedexOrder_Alphabetical[i]; - if (NationalToHoennOrder(temp_dexNum) <= temp_dexCount && GetSetPokedexFlag(temp_dexNum, FLAG_GET_SEEN)) + if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_SEEN)) { sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum; sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE; @@ -2578,7 +2578,7 @@ static void CreatePokedexList(u8 dexMode, u8 order) { temp_dexNum = gPokedexOrder_Weight[i]; - if (NationalToHoennOrder(temp_dexNum) <= temp_dexCount && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) + if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) { sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum; sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE; @@ -2592,7 +2592,7 @@ static void CreatePokedexList(u8 dexMode, u8 order) { temp_dexNum = gPokedexOrder_Weight[i]; - if (NationalToHoennOrder(temp_dexNum) <= temp_dexCount && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) + if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) { sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum; sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE; @@ -2606,7 +2606,7 @@ static void CreatePokedexList(u8 dexMode, u8 order) { temp_dexNum = gPokedexOrder_Height[i]; - if (NationalToHoennOrder(temp_dexNum) <= temp_dexCount && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) + if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) { sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum; sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE; @@ -2620,7 +2620,7 @@ static void CreatePokedexList(u8 dexMode, u8 order) { temp_dexNum = gPokedexOrder_Height[i]; - if (NationalToHoennOrder(temp_dexNum) <= temp_dexCount && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) + if ((!temp_isHoennDex || NationalToHoennOrder(temp_dexNum) != 0) && GetSetPokedexFlag(temp_dexNum, FLAG_GET_CAUGHT)) { sPokedexView->pokedexList[sPokedexView->pokemonListCount].dexNum = temp_dexNum; sPokedexView->pokedexList[sPokedexView->pokemonListCount].seen = TRUE; diff --git a/src/pokemon.c b/src/pokemon.c index d377af1c42..0771076b2a 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -75,7 +75,6 @@ static void EncryptBoxMon(struct BoxPokemon *boxMon); static void DecryptBoxMon(struct BoxPokemon *boxMon); static void Task_PlayMapChosenOrBattleBGM(u8 taskId); static bool8 ShouldSkipFriendshipChange(void); -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv); void TrySpecialOverworldEvo(); EWRAM_DATA static u8 sLearningMoveTableID = 0; @@ -5748,7 +5747,9 @@ u16 GetBattleBGM(void) } } else if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK)) + { return MUS_VS_TRAINER; + } else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) { u8 trainerClass; @@ -5795,7 +5796,9 @@ u16 GetBattleBGM(void) } } else + { return MUS_VS_WILD; + } } void PlayBattleBGM(void) @@ -6680,7 +6683,9 @@ u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove) return 0; } -static void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) +// Removes the selected index from the given IV list and shifts the remaining +// elements to the left. +void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv) { s32 i, j; u8 temp[NUM_STATS]; diff --git a/src/pokenav_conditions_search_results.c b/src/pokenav_conditions_search_results.c index 4889dd788c..09ad43706b 100644 --- a/src/pokenav_conditions_search_results.c +++ b/src/pokenav_conditions_search_results.c @@ -186,13 +186,21 @@ static bool32 HandleConditionSearchInput_WaitSetup(struct Pokenav_SearchResults static u32 HandleConditionSearchInput(struct Pokenav_SearchResults *menu) { if (JOY_REPEAT(DPAD_UP)) + { return CONDITION_SEARCH_FUNC_MOVE_UP; + } else if (JOY_REPEAT(DPAD_DOWN)) + { return CONDITION_SEARCH_FUNC_MOVE_DOWN; + } else if (JOY_NEW(DPAD_LEFT)) + { return CONDITION_SEARCH_FUNC_PAGE_UP; + } else if (JOY_NEW(DPAD_RIGHT)) + { return CONDITION_SEARCH_FUNC_PAGE_DOWN; + } else if (JOY_NEW(B_BUTTON)) { // Exiting back to main search menu @@ -209,7 +217,9 @@ static u32 HandleConditionSearchInput(struct Pokenav_SearchResults *menu) return CONDITION_SEARCH_FUNC_SELECT_MON; } else + { return CONDITION_SEARCH_FUNC_NONE; + } } static u32 ReturnToConditionSearchList(struct Pokenav_SearchResults *menu) diff --git a/src/pokenav_menu_handler_gfx.c b/src/pokenav_menu_handler_gfx.c index 09fb96f3dc..42588aeed0 100644 --- a/src/pokenav_menu_handler_gfx.c +++ b/src/pokenav_menu_handler_gfx.c @@ -509,7 +509,9 @@ static u32 LoopedTask_OpenMenu(s32 state) ShowBg(2); ShowBg(3); if (gfx->pokenavAlreadyOpen) + { PokenavFadeScreen(POKENAV_FADE_FROM_BLACK); + } else { PlaySE(SE_POKENAV_ON); diff --git a/src/recorded_battle.c b/src/recorded_battle.c index c32e86b525..5e1ff63bbe 100644 --- a/src/recorded_battle.c +++ b/src/recorded_battle.c @@ -53,7 +53,7 @@ EWRAM_DATA static u32 sAI_Scripts = 0; EWRAM_DATA static struct Pokemon sSavedPlayerParty[PARTY_SIZE] = {0}; EWRAM_DATA static struct Pokemon sSavedOpponentParty[PARTY_SIZE] = {0}; EWRAM_DATA static u16 sPlayerMonMoves[MAX_BATTLERS_COUNT / 2][MAX_MON_MOVES] = {0}; -EWRAM_DATA static struct PlayerInfo sPlayers[MAX_BATTLERS_COUNT] = {0}; +EWRAM_DATA static struct PlayerInfo sPlayers[MAX_LINK_PLAYERS] = {0}; EWRAM_DATA static bool8 sIsPlaybackFinished = 0; EWRAM_DATA static u8 sRecordMixFriendName[PLAYER_NAME_LENGTH + 1] = {0}; EWRAM_DATA static u8 sRecordMixFriendClass = 0; @@ -116,7 +116,7 @@ void RecordedBattle_SetTrainerInfo(void) gRecordedBattleMultiplayerId = GetMultiplayerId(); linkPlayersCount = GetLinkPlayerCount(); - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < MAX_LINK_PLAYERS; i++) { sPlayers[i].trainerId = gLinkPlayers[i].trainerId; sPlayers[i].gender = gLinkPlayers[i].gender; @@ -304,7 +304,7 @@ bool32 MoveRecordedBattleToSaveData(void) battleSave->opponentParty[i] = sSavedOpponentParty[i]; } - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < MAX_LINK_PLAYERS; i++) { for (j = 0; j < PLAYER_NAME_LENGTH + 1; j++) battleSave->playersName[i][j] = sPlayers[i].name[j]; @@ -511,7 +511,7 @@ void SetVariablesForRecordedBattle(struct RecordedBattleSave *src) s32 i, j; SetPartiesFromRecordedSave(src); - for (i = 0; i < MAX_BATTLERS_COUNT; i++) + for (i = 0; i < MAX_LINK_PLAYERS; i++) { for (var = FALSE, j = 0; j < PLAYER_NAME_LENGTH + 1; j++) { diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index 020094389a..fc248435a9 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -487,12 +487,49 @@ void ScrCmd_createmon(struct ScriptContext *ctx) u8 speedEv = PARSE_FLAG(8, 0); u8 spAtkEv = PARSE_FLAG(9, 0); u8 spDefEv = PARSE_FLAG(10, 0); - u8 hpIv = PARSE_FLAG(11, Random() % (MAX_PER_STAT_IVS + 1)); - u8 atkIv = PARSE_FLAG(12, Random() % (MAX_PER_STAT_IVS + 1)); - u8 defIv = PARSE_FLAG(13, Random() % (MAX_PER_STAT_IVS + 1)); - u8 speedIv = PARSE_FLAG(14, Random() % (MAX_PER_STAT_IVS + 1)); - u8 spAtkIv = PARSE_FLAG(15, Random() % (MAX_PER_STAT_IVS + 1)); - u8 spDefIv = PARSE_FLAG(16, Random() % (MAX_PER_STAT_IVS + 1)); + u8 hpIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 atkIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 defIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 speedIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 spAtkIv = Random() % (MAX_PER_STAT_IVS + 1); + u8 spDefIv = Random() % (MAX_PER_STAT_IVS + 1); + + // Perfect IV calculation + u32 i; + u8 availableIVs[NUM_STATS]; + u8 selectedIvs[NUM_STATS]; + if (gSpeciesInfo[species].perfectIVCount != 0) + { + // Initialize a list of IV indices. + for (i = 0; i < NUM_STATS; i++) + availableIVs[i] = i; + + // Select the IVs that will be perfected. + for (i = 0; i < NUM_STATS && i < gSpeciesInfo[species].perfectIVCount; i++) + { + u8 index = Random() % (NUM_STATS - i); + selectedIvs[i] = availableIVs[index]; + RemoveIVIndexFromList(availableIVs, index); + } + for (i = 0; i < NUM_STATS && i < gSpeciesInfo[species].perfectIVCount; i++) + { + switch (selectedIvs[i]) + { + case STAT_HP: hpIv = MAX_PER_STAT_IVS; break; + case STAT_ATK: atkIv = MAX_PER_STAT_IVS; break; + case STAT_DEF: defIv = MAX_PER_STAT_IVS; break; + case STAT_SPEED: speedIv = MAX_PER_STAT_IVS; break; + case STAT_SPATK: spAtkIv = MAX_PER_STAT_IVS; break; + case STAT_SPDEF: spDefIv = MAX_PER_STAT_IVS; break; + } + } + } + hpIv = PARSE_FLAG(11, hpIv); + atkIv = PARSE_FLAG(12, atkIv); + defIv = PARSE_FLAG(13, defIv); + speedIv = PARSE_FLAG(14, speedIv); + spAtkIv = PARSE_FLAG(15, spAtkIv); + spDefIv = PARSE_FLAG(16, spDefIv); u16 move1 = PARSE_FLAG(17, MOVE_NONE); u16 move2 = PARSE_FLAG(18, MOVE_NONE); u16 move3 = PARSE_FLAG(19, MOVE_NONE); diff --git a/src/slot_machine.c b/src/slot_machine.c index e813f60c66..7f11396514 100644 --- a/src/slot_machine.c +++ b/src/slot_machine.c @@ -2324,7 +2324,9 @@ static bool8 ReelTask_MoveToStop(struct Task *task) memcpy(reelStopShocks, sReelStopShocks, sizeof(sReelStopShocks)); reelPixelPos = sSlotMachine->reelPixelOffsets[task->tReelId] % REEL_SYMBOL_HEIGHT; if (reelPixelPos != 0) + { reelPixelPos = AdvanceSlotReelToNextSymbol(task->tReelId, sSlotMachine->reelSpeed); + } else if (sSlotMachine->reelExtraTurns[task->tReelId]) { sSlotMachine->reelExtraTurns[task->tReelId]--; diff --git a/src/sprite.c b/src/sprite.c index 8ae96581c9..14e9409c66 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -1048,9 +1048,13 @@ void ContinueAffineAnim(struct Sprite *sprite) u8 matrixNum = GetSpriteMatrixNum(sprite); if (sAffineAnimStates[matrixNum].delayCounter) + { AffineAnimDelay(matrixNum, sprite); + } else if (sprite->affineAnimPaused) + { return; + } else { s16 type; diff --git a/src/tv.c b/src/tv.c index 9030c21478..8313ee9bf5 100644 --- a/src/tv.c +++ b/src/tv.c @@ -5334,7 +5334,8 @@ static void DoTVShow3CheersForPokeblocks(void) if (show->threeCheers.sheen > 24) { StringCopy(gStringVar2, gText_Excellent); - } else if (show->threeCheers.sheen > 22) + } + else if (show->threeCheers.sheen > 22) { StringCopy(gStringVar2, gText_VeryGood); } diff --git a/test/battle/ability/anger_shell.c b/test/battle/ability/anger_shell.c index c5b490216b..cf28fad28c 100644 --- a/test/battle/ability/anger_shell.c +++ b/test/battle/ability/anger_shell.c @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Anger Shell activates only if the target had more than 50% o PARAMETRIZE { hp = 254; activates = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(hp); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Anger Shell lowers Def/Sp.Def by 1 and raises Atk/Sp.Atk/Spd { u16 maxHp = 500; GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/battle_bond.c b/test/battle/ability/battle_bond.c index f61a6d171c..ef2b2753b3 100644 --- a/test/battle/ability/battle_bond.c +++ b/test/battle/ability/battle_bond.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WATER_GUN].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_WATER_GUN)); } SINGLE_BATTLE_TEST("Battle Bond does not transform species other than Greninja") diff --git a/test/battle/ability/berserk.c b/test/battle/ability/berserk.c index 3bf269e1ee..7d7f905170 100644 --- a/test/battle/ability/berserk.c +++ b/test/battle/ability/berserk.c @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Berserk activates only if the target had more than 50% of it PARAMETRIZE { hp = 254; activates = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(hp); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Berserk raises Sp.Atk by 1") { u16 maxHp = 500; GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/cotton_down.c b/test/battle/ability/cotton_down.c index 4d0dab9dcc..02a0f18f63 100644 --- a/test/battle/ability/cotton_down.c +++ b/test/battle/ability/cotton_down.c @@ -62,3 +62,37 @@ DOUBLE_BATTLE_TEST("Cotton Down drops speed by one of all other battlers on the EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); } } + +DOUBLE_BATTLE_TEST("Cotton Down correctly gets blocked by stat reduction preventing abilities") +{ + GIVEN { + PLAYER(SPECIES_METAGROSS) { Ability(ABILITY_CLEAR_BODY); } + PLAYER(SPECIES_WYNAUT) { Item(ITEM_CLEAR_AMULET); } + OPPONENT(SPECIES_ELDEGOSS) { Ability(ABILITY_COTTON_DOWN); } + OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_COTTON_DOWN); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Metagross's Speed fell!"); + } + ABILITY_POPUP(playerLeft, ABILITY_CLEAR_BODY); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + MESSAGE("Wynaut's Speed fell!"); + } + MESSAGE("The effects of the Clear Amulet held by Wynaut prevents its stats from being lowered!"); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("The opposing Corviknight's Speed fell!"); + } + ABILITY_POPUP(opponentRight, ABILITY_MIRROR_ARMOR); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/ability/cud_chew.c b/test/battle/ability/cud_chew.c index 297635c9f3..b3dd92ecd5 100644 --- a/test/battle/ability/cud_chew.c +++ b/test/battle/ability/cud_chew.c @@ -29,7 +29,7 @@ SINGLE_BATTLE_TEST("Cud Chew will activate Oran Berry effect again on the next t ASSUME(gItemsInfo[ITEM_ORAN_BERRY].holdEffect == HOLD_EFFECT_RESTORE_HP); ASSUME(gItemsInfo[ITEM_ORAN_BERRY].holdEffectParam == 10); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TAUROS_PALDEA_COMBAT) { MaxHP(60); HP(60); Ability(ABILITY_CUD_CHEW); Item(ITEM_ORAN_BERRY); } } WHEN { diff --git a/test/battle/ability/desolate_land.c b/test/battle/ability/desolate_land.c index 06d604e8fc..18fe76b0c9 100644 --- a/test/battle/ability/desolate_land.c +++ b/test/battle/ability/desolate_land.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WATER_GUN].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_WATER_GUN)); ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); } @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Desolate Land blocks damaging Water-type moves") DOUBLE_BATTLE_TEST("Desolate Land blocks damaging Water-type moves and prints the message only once with moves hitting multiple targets") { GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_SURF)); ASSUME(gMovesInfo[MOVE_SURF].type == TYPE_WATER); ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_GROUDON) {Item(ITEM_RED_ORB); {Speed(5);}} diff --git a/test/battle/ability/disguise.c b/test/battle/ability/disguise.c index 3a8df70be5..9c5f917e9d 100644 --- a/test/battle/ability/disguise.c +++ b/test/battle/ability/disguise.c @@ -173,3 +173,19 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu blocks a move after getting Gastro Acid Ba ABILITY_POPUP(player, ABILITY_DISGUISE); } } + +SINGLE_BATTLE_TEST("Disguise does not break from a teammate's Wish") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_WISH].effect == EFFECT_WISH); + PLAYER(SPECIES_JIRACHI); + PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); HP(219); MaxHP(220); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_WISH); } + TURN { SWITCH(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WISH, player); + NOT ABILITY_POPUP(player, ABILITY_DISGUISE); + } +} diff --git a/test/battle/ability/electromorphosis.c b/test/battle/ability/electromorphosis.c index 094b2843bf..0f0ac1c39a 100644 --- a/test/battle/ability/electromorphosis.c +++ b/test/battle/ability/electromorphosis.c @@ -10,11 +10,11 @@ SINGLE_BATTLE_TEST("Electromorphosis sets up Charge when hit by any move") PARAMETRIZE {move = MOVE_GUST; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); - ASSUME(gMovesInfo[MOVE_GUST].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IS_MOVE_STATUS(MOVE_GUST)); ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_THUNDER_SHOCK)); ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); PLAYER(SPECIES_BELLIBOLT) { Ability(ABILITY_ELECTROMORPHOSIS); Speed(10); } diff --git a/test/battle/ability/frisk.c b/test/battle/ability/frisk.c index 3c892329c3..28bd477a35 100644 --- a/test/battle/ability/frisk.c +++ b/test/battle/ability/frisk.c @@ -42,7 +42,7 @@ DOUBLE_BATTLE_TEST("Frisk triggers for player in a Double Battle after switching PARAMETRIZE { target = playerRight; } GIVEN { - ASSUME(gMovesInfo[MOVE_POUND].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_POUND)); PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_FURRET) { Ability(ABILITY_FRISK); }; @@ -65,7 +65,7 @@ DOUBLE_BATTLE_TEST("Frisk triggers for opponent in a Double Battle after switchi PARAMETRIZE { target = opponentRight; } GIVEN { - ASSUME(gMovesInfo[MOVE_POUND].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_POUND)); PLAYER(SPECIES_WYNAUT) { Item(ITEM_POTION); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { HP(1); } diff --git a/test/battle/ability/gulp_missile.c b/test/battle/ability/gulp_missile.c index f5e1fd9d9d..189702a4be 100644 --- a/test/battle/ability/gulp_missile.c +++ b/test/battle/ability/gulp_missile.c @@ -92,6 +92,7 @@ SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant deal 1/4 of damage oppo MESSAGE("The opposing Wobbuffet's Defense fell!"); } THEN { EXPECT_EQ(gulpMissileDamage, opponent->maxHP / 4); + EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1); } } @@ -133,3 +134,59 @@ SINGLE_BATTLE_TEST("(Gulp Missile) triggers even if the user is fainted by oppos STATUS_ICON(opponent, paralysis: TRUE); } } + +SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense but is prevented by stat reduction preventing abilities") +{ + u32 species, ability; + PARAMETRIZE { species = SPECIES_METAGROSS; ability = ABILITY_CLEAR_BODY; } + PARAMETRIZE { species = SPECIES_CORVIKNIGHT; ability = ABILITY_MIRROR_ARMOR; } + PARAMETRIZE { species = SPECIES_CHATOT; ability = ABILITY_BIG_PECKS; } + GIVEN { + PLAYER(SPECIES_CRAMORANT) { Ability(ABILITY_GULP_MISSILE); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SURF); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, player); + HP_BAR(opponent); + ABILITY_POPUP(player, ABILITY_GULP_MISSILE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_GULP_MISSILE); + ABILITY_POPUP(opponent, ability); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + } THEN { + EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense and still triggers other effects after") +{ + // Make sure attacker and target are correct after triggering the ability + u32 ability; + PARAMETRIZE { ability = ABILITY_INFILTRATOR; } + PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } + GIVEN { + ASSUME(gMovesInfo[MOVE_TACKLE].makesContact == TRUE); + PLAYER(SPECIES_CRAMORANT) { Ability(ABILITY_GULP_MISSILE); Item(ITEM_ROCKY_HELMET); } + OPPONENT(SPECIES_DRAGAPULT) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SURF); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SURF, player); + HP_BAR(opponent); + ABILITY_POPUP(player, ABILITY_GULP_MISSILE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_GULP_MISSILE); + HP_BAR(opponent); + if (ability == ABILITY_INFILTRATOR) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("The opposing Dragapult's Defense fell!"); + } else { + ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY); + } + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(opponent); + } +} diff --git a/test/battle/ability/innards_out.c b/test/battle/ability/innards_out.c index bc59bcfa0b..5837b98d1f 100644 --- a/test/battle/ability/innards_out.c +++ b/test/battle/ability/innards_out.c @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Innards Out deal dmg on fainting equal to the amount of dmg PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(70); SpAttack(1000); } OPPONENT(SPECIES_WOBBUFFET); - ASSUME(gMovesInfo[MOVE_PSYCHIC].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_PSYCHIC)); ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL); } WHEN { TURN { MOVE(opponent, MOVE_PSYCHIC); SEND_OUT(player, 1); if (hp == 100) { SEND_OUT(opponent, 1); } } @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Innards Out does not trigger after Gastro Acid has been used PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); - ASSUME(gMovesInfo[MOVE_PSYCHIC].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_PSYCHIC)); ASSUME(gMovesInfo[MOVE_GASTRO_ACID].effect == EFFECT_GASTRO_ACID); } WHEN { TURN { MOVE(opponent, MOVE_GASTRO_ACID); } @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Innards Out does not damage Magic Guard Pokemon") PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_CLEFABLE) { Ability(ABILITY_MAGIC_GUARD); } - ASSUME(gMovesInfo[MOVE_PSYCHIC].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_PSYCHIC)); } WHEN { TURN { MOVE(opponent, MOVE_PSYCHIC); SEND_OUT(player, 1); } } SCENE { diff --git a/test/battle/ability/magician.c b/test/battle/ability/magician.c index a951c2f973..14e553a763 100644 --- a/test/battle/ability/magician.c +++ b/test/battle/ability/magician.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Magician does not get self-damage recoil after stealing Life { GIVEN { ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_DELPHOX) { Ability(ABILITY_MAGICIAN); Item(ITEM_NONE); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); } } WHEN { diff --git a/test/battle/ability/pickup.c b/test/battle/ability/pickup.c index 927e1b3468..a6dabb66cc 100644 --- a/test/battle/ability/pickup.c +++ b/test/battle/ability/pickup.c @@ -23,7 +23,24 @@ SINGLE_BATTLE_TEST("Pickup grants an item used by another Pokémon") } } -SINGLE_BATTLE_TEST("Pickup doesn't grant the user their item") +WILD_BATTLE_TEST("Pickup grants an item used by itself in wild battles (Gen 9)") +{ + GIVEN { + ASSUME(B_PICKUP_WILD >= GEN_9); + PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ABILITY_POPUP(player, ABILITY_PICKUP); + MESSAGE("Zigzagoon found one Sitrus Berry!"); + } THEN { + EXPECT_EQ(player->item, ITEM_SITRUS_BERRY); + } +} + +SINGLE_BATTLE_TEST("Pickup doesn't grant the user their item outside wild battles") { GIVEN { PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/primordial_sea.c b/test/battle/ability/primordial_sea.c index 643dca161c..01ed892874 100644 --- a/test/battle/ability/primordial_sea.c +++ b/test/battle/ability/primordial_sea.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_EMBER].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_EMBER)); ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); } @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Primordial Sea blocks damaging Fire-type moves") DOUBLE_BATTLE_TEST("Primordial Sea blocks damaging Fire-type moves and prints the message only once with moves hitting multiple targets") { GIVEN { - ASSUME(gMovesInfo[MOVE_ERUPTION].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_ERUPTION)); ASSUME(gMovesInfo[MOVE_ERUPTION].type == TYPE_FIRE); ASSUME(gMovesInfo[MOVE_ERUPTION].target == MOVE_TARGET_BOTH); PLAYER(SPECIES_KYOGRE) {Item(ITEM_BLUE_ORB); {Speed(5);}} diff --git a/test/battle/ability/rattled.c b/test/battle/ability/rattled.c index 5d3e47db33..da8157d28a 100644 --- a/test/battle/ability/rattled.c +++ b/test/battle/ability/rattled.c @@ -4,13 +4,13 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_FURY_CUTTER].type == TYPE_BUG); - ASSUME(gMovesInfo[MOVE_FURY_CUTTER].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_FURY_CUTTER)); ASSUME(gMovesInfo[MOVE_FEINT_ATTACK].type == TYPE_DARK); - ASSUME(gMovesInfo[MOVE_FEINT_ATTACK].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_FEINT_ATTACK)); ASSUME(gMovesInfo[MOVE_SHADOW_PUNCH].type == TYPE_GHOST); - ASSUME(gMovesInfo[MOVE_SHADOW_PUNCH].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_SHADOW_PUNCH)); ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); } SINGLE_BATTLE_TEST("Rattled boosts speed by 1 when hit by Bug, Dark or Ghost type move") diff --git a/test/battle/ability/regenerator.c b/test/battle/ability/regenerator.c new file mode 100644 index 0000000000..0f1b432772 --- /dev/null +++ b/test/battle/ability/regenerator.c @@ -0,0 +1,50 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Regenerator heals 1/3 of max HP upon switching out") +{ + u32 currHP; + PARAMETRIZE { currHP = 1; } + PARAMETRIZE { currHP = 2; } + PARAMETRIZE { currHP = 3; } + GIVEN { + PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_REGENERATOR); HP(currHP); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(player, 1); } + TURN { SWITCH(player, 0); } + } SCENE { + SWITCH_OUT_MESSAGE("Slowbro"); + SEND_IN_MESSAGE("Wobbuffet"); + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Slowbro"); + } THEN { + EXPECT_EQ(player->hp, player->maxHP / 3 + currHP); + } +} + +SINGLE_BATTLE_TEST("Regenerator heals 1/3 of max HP upon switching out but doesn't surpass max HP") +{ + u32 currHP; + PARAMETRIZE { currHP = 5; } + PARAMETRIZE { currHP = 4; } + PARAMETRIZE { currHP = 3; } + PARAMETRIZE { currHP = 2; } + PARAMETRIZE { currHP = 1; } + GIVEN { + PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_REGENERATOR); HP(currHP); MaxHP(5); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(player, 1); } + TURN { SWITCH(player, 0); } + } SCENE { + SWITCH_OUT_MESSAGE("Slowbro"); + SEND_IN_MESSAGE("Wobbuffet"); + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Slowbro"); + } THEN { + EXPECT_LE(player->hp, player->maxHP); + } +} diff --git a/test/battle/ability/sheer_force.c b/test/battle/ability/sheer_force.c index 97dee48a31..e06e56c2c5 100644 --- a/test/battle/ability/sheer_force.c +++ b/test/battle/ability/sheer_force.c @@ -7,64 +7,909 @@ ASSUMPTIONS ASSUME(MoveIsAffectedBySheerForce(MOVE_ELECTRO_SHOT) == TRUE); } -SINGLE_BATTLE_TEST("Sheer Force boosts power, but removes secondary effects of moves", s16 damage) +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Magnitude", s16 damage) { - s32 j; - u32 ability = 0, move = 0; - - for (j = 1; j < MOVES_COUNT; j++) - { - if (MoveIsAffectedBySheerForce(j) - //&& gMovesInfo[j].effect != EFFECT_ORDER_UP - && gMovesInfo[j].effect != EFFECT_AURA_WHEEL - && gMovesInfo[j].effect != EFFECT_PLACEHOLDER) - { - PARAMETRIZE { ability = ABILITY_ANGER_POINT; move = j; } - PARAMETRIZE { ability = ABILITY_SHEER_FORCE; move = j; } - } - } - + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } GIVEN { - PLAYER(SPECIES_TAUROS) { Ability(ability); Status1(move == MOVE_SNORE ? STATUS1_SLEEP : STATUS1_NONE); } + PLAYER(SPECIES_TAUROS) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect - TURN { MOVE(opponent, MOVE_AGILITY); MOVE(player, move); } - else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move - TURN { MOVE(opponent, MOVE_QUICK_ATTACK); MOVE(player, move); } - else - TURN { MOVE(player, move); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE) { - TURN { SKIP_TURN(player); } - TURN { ; } - } + TURN { MOVE(player, MOVE_MAGNITUDE); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, move, player); HP_BAR(opponent, captureDamage: &results[i].damage); - if (ability == ABILITY_SHEER_FORCE) { - NONE_OF { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - STATUS_ICON(opponent, STATUS1_FREEZE); - STATUS_ICON(opponent, STATUS1_POISON); - STATUS_ICON(opponent, STATUS1_BURN); - STATUS_ICON(opponent, STATUS1_TOXIC_POISON); - STATUS_ICON(opponent, STATUS1_PARALYSIS); - MESSAGE("Wobbuffet is confused!"); - MESSAGE("Wobbuffet flinched and couldn't move!"); - } - // Volt Tackle/Flare Blitz edge case: recoil happens, but target isn't statused - if (gMovesInfo[move].recoil > 0) - { - HP_BAR(player); - MESSAGE("Tauros was damaged by the recoil!"); - } - } } FINALLY { - s32 j; - for (j = 0; j < gBattleTestRunnerState->parametersCount; j+=2) - { - EXPECT_GT(results[j+1].damage, results[j].damage); - } + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Eruption", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PRESENT); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Water Spout", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PRESENT); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Present", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PRESENT); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Psywave", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PSYWAVE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Round", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ROUND); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Gyro Ball", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GYRO_BALL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Electro Ball", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRO_BALL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Dragon Energy", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DRAGON_ENERGY); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Belch", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); HP(1); Item(ITEM_SITRUS_BERRY); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Shell Trap", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SHELL_TRAP); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Burn Up", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ZEN_MODE; } + GIVEN { + PLAYER(SPECIES_DARMANITAN) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BURN_UP); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Double Shock", s16 damage) +{ + u16 move = 0; + PARAMETRIZE { move = MOVE_SKILL_SWAP; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_PIKACHU); + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_DOUBLE_SHOCK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Steel Roller", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_GRASSY_TERRAIN); MOVE(player, MOVE_STEEL_ROLLER); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Synchronoise", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); HP(1); Item(ITEM_SITRUS_BERRY); } + OPPONENT(SPECIES_CHANSEY); + } WHEN { + TURN { MOVE(player, MOVE_SYNCHRONOISE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Aura Wheel", s16 damage) +{ + u16 move = 0; + PARAMETRIZE { move = MOVE_SKILL_SWAP; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_MORPEKO); + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_AURA_WHEEL); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Hyperspace Fury", s16 damage) +{ + u16 move = 0; + PARAMETRIZE { move = MOVE_SKILL_SWAP; } + PARAMETRIZE { move = MOVE_CELEBRATE; } + GIVEN { + PLAYER(SPECIES_HOOPA_UNBOUND); + OPPONENT(SPECIES_TAUROS) { Ability(ABILITY_SHEER_FORCE); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_HYPERSPACE_FURY); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Bolt Beak", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BOLT_BEAK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Fishious Rend", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FISHIOUS_REND); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_COMEUPPANCE); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} +SINGLE_BATTLE_TEST("Sheer Force doesn't boost Comeuppance", s16 damage) +{ + u16 ability = 0; + PARAMETRIZE { ability = ABILITY_SHEER_FORCE; } + PARAMETRIZE { ability = ABILITY_ANGER_POINT; } + GIVEN { + PLAYER(SPECIES_TAUROS) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PAYBACK); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + EXPECT_NE(results[0].damage, 0); + } +} + +static inline bool32 IgnoreMoveForSheerForceBoost(u32 move) +{ + switch (move) { + case MOVE_PSYWAVE: // Just skip Psywve + case MOVE_PRESENT: // And Present... + case MOVE_MAGNITUDE: // And Magnitude... + case MOVE_ERUPTION: // And Eruption... + case MOVE_WATER_SPOUT: + case MOVE_GYRO_BALL: + case MOVE_SYNCHRONOISE: + case MOVE_ELECTRO_BALL: + case MOVE_ROUND: + case MOVE_BELCH: + case MOVE_HYPERSPACE_FURY: + case MOVE_BURN_UP: + case MOVE_SHELL_TRAP: + case MOVE_BOLT_BEAK: + case MOVE_FISHIOUS_REND: + case MOVE_AURA_WHEEL: + case MOVE_STEEL_ROLLER: + case MOVE_DRAGON_ENERGY: + case MOVE_DOUBLE_SHOCK: + case MOVE_COMEUPPANCE: + case MOVE_UPPER_HAND: // Bugged? + case MOVE_GLITZY_GLOW: // Light Screen Move Effect seems to be bugged + case MOVE_PAYBACK: + return TRUE; + } + return FALSE; +} + +static inline bool32 IsMoveSheerForceBoosted(u32 move) +{ + switch (move) { + case MOVE_AIR_SLASH: + case MOVE_ANCIENT_POWER: + case MOVE_ASTONISH: + case MOVE_BITE: + case MOVE_BLIZZARD: + case MOVE_BODY_SLAM: + case MOVE_BOUNCE: + case MOVE_BREAKING_SWIPE: + case MOVE_BUBBLE: + case MOVE_BUBBLE_BEAM: + case MOVE_BUG_BUZZ: + case MOVE_BULLDOZE: + case MOVE_BURNING_JEALOUSY: + case MOVE_CHARGE_BEAM: + case MOVE_CHILLING_WATER: + case MOVE_CONFUSION: + case MOVE_CRUNCH: + case MOVE_CRUSH_CLAW: + case MOVE_DARK_PULSE: + case MOVE_DRAGON_RUSH: + case MOVE_DRAGON_BREATH: + case MOVE_DYNAMIC_PUNCH: + case MOVE_EARTH_POWER: + case MOVE_EMBER: + case MOVE_ESPER_WING: + case MOVE_EXTRASENSORY: + case MOVE_FAKE_OUT: + case MOVE_FIRE_BLAST: + case MOVE_FIRE_FANG: + case MOVE_FIRE_PUNCH: + case MOVE_FLAME_CHARGE: + case MOVE_FLAME_WHEEL: + case MOVE_FLAMETHROWER: + case MOVE_FLARE_BLITZ: + case MOVE_FLASH_CANNON: + case MOVE_FOCUS_BLAST: + case MOVE_FORCE_PALM: + case MOVE_GUNK_SHOT: + case MOVE_HEADBUTT: + case MOVE_HEAT_WAVE: + case MOVE_HURRICANE: + case MOVE_ICE_BEAM: + case MOVE_ICE_FANG: + case MOVE_ICE_PUNCH: + case MOVE_ICICLE_CRASH: + case MOVE_ICY_WIND: + case MOVE_IRON_HEAD: + case MOVE_IRON_TAIL: + case MOVE_LAVA_PLUME: + case MOVE_LIQUIDATION: + case MOVE_LOW_SWEEP: + case MOVE_METAL_CLAW: + case MOVE_MUD_BOMB: + case MOVE_MUDDY_WATER: + case MOVE_MUD_SHOT: + case MOVE_MUD_SLAP: + case MOVE_MYSTICAL_FIRE: + case MOVE_PLAY_ROUGH: + case MOVE_POISON_FANG: + case MOVE_POISON_JAB: + case MOVE_POISON_STING: + case MOVE_POISON_TAIL: + case MOVE_POUNCE: + case MOVE_POWER_UP_PUNCH: + case MOVE_PSYBEAM: + case MOVE_PSYCHIC: + case MOVE_RAZOR_SHELL: + case MOVE_ROCK_CLIMB: + case MOVE_ROCK_SLIDE: + case MOVE_ROCK_SMASH: + case MOVE_ROCK_TOMB: + case MOVE_SANDSEAR_STORM: + case MOVE_SCALD: + case MOVE_SCORCHING_SANDS: + case MOVE_SECRET_POWER: + case MOVE_SHADOW_BALL: + case MOVE_SIGNAL_BEAM: + case MOVE_SKY_ATTACK: + case MOVE_SLUDGE_BOMB: + case MOVE_SLUDGE_WAVE: + case MOVE_SNARL: + case MOVE_SNORE: + case MOVE_STEEL_WING: + case MOVE_STOMP: + case MOVE_STONE_AXE: + case MOVE_STRUGGLE_BUG: + case MOVE_THROAT_CHOP: + case MOVE_THUNDER: + case MOVE_THUNDER_FANG: + case MOVE_THUNDERBOLT: + case MOVE_THUNDER_PUNCH: + case MOVE_TRAILBLAZE: + case MOVE_TWISTER: + case MOVE_UPPER_HAND: + case MOVE_WATER_PULSE: + case MOVE_WATERFALL: + case MOVE_ZAP_CANNON: + case MOVE_ZEN_HEADBUTT: + case MOVE_ACID: + case MOVE_ACID_SPRAY: + case MOVE_ALLURING_VOICE: + case MOVE_ANCHOR_SHOT: + case MOVE_APPLE_ACID: + case MOVE_AQUA_STEP: + case MOVE_AURA_WHEEL: + case MOVE_AURORA_BEAM: + case MOVE_AXE_KICK: + case MOVE_BARB_BARRAGE: + case MOVE_BITTER_MALICE: + case MOVE_BLAZE_KICK: + case MOVE_BLAZING_TORQUE: + case MOVE_BLEAKWIND_STORM: + case MOVE_BLUE_FLARE: + case MOVE_BOLT_STRIKE: + case MOVE_BONE_CLUB: + case MOVE_CEASELESS_EDGE: + case MOVE_CHATTER: + case MOVE_CLANGOROUS_SOULBLAZE: + case MOVE_COMBAT_TORQUE: + case MOVE_CONSTRICT: + case MOVE_CROSS_POISON: + case MOVE_DIAMOND_STORM: + case MOVE_DIRE_CLAW: + case MOVE_DISCHARGE: + case MOVE_DIZZY_PUNCH: + case MOVE_DOUBLE_IRON_BASH: + case MOVE_DRUM_BEATING: + case MOVE_EERIE_SPELL: + case MOVE_ELECTROWEB: + case MOVE_ENERGY_BALL: + case MOVE_FIERY_DANCE: + case MOVE_FIERY_WRATH: + case MOVE_FREEZING_GLARE: + case MOVE_FIRE_LASH: + case MOVE_FREEZE_DRY: + case MOVE_FREEZE_SHOCK: + case MOVE_GENESIS_SUPERNOVA: + case MOVE_GLACIATE: + case MOVE_GRAV_APPLE: + case MOVE_HEART_STAMP: + case MOVE_HYPER_FANG: + case MOVE_ICE_BURN: + case MOVE_INFERNAL_PARADE: + case MOVE_INFERNO: + case MOVE_LEAF_TORNADO: + case MOVE_LICK: + case MOVE_LUMINA_CRASH: + case MOVE_LUNGE: + case MOVE_LUSTER_PURGE: + case MOVE_MAGICAL_TORQUE: + case MOVE_MALIGNANT_CHAIN: + case MOVE_MATCHA_GOTCHA: + case MOVE_METEOR_MASH: + case MOVE_MIRROR_SHOT: + case MOVE_MIST_BALL: + case MOVE_MOONBLAST: + case MOVE_MORTAL_SPIN: + case MOVE_MOUNTAIN_GALE: + case MOVE_MYSTICAL_POWER: + case MOVE_NEEDLE_ARM: + case MOVE_NIGHT_DAZE: + case MOVE_NOXIOUS_TORQUE: + case MOVE_NUZZLE: + case MOVE_OCTAZOOKA: + case MOVE_OMINOUS_WIND: + case MOVE_ORDER_UP: + case MOVE_POWDER_SNOW: + case MOVE_PSYSHIELD_BASH: + case MOVE_PYRO_BALL: + case MOVE_RAPID_SPIN: + case MOVE_RELIC_SONG: + case MOVE_ROLLING_KICK: + case MOVE_SACRED_FIRE: + case MOVE_SALT_CURE: + case MOVE_SEARING_SHOT: + case MOVE_SEED_FLARE: + case MOVE_SHADOW_BONE: + case MOVE_SHELL_SIDE_ARM: + case MOVE_SILVER_WIND: + case MOVE_SKITTER_SMACK: + case MOVE_SLUDGE: + case MOVE_SMOG: + case MOVE_SPARK: + case MOVE_SPARKLING_ARIA: + case MOVE_SPIRIT_BREAK: + case MOVE_SPIRIT_SHACKLE: + case MOVE_SPLISHY_SPLASH: + case MOVE_SPRINGTIDE_STORM: + case MOVE_STEAM_ERUPTION: + case MOVE_STEAMROLLER: + case MOVE_STOKED_SPARKSURFER: + case MOVE_STRANGE_STEAM: + case MOVE_SYRUP_BOMB: + case MOVE_THUNDER_SHOCK: + case MOVE_THUNDEROUS_KICK: + case MOVE_TORCH_SONG: + case MOVE_TRI_ATTACK: + case MOVE_TRIPLE_ARROWS: + case MOVE_TROP_KICK: + case MOVE_TWINEEDLE: + case MOVE_VOLT_TACKLE: + case MOVE_WICKED_TORQUE: + case MOVE_WILDBOLT_STORM: + case MOVE_ZING_ZAP: + case MOVE_ELECTRO_SHOT: + case MOVE_PSYCHIC_NOISE: + return TRUE; + } + return FALSE; +} + +// Test split into four parts that handles ~1/4 of all moves each +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 1") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 1; j < MOVES_COUNT; j += 4) + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); + } +} +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 2") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 2; j < MOVES_COUNT; j += 4) + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); + } +} +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 3") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 3; j < MOVES_COUNT; j += 4) + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); + } +} +DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to boost 4") +{ + s16 damage1, damage2; + u32 move = 0; + for (u32 j = 4; j < MOVES_COUNT; j += 4) + { + if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + PARAMETRIZE { move = j; } + } + GIVEN { + PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_STEELIX) { Ability(ABILITY_STURDY); Item(ITEM_BLUK_BERRY); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_TELEPATHY); Level(100); Item(ITEM_BLUK_BERRY); } + } WHEN { + if (move == MOVE_ALLURING_VOICE || move == MOVE_BURNING_JEALOUSY) // Alluring Voice requires the target to boost stats to have an effect + TURN { MOVE(opponentRight, MOVE_AGILITY); MOVE(playerRight, MOVE_AGILITY); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_UPPER_HAND) // Upper Hand requires the target to be using a damaging priority move + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); MOVE(playerRight, move, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_COUNTER || move == MOVE_UPPER_HAND) + TURN { MOVE(opponentRight, MOVE_QUICK_ATTACK, target: playerLeft); + MOVE(playerRight, MOVE_QUICK_ATTACK, target: opponentLeft); + MOVE(playerLeft, move, target: opponentRight); + MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_MIRROR_COAT || move == MOVE_METAL_BURST) + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_SUCKER_PUNCH || move == MOVE_THUNDERCLAP) + TURN { MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + else if (move == MOVE_DREAM_EATER) + { + TURN { MOVE(playerLeft, MOVE_HYPNOSIS, target: opponentRight); MOVE(opponentLeft, MOVE_HYPNOSIS, target: playerRight); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SNORE) + { + TURN { MOVE(opponentRight, MOVE_HYPNOSIS, target: playerLeft); MOVE(playerRight, MOVE_HYPNOSIS, target: opponentLeft); MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else if (move == MOVE_SPIT_UP || move == MOVE_LAST_RESORT) + { + TURN { MOVE(playerLeft, MOVE_STOCKPILE); MOVE(opponentLeft, MOVE_STOCKPILE); } + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + } + else + TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + { + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) + { + TURN { ; } + TURN { ; } + } + if (gMovesInfo[move].effect == EFFECT_BIDE) + { + TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + } + } SCENE { + if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + { + HP_BAR(opponentRight, captureDamage: &damage1); + HP_BAR(playerRight, captureDamage: &damage2); + } + else + { + HP_BAR(playerRight, captureDamage: &damage2); + HP_BAR(opponentRight, captureDamage: &damage1); + } + } THEN { + if (IsMoveSheerForceBoosted(move)) + EXPECT_GT(damage1, damage2); + else + EXPECT_EQ(damage2, damage1); } } diff --git a/test/battle/ability/stamina.c b/test/battle/ability/stamina.c index 0dce4729b2..5bf7dc09a6 100644 --- a/test/battle/ability/stamina.c +++ b/test/battle/ability/stamina.c @@ -24,8 +24,8 @@ SINGLE_BATTLE_TEST("Stamina raises Defense by 1 when hit by a move") PARAMETRIZE {move = MOVE_GUST; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); - ASSUME(gMovesInfo[MOVE_GUST].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IS_MOVE_STATUS(MOVE_GUST)); ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STAMINA); } diff --git a/test/battle/ability/stance_change.c b/test/battle/ability/stance_change.c index 8221e16385..f8a0c70b3e 100644 --- a/test/battle/ability/stance_change.c +++ b/test/battle/ability/stance_change.c @@ -63,7 +63,6 @@ SINGLE_BATTLE_TEST("Stance Change changes Aegislash from Blade to Shield when us SINGLE_BATTLE_TEST("Stance Change doesn't change Aegislash to Shield if King's Shield is called by a different move - Sleep Talk") { - KNOWN_FAILING; // Currently does change form GIVEN { ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); PLAYER(SPECIES_AEGISLASH_BLADE) { Moves(MOVE_KINGS_SHIELD, MOVE_SLEEP_TALK); Status1(STATUS1_SLEEP_TURN(3)); } diff --git a/test/battle/ability/weak_armor.c b/test/battle/ability/weak_armor.c index 7fd7e10ef7..0d264e7ff9 100644 --- a/test/battle/ability/weak_armor.c +++ b/test/battle/ability/weak_armor.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); - ASSUME(gMovesInfo[MOVE_GUST].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IS_MOVE_STATUS(MOVE_GUST)); ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); ASSUME(B_WEAK_ARMOR_SPEED >= GEN_7); diff --git a/test/battle/ability/wind_power.c b/test/battle/ability/wind_power.c index 831a2a66df..9ad42fad0f 100644 --- a/test/battle/ability/wind_power.c +++ b/test/battle/ability/wind_power.c @@ -3,13 +3,13 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_THUNDERBOLT)); ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); - ASSUME(gMovesInfo[MOVE_AIR_CUTTER].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IS_MOVE_STATUS(MOVE_AIR_CUTTER)); ASSUME(gMovesInfo[MOVE_AIR_CUTTER].target == MOVE_TARGET_BOTH); ASSUME(gMovesInfo[MOVE_AIR_CUTTER].windMove == TRUE); - ASSUME(gMovesInfo[MOVE_PETAL_BLIZZARD].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_PETAL_BLIZZARD)); ASSUME(gMovesInfo[MOVE_PETAL_BLIZZARD].target == MOVE_TARGET_FOES_AND_ALLY); ASSUME(gMovesInfo[MOVE_PETAL_BLIZZARD].windMove == TRUE); ASSUME(gMovesInfo[MOVE_TACKLE].windMove == FALSE); diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index 37ad7edb15..7279085ff2 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -37,7 +37,7 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Smelling Salt") GIVEN { ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument == STATUS1_PARALYSIS); + ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument.status == STATUS1_PARALYSIS); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(60); Status1(status1); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_BODY_SLAM, MOVE_SMELLING_SALTS); } @@ -59,7 +59,7 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Wake Up Slap") GIVEN { ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument == STATUS1_SLEEP); + ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument.status == STATUS1_SLEEP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_MEGANIUM) { HP(35); Status1(status1); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_BODY_SLAM, MOVE_WAKE_UP_SLAP); } diff --git a/test/battle/form_change/primal_reversion.c b/test/battle/form_change/primal_reversion.c index 72e2a7e3c6..d4e682e8de 100644 --- a/test/battle/form_change/primal_reversion.c +++ b/test/battle/form_change/primal_reversion.c @@ -120,7 +120,7 @@ DOUBLE_BATTLE_TEST("Primal reversion's order is determined by Speed - player fas SINGLE_BATTLE_TEST("Primal reversion happens after a mon is sent out after a mon is fainted") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET) {HP(1); } PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } OPPONENT(SPECIES_WOBBUFFET); @@ -156,7 +156,7 @@ SINGLE_BATTLE_TEST("Primal reversion happens after a mon is switched in") SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Eject Button") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); ASSUME(gItemsInfo[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON); PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_EJECT_BUTTON); } PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } @@ -177,7 +177,7 @@ SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Eject B SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Red Card") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); ASSUME(gItemsInfo[ITEM_RED_CARD].holdEffect == HOLD_EFFECT_RED_CARD); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index abc9a11c4d..d76febbd0a 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -626,7 +626,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") { GIVEN { // Fails?: ASSUME(GetMaxMove(B_POSITION_PLAYER_LEFT, MOVE_TACKLE) == MOVE_MAX_STRIKE); - ASSUME(gMovesInfo[MOVE_MAX_STRIKE].argument == MAX_EFFECT_LOWER_SPEED); + ASSUME(gMovesInfo[MOVE_MAX_STRIKE].argument.maxEffect == MAX_EFFECT_LOWER_SPEED); OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } PLAYER(SPECIES_WOBBUFFET) { Speed(80); } } WHEN { @@ -650,7 +650,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") DOUBLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers both opponents' speed") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_STRIKE].argument == MAX_EFFECT_LOWER_SPEED); + ASSUME(gMovesInfo[MOVE_MAX_STRIKE].argument.maxEffect == MAX_EFFECT_LOWER_SPEED); PLAYER(SPECIES_WOBBUFFET) { Speed(80); } PLAYER(SPECIES_WOBBUFFET) { Speed(79); } OPPONENT(SPECIES_WOBBUFFET) {Speed(100); } @@ -687,7 +687,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") { s16 damage[4]; GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_KNUCKLE].argument == MAX_EFFECT_RAISE_TEAM_ATTACK); + ASSUME(gMovesInfo[MOVE_MAX_KNUCKLE].argument.maxEffect == MAX_EFFECT_RAISE_TEAM_ATTACK); ASSUME(gMovesInfo[MOVE_CLOSE_COMBAT].category == DAMAGE_CATEGORY_PHYSICAL); ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); @@ -729,7 +729,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") SINGLE_BATTLE_TEST("(DYNAMAX) Max Flare sets up sunlight") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_FLARE].argument == MAX_EFFECT_SUN); + ASSUME(gMovesInfo[MOVE_MAX_FLARE].argument.maxEffect == MAX_EFFECT_SUN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -745,7 +745,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Flare sets up sunlight") SINGLE_BATTLE_TEST("(DYNAMAX) Max Geyser sets up heavy rain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_GEYSER].argument == MAX_EFFECT_RAIN); + ASSUME(gMovesInfo[MOVE_MAX_GEYSER].argument.maxEffect == MAX_EFFECT_RAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -761,7 +761,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Geyser sets up heavy rain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Hailstorm sets up hail") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_HAILSTORM].argument == MAX_EFFECT_HAIL); + ASSUME(gMovesInfo[MOVE_MAX_HAILSTORM].argument.maxEffect == MAX_EFFECT_HAIL); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -777,7 +777,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Hailstorm sets up hail") SINGLE_BATTLE_TEST("(DYNAMAX) Max Rockfall sets up a sandstorm") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_ROCKFALL].argument == MAX_EFFECT_SANDSTORM); + ASSUME(gMovesInfo[MOVE_MAX_ROCKFALL].argument.maxEffect == MAX_EFFECT_SANDSTORM); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -794,7 +794,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Overgrowth sets up Grassy Terrain") { s32 maxHP = 490; // Because of recalculated stats upon Dynamaxing GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_OVERGROWTH].argument == MAX_EFFECT_GRASSY_TERRAIN); + ASSUME(gMovesInfo[MOVE_MAX_OVERGROWTH].argument.maxEffect == MAX_EFFECT_GRASSY_TERRAIN); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].baseHP == 190); OPPONENT(SPECIES_WOBBUFFET) { MaxHP(maxHP); HP(maxHP / 2); }; PLAYER(SPECIES_WOBBUFFET) { MaxHP(maxHP); HP(maxHP / 2); }; @@ -814,7 +814,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Overgrowth sets up Grassy Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Mindstorm sets up Psychic Terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_MINDSTORM].argument == MAX_EFFECT_PSYCHIC_TERRAIN); + ASSUME(gMovesInfo[MOVE_MAX_MINDSTORM].argument.maxEffect == MAX_EFFECT_PSYCHIC_TERRAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -831,7 +831,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Mindstorm sets up Psychic Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Lightning sets up Electric Terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_LIGHTNING].argument == MAX_EFFECT_ELECTRIC_TERRAIN); + ASSUME(gMovesInfo[MOVE_MAX_LIGHTNING].argument.maxEffect == MAX_EFFECT_ELECTRIC_TERRAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -846,7 +846,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Lightning sets up Electric Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Starfall sets up Misty Terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_STARFALL].argument == MAX_EFFECT_MISTY_TERRAIN); + ASSUME(gMovesInfo[MOVE_MAX_STARFALL].argument.maxEffect == MAX_EFFECT_MISTY_TERRAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -861,7 +861,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Starfall sets up Misty Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STONESURGE].argument == MAX_EFFECT_STEALTH_ROCK); + ASSUME(gMovesInfo[MOVE_G_MAX_STONESURGE].argument.maxEffect == MAX_EFFECT_STEALTH_ROCK); PLAYER(SPECIES_DREDNAW) { GigantamaxFactor(TRUE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -881,7 +881,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks") SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Steelsurge sets up sharp steel") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STEELSURGE].argument == MAX_EFFECT_STEELSURGE); + ASSUME(gMovesInfo[MOVE_G_MAX_STEELSURGE].argument.maxEffect == MAX_EFFECT_STEELSURGE); PLAYER(SPECIES_COPPERAJAH) { GigantamaxFactor(TRUE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_HATTERENE); @@ -912,7 +912,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Hydrosnipe has fixed power and ignores abili PARAMETRIZE { move = MOVE_WATER_GUN; } PARAMETRIZE { move = MOVE_HYDRO_CANNON; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_HYDROSNIPE].argument == MAX_EFFECT_FIXED_POWER); + ASSUME(gMovesInfo[MOVE_G_MAX_HYDROSNIPE].argument.maxEffect == MAX_EFFECT_FIXED_POWER); PLAYER(SPECIES_INTELEON) { GigantamaxFactor(TRUE); } OPPONENT(SPECIES_ARCTOVISH) { Ability(ABILITY_WATER_ABSORB); } } WHEN { @@ -928,7 +928,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Hydrosnipe has fixed power and ignores abili DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Volt Crash paralyzes both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_VOLT_CRASH].argument == MAX_EFFECT_PARALYZE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_VOLT_CRASH].argument.maxEffect == MAX_EFFECT_PARALYZE_FOES); PLAYER(SPECIES_PIKACHU) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_PICHU); OPPONENT(SPECIES_WOBBUFFET); @@ -955,7 +955,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponen PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = STATUS1_PARALYSIS; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STUN_SHOCK].argument == MAX_EFFECT_POISON_PARALYZE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_STUN_SHOCK].argument.maxEffect == MAX_EFFECT_POISON_PARALYZE_FOES); PLAYER(SPECIES_TOXTRICITY) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_TOXEL); OPPONENT(SPECIES_WOBBUFFET); @@ -992,7 +992,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponen DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock chooses statuses before considering immunities") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STUN_SHOCK].argument == MAX_EFFECT_POISON_PARALYZE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_STUN_SHOCK].argument.maxEffect == MAX_EFFECT_POISON_PARALYZE_FOES); PLAYER(SPECIES_TOXTRICITY) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_TOXEL); OPPONENT(SPECIES_GARBODOR); @@ -1025,7 +1025,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Befuddle paralyzes, poisons, or sleeps both PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_SLP; rng = STATUS1_SLEEP; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_BEFUDDLE].argument == MAX_EFFECT_EFFECT_SPORE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_BEFUDDLE].argument.maxEffect == MAX_EFFECT_EFFECT_SPORE_FOES); PLAYER(SPECIES_BUTTERFREE) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_CATERPIE); OPPONENT(SPECIES_WOBBUFFET); @@ -1069,7 +1069,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Befuddle paralyzes, poisons, or sleeps both DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Gold Rush confuses both opponents and generates money") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_GOLD_RUSH].argument == MAX_EFFECT_CONFUSE_FOES_PAY_DAY); + ASSUME(gMovesInfo[MOVE_G_MAX_GOLD_RUSH].argument.maxEffect == MAX_EFFECT_CONFUSE_FOES_PAY_DAY); PLAYER(SPECIES_MEOWTH) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_PERSIAN); OPPONENT(SPECIES_WOBBUFFET); @@ -1089,7 +1089,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Gold Rush confuses both opponents and genera DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Smite confuses both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_SMITE].argument == MAX_EFFECT_CONFUSE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_SMITE].argument.maxEffect == MAX_EFFECT_CONFUSE_FOES); PLAYER(SPECIES_HATTERENE) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_HATENNA); OPPONENT(SPECIES_WOBBUFFET); @@ -1108,7 +1108,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Smite confuses both opponents") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Cuddle infatuates both opponents, if possible") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_CUDDLE].argument == MAX_EFFECT_INFATUATE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_CUDDLE].argument.maxEffect == MAX_EFFECT_INFATUATE_FOES); PLAYER(SPECIES_EEVEE) { Gender(MON_MALE); GigantamaxFactor(TRUE); } PLAYER(SPECIES_EEVEE); OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); } @@ -1129,7 +1129,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Cuddle infatuates both opponents, if possibl DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Terror traps both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_TERROR].argument == MAX_EFFECT_MEAN_LOOK); + ASSUME(gMovesInfo[MOVE_G_MAX_TERROR].argument.maxEffect == MAX_EFFECT_MEAN_LOOK); PLAYER(SPECIES_GENGAR) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_GASTLY); OPPONENT(SPECIES_WOBBUFFET); @@ -1150,7 +1150,7 @@ TO_DO_BATTLE_TEST("(DYNAMAX) Baton Pass passes G-Max Terror's escape prevention DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Meltdown torments both opponents for 3 turns") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_MELTDOWN].argument == MAX_EFFECT_TORMENT_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_MELTDOWN].argument.maxEffect == MAX_EFFECT_TORMENT_FOES); PLAYER(SPECIES_MELMETAL) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_MELTAN); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH, MOVE_CELEBRATE); } @@ -1187,7 +1187,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Wildfire sets a field effect that damages no { s16 damage; GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_WILDFIRE].argument == MAX_EFFECT_WILDFIRE); + ASSUME(gMovesInfo[MOVE_G_MAX_WILDFIRE].argument.maxEffect == MAX_EFFECT_WILDFIRE); PLAYER(SPECIES_CHARIZARD) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_CHARMANDER); OPPONENT(SPECIES_WOBBUFFET) { HP(600); MaxHP(600); } @@ -1233,7 +1233,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries 50\% of t { PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH); GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_REPLENISH].argument == MAX_EFFECT_RECYCLE_BERRIES); + ASSUME(gMovesInfo[MOVE_G_MAX_REPLENISH].argument.maxEffect == MAX_EFFECT_RECYCLE_BERRIES); PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); } PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); } @@ -1261,7 +1261,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Snooze makes only the target drowsy") { PASSES_RANDOMLY(1, 2, RNG_G_MAX_SNOOZE); GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_SNOOZE].argument == MAX_EFFECT_YAWN_FOE); + ASSUME(gMovesInfo[MOVE_G_MAX_SNOOZE].argument.maxEffect == MAX_EFFECT_YAWN_FOE); ASSUME(gMovesInfo[MOVE_DARK_PULSE].category == DAMAGE_CATEGORY_SPECIAL); // Otherwise, Blissey faints. PLAYER(SPECIES_GRIMMSNARL) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_IMPIDIMP); @@ -1285,7 +1285,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Finale heals allies by 1/6 of their health") { s16 damage1, damage2; GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_FINALE].argument == MAX_EFFECT_HEAL_TEAM); + ASSUME(gMovesInfo[MOVE_G_MAX_FINALE].argument.maxEffect == MAX_EFFECT_HEAL_TEAM); PLAYER(SPECIES_ALCREMIE) { HP(1); GigantamaxFactor(TRUE); } PLAYER(SPECIES_MILCERY) { HP(1); } OPPONENT(SPECIES_WOBBUFFET); @@ -1305,7 +1305,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Finale heals allies by 1/6 of their health") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Sweetness cures allies' status conditions") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_SWEETNESS].argument == MAX_EFFECT_AROMATHERAPY); + ASSUME(gMovesInfo[MOVE_G_MAX_SWEETNESS].argument.maxEffect == MAX_EFFECT_AROMATHERAPY); PLAYER(SPECIES_APPLETUN) { Status1(STATUS1_POISON); GigantamaxFactor(TRUE); } PLAYER(SPECIES_APPLIN) { Status1(STATUS1_POISON); } OPPONENT(SPECIES_WOBBUFFET); @@ -1325,7 +1325,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Sweetness cures allies' status conditions") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Centiferno traps both opponents in Fire Spin") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_CENTIFERNO].argument == MAX_EFFECT_FIRE_SPIN_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_CENTIFERNO].argument.maxEffect == MAX_EFFECT_FIRE_SPIN_FOES); PLAYER(SPECIES_CENTISKORCH) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_SIZZLIPEDE); PLAYER(SPECIES_SIZZLIPEDE); @@ -1354,7 +1354,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance") u32 j; GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_6); - ASSUME(gMovesInfo[MOVE_G_MAX_CHI_STRIKE].argument == MAX_EFFECT_CRIT_PLUS); + ASSUME(gMovesInfo[MOVE_G_MAX_CHI_STRIKE].argument.maxEffect == MAX_EFFECT_CRIT_PLUS); PLAYER(SPECIES_MACHAMP) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_MACHOP); OPPONENT(SPECIES_WOBBUFFET); @@ -1386,7 +1386,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Depletion takes away 2 PP from the target's { GIVEN { ASSUME(gMovesInfo[MOVE_DRAGON_CLAW].category == DAMAGE_CATEGORY_PHYSICAL); // Otherwise Sableye faints. - ASSUME(gMovesInfo[MOVE_G_MAX_DEPLETION].argument == MAX_EFFECT_SPITE); + ASSUME(gMovesInfo[MOVE_G_MAX_DEPLETION].argument.maxEffect == MAX_EFFECT_SPITE); PLAYER(SPECIES_DURALUDON) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_WYNAUT); // Dynamax behaves weird with test turn order because stats are recalculated. @@ -1408,7 +1408,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max One Blow bypasses Max Guard for full damage" PARAMETRIZE { protect = TRUE; } PARAMETRIZE { protect = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_ONE_BLOW].argument == MAX_EFFECT_BYPASS_PROTECT); + ASSUME(gMovesInfo[MOVE_G_MAX_ONE_BLOW].argument.maxEffect == MAX_EFFECT_BYPASS_PROTECT); PLAYER(SPECIES_URSHIFU) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_KUBFU); OPPONENT(SPECIES_WOBBUFFET); @@ -1431,6 +1431,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max One Blow bypasses Max Guard for full damage" } // Bug Testing +// This test will fail if it's the first test a thread runs DOUBLE_BATTLE_TEST("(DYNAMAX) Max Flare doesn't softlock the game when fainting player partner") { GIVEN { diff --git a/test/battle/hold_effect/attack_up.c b/test/battle/hold_effect/attack_up.c index 383e564ce6..d166d8ff2c 100644 --- a/test/battle/hold_effect/attack_up.c +++ b/test/battle/hold_effect/attack_up.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Liechi Berry raises the holder's Attack by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/critical_hit_up.c b/test/battle/hold_effect/critical_hit_up.c index c23f29773a..7bfe4ed74f 100644 --- a/test/battle/hold_effect/critical_hit_up.c +++ b/test/battle/hold_effect/critical_hit_up.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_LANSAT_BERRY].holdEffect == HOLD_EFFECT_CRITICAL_UP); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Lansat Berry raises the holder's critical-hit-ratio by two stages when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/defense_up.c b/test/battle/hold_effect/defense_up.c index 46130b9fe7..87f41be7b3 100644 --- a/test/battle/hold_effect/defense_up.c +++ b/test/battle/hold_effect/defense_up.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_GANLON_BERRY].holdEffect == HOLD_EFFECT_DEFENSE_UP); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Ganlon Berry raises the holder's Defense by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/micle_berry.c b/test/battle/hold_effect/micle_berry.c index 87f6742609..f196c67c96 100644 --- a/test/battle/hold_effect/micle_berry.c +++ b/test/battle/hold_effect/micle_berry.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_MICLE_BERRY].holdEffect == HOLD_EFFECT_MICLE_BERRY); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Micle Berry raises the holder's accuracy by 1.2 when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/room_service.c b/test/battle/hold_effect/room_service.c new file mode 100644 index 0000000000..04b6450e05 --- /dev/null +++ b/test/battle/hold_effect/room_service.c @@ -0,0 +1,33 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gItemsInfo[ITEM_ROOM_SERVICE].holdEffect == HOLD_EFFECT_ROOM_SERVICE); +} + +SINGLE_BATTLE_TEST("Room Serive decreases the holder's seep by one stage") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); + ASSUME(gMovesInfo[MOVE_TRICK_ROOM].effect == EFFECT_TRICK_ROOM); + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); Item(ITEM_ROOM_SERVICE); } + OPPONENT(SPECIES_WYNAUT) { HP(1); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_TRICK_ROOM); } + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TRICK_ROOM, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + HP_BAR(opponent); + MESSAGE("2 sent out Wynaut!"); + ABILITY_POPUP(player, ABILITY_INTIMIDATE); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE - 1); + } +} diff --git a/test/battle/hold_effect/special_attack_up.c b/test/battle/hold_effect/special_attack_up.c index ef348024fc..9ae73340bf 100644 --- a/test/battle/hold_effect/special_attack_up.c +++ b/test/battle/hold_effect/special_attack_up.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_PETAYA_BERRY].holdEffect == HOLD_EFFECT_SP_ATTACK_UP); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Petaya Berry raises the holder's Sp. Atk by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/special_defense_up.c b/test/battle/hold_effect/special_defense_up.c index 9585e5b5a7..c96f1680b2 100644 --- a/test/battle/hold_effect/special_defense_up.c +++ b/test/battle/hold_effect/special_defense_up.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_APICOT_BERRY].holdEffect == HOLD_EFFECT_SP_DEFENSE_UP); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Apicot Berry raises the holder's Sp. Def by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/speed_up.c b/test/battle/hold_effect/speed_up.c index 4a8b28b6d9..a0e727fd44 100644 --- a/test/battle/hold_effect/speed_up.c +++ b/test/battle/hold_effect/speed_up.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_SALAC_BERRY].holdEffect == HOLD_EFFECT_SPEED_UP); ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); } SINGLE_BATTLE_TEST("Salac Berry raises the holder's Speed by one stage when HP drops to 1/4 or below") diff --git a/test/battle/move_effect/absorb.c b/test/battle/move_effect/absorb.c index bd4eada975..6ed1403fee 100644 --- a/test/battle/move_effect/absorb.c +++ b/test/battle/move_effect/absorb.c @@ -125,4 +125,20 @@ SINGLE_BATTLE_TEST("Draining Kiss recovers 75% of the damage dealt") } } +SINGLE_BATTLE_TEST("Absorb does not drain any HP if user flinched") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_FAKE_OUT); MOVE(player, MOVE_ABSORB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + MESSAGE("The opposing Wobbuffet had its energy drained!"); + } + } +} + TO_DO_BATTLE_TEST("Absorb recovers 50% of the damage dealt to a Substitute"); diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index c7aa52d7c5..dee29a58e0 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -203,5 +203,95 @@ DOUBLE_BATTLE_TEST("Ally Switch works if ally used two-turn move like Dig") } } +DOUBLE_BATTLE_TEST("Ally switch swaps sky drop targets if being used by partner") +{ + u8 visibility; + GIVEN { + ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP); + PLAYER(SPECIES_FEAROW) { Speed(100); } + PLAYER(SPECIES_XATU) { Speed(150); } + OPPONENT(SPECIES_ARON) { Speed(25); Ability(ABILITY_STURDY); } + OPPONENT(SPECIES_WYNAUT) { Speed(30); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_SKY_DROP, target: opponentLeft); } + TURN { MOVE(playerRight, MOVE_ALLY_SWITCH); SKIP_TURN(playerLeft); MOVE(opponentRight, MOVE_MUD_SPORT); MOVE(opponentLeft, MOVE_IRON_DEFENSE); } + } SCENE { + MESSAGE("Fearow used Sky Drop!"); + MESSAGE("Fearow took the opposing Aron into the sky!"); + // turn 2 + MESSAGE("Xatu used Ally Switch!"); + MESSAGE("Xatu and Fearow switched places!"); + MESSAGE("Fearow used Sky Drop!"); + HP_BAR(opponentLeft); + MESSAGE("The opposing Wynaut used Mud Sport!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MUD_SPORT, opponentRight); + MESSAGE("The opposing Aron used Iron Defense!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, opponentLeft); + } THEN { + // all battlers should be visible + visibility = gBattleSpritesDataPtr->battlerData[0].invisible; + EXPECT_EQ(visibility, 0); + visibility = gBattleSpritesDataPtr->battlerData[1].invisible; + EXPECT_EQ(visibility, 0); + visibility = gBattleSpritesDataPtr->battlerData[2].invisible; + EXPECT_EQ(visibility, 0); + visibility = gBattleSpritesDataPtr->battlerData[3].invisible; + EXPECT_EQ(visibility, 0); + } +} + +DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is being held in the air") +{ + u8 visibility; + GIVEN { + ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP); + PLAYER(SPECIES_ARON) { Speed(25); Ability(ABILITY_STURDY); } + PLAYER(SPECIES_WYNAUT) { Speed(30); } + OPPONENT(SPECIES_FEAROW) { Speed(100); } + OPPONENT(SPECIES_XATU) { Speed(150); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_SKY_DROP, target: playerLeft); } + TURN { MOVE(opponentRight, MOVE_ALLY_SWITCH); SKIP_TURN(opponentLeft); MOVE(playerRight, MOVE_MUD_SPORT); MOVE(playerLeft, MOVE_IRON_DEFENSE); } + } SCENE { + MESSAGE("The opposing Fearow used Sky Drop!"); + MESSAGE("The opposing Fearow took Aron into the sky!"); + // turn 2 + MESSAGE("The opposing Xatu used Ally Switch!"); + MESSAGE("The opposing Xatu and the opposing Fearow switched places!"); + MESSAGE("The opposing Fearow used Sky Drop!"); + HP_BAR(playerLeft); + MESSAGE("Wynaut used Mud Sport!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MUD_SPORT, playerRight); + MESSAGE("Aron used Iron Defense!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, playerLeft); + } THEN { + // all battlers should be visible + visibility = gBattleSpritesDataPtr->battlerData[0].invisible; + EXPECT_EQ(visibility, 0); + visibility = gBattleSpritesDataPtr->battlerData[1].invisible; + EXPECT_EQ(visibility, 0); + visibility = gBattleSpritesDataPtr->battlerData[2].invisible; + EXPECT_EQ(visibility, 0); + visibility = gBattleSpritesDataPtr->battlerData[3].invisible; + EXPECT_EQ(visibility, 0); + } +} + +DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_ALLY_SWITCH].effect == EFFECT_ALLY_SWITCH); + PLAYER(SPECIES_HOOPA); + PLAYER(SPECIES_ZOROARK); + PLAYER(SPECIES_MAMOSWINE); // the third member here is required for zoroark + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_ALLY_SWITCH); } + } THEN { + 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/move_effect/belch.c b/test/battle/move_effect/belch.c index 2a732e0e45..f8e28929f9 100644 --- a/test/battle/move_effect/belch.c +++ b/test/battle/move_effect/belch.c @@ -21,7 +21,7 @@ AI_SINGLE_BATTLE_TEST("AI: Belch has nonzero score after eating a berry") TURN { MOVE(player, MOVE_MUD_SHOT); EXPECT_MOVE(opponent, MOVE_TACKLE); } TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_BELCH);} } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, opponent); } } @@ -53,6 +53,64 @@ SINGLE_BATTLE_TEST("Belch cannot be used if the user has not eaten a berry") } } -TO_DO_BATTLE_TEST("Belch can still be used after switching out"); -TO_DO_BATTLE_TEST("Belch can still be used after fainting"); -TO_DO_BATTLE_TEST("Belch can still be used after restoring the consumed berry"); +SINGLE_BATTLE_TEST("Belch can still be used after switching out") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } + PLAYER(SPECIES_SKWOVET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + TURN { SWITCH(player, 1); } + TURN { SWITCH(player, 0); } + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + SWITCH_OUT_MESSAGE("Greedent"); + SWITCH_OUT_MESSAGE("Skwovet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player); + } +} + +SINGLE_BATTLE_TEST("Belch can still be used after fainting") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(gMovesInfo[MOVE_FISSURE].effect == EFFECT_OHKO); + ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING); + PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } + PLAYER(SPECIES_SKWOVET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); MOVE(opponent, MOVE_FISSURE); SEND_OUT(player, 1); } + TURN { MOVE(player, MOVE_REVIVAL_BLESSING, partyIndex: 0); } + TURN { SWITCH(player, 0); } + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FISSURE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REVIVAL_BLESSING, player); + SWITCH_OUT_MESSAGE("Skwovet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player); + } +} + +SINGLE_BATTLE_TEST("Belch can still be used after restoring the consumed berry") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } + PLAYER(SPECIES_SKWOVET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STUFF_CHEEKS); } + TURN { MOVE(player, MOVE_RECYCLE); } + TURN { MOVE(player, MOVE_BELCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STUFF_CHEEKS, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RECYCLE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BELCH, player); + } +} diff --git a/test/battle/move_effect/change_type_on_item.c b/test/battle/move_effect/change_type_on_item.c index 6365215a42..2824438634 100644 --- a/test/battle/move_effect/change_type_on_item.c +++ b/test/battle/move_effect/change_type_on_item.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_TECHNO_BLAST].effect == EFFECT_CHANGE_TYPE_ON_ITEM); - ASSUME(gMovesInfo[MOVE_TECHNO_BLAST].argument == HOLD_EFFECT_DRIVE); + ASSUME(gMovesInfo[MOVE_TECHNO_BLAST].argument.holdEffect == HOLD_EFFECT_DRIVE); } SINGLE_BATTLE_TEST("Techno Blast changes type depending on the drive the user holds") diff --git a/test/battle/move_effect/charge.c b/test/battle/move_effect/charge.c index f95a137993..b057fa4753 100644 --- a/test/battle/move_effect/charge.c +++ b/test/battle/move_effect/charge.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_THUNDERBOLT)); ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); } @@ -115,7 +115,7 @@ SINGLE_BATTLE_TEST("Charge's effect is removed regardless if the next move is El GIVEN { ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_TACKLE].power != 0); + ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/fail_if_not_arg_type.c b/test/battle/move_effect/fail_if_not_arg_type.c index 9e8d005d8b..4ded2d3a7f 100644 --- a/test/battle/move_effect/fail_if_not_arg_type.c +++ b/test/battle/move_effect/fail_if_not_arg_type.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type") { GIVEN { ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); PLAYER(SPECIES_CYNDAQUIL); @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Burn Up fails if the user isn't a Fire-type") { GIVEN { ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type if enemy faints") { GIVEN { ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); PLAYER(SPECIES_CYNDAQUIL); @@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type") { GIVEN { ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); PLAYER(SPECIES_PIKACHU); @@ -80,7 +80,7 @@ SINGLE_BATTLE_TEST("Double Shock fails if the user isn't an Electric-type") { GIVEN { ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -97,7 +97,7 @@ SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type if enemy faints") { GIVEN { ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); PLAYER(SPECIES_PIKACHU); diff --git a/test/battle/move_effect/fixed_damage_arg.c b/test/battle/move_effect/fixed_damage_arg.c index 484601be05..1dae74e3f5 100644 --- a/test/battle/move_effect/fixed_damage_arg.c +++ b/test/battle/move_effect/fixed_damage_arg.c @@ -11,9 +11,9 @@ SINGLE_BATTLE_TEST("Sonic Boom deals fixed damage", s16 damage) u16 mon; PARAMETRIZE { mon = SPECIES_RATTATA; } PARAMETRIZE { mon = SPECIES_ARON; } - + GIVEN { - ASSUME(gMovesInfo[MOVE_SONIC_BOOM].argument == 20); + ASSUME(gMovesInfo[MOVE_SONIC_BOOM].argument.fixedDamage == 20); PLAYER(SPECIES_WOBBUFFET); OPPONENT(mon); } WHEN { diff --git a/test/battle/move_effect/heal_pulse.c b/test/battle/move_effect/heal_pulse.c index e252039982..95a2d75195 100644 --- a/test/battle/move_effect/heal_pulse.c +++ b/test/battle/move_effect/heal_pulse.c @@ -86,7 +86,7 @@ SINGLE_BATTLE_TEST("Heal Pulse is blocked by Substitute") SINGLE_BATTLE_TEST("Floral Healing heals the target by 2/3rd of it's maxHP if Grassy Terrain is on the field") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLORAL_HEALING].argument == MOVE_EFFECT_FLORAL_HEALING); + ASSUME(gMovesInfo[MOVE_FLORAL_HEALING].argument.moveProperty == MOVE_EFFECT_FLORAL_HEALING); ASSUME(gMovesInfo[MOVE_GRASSY_TERRAIN].effect == EFFECT_GRASSY_TERRAIN); PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(1); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/powder.c b/test/battle/move_effect/powder.c index 85e486918b..7701f4d3a2 100644 --- a/test/battle/move_effect/powder.c +++ b/test/battle/move_effect/powder.c @@ -165,7 +165,7 @@ DOUBLE_BATTLE_TEST("Powder still blocks the target's Fire type moves even if it { GIVEN { ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].effect == EFFECT_THIRD_TYPE); - ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].argument == TYPE_GRASS); + ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].argument.type == TYPE_GRASS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TREVENANT); diff --git a/test/battle/move_effect/pursuit.c b/test/battle/move_effect/pursuit.c index 5dfa3f8e33..a20b1ed1d1 100644 --- a/test/battle/move_effect/pursuit.c +++ b/test/battle/move_effect/pursuit.c @@ -610,4 +610,67 @@ SINGLE_BATTLE_TEST("Pursuit attacks a switching foe and switchin is correctly st } } +SINGLE_BATTLE_TEST("Pursuit doesn't cause mon with Emergency Exit to switch twice") +{ + GIVEN { + PLAYER(SPECIES_GOLISOPOD) { HP(101); MaxHP(200); Ability(ABILITY_EMERGENCY_EXIT); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_VOLTORB); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_PURSUIT); SEND_OUT(player, 2); } + } SCENE { + SWITCH_OUT_MESSAGE("Golisopod"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PURSUIT, opponent); + ABILITY_POPUP(player, ABILITY_EMERGENCY_EXIT); + SEND_IN_MESSAGE("Voltorb"); + } THEN { + EXPECT_EQ(player->species, SPECIES_VOLTORB); + } +} + +SINGLE_BATTLE_TEST("Pursuit user gets forced out by Red Card and target still switches out") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_RED_CARD].holdEffect == HOLD_EFFECT_RED_CARD); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + PLAYER(SPECIES_VOLTORB); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VOLTORB); + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_PURSUIT); } + } SCENE { + SWITCH_OUT_MESSAGE("Wobbuffet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PURSUIT, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("The opposing Voltorb was dragged out!"); + SEND_IN_MESSAGE("Voltorb"); + } THEN { + EXPECT_EQ(player->species, SPECIES_VOLTORB); + EXPECT_EQ(opponent->species, SPECIES_VOLTORB); + } +} + +SINGLE_BATTLE_TEST("Pursuit user faints to Life Orb and target still switches out") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_VOLTORB); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); HP(1); } + OPPONENT(SPECIES_VOLTORB); + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_PURSUIT); SEND_OUT(opponent, 1); } + } SCENE { + SWITCH_OUT_MESSAGE("Wobbuffet"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PURSUIT, opponent); + HP_BAR(opponent); + MESSAGE("The opposing Wobbuffet fainted!"); + SEND_IN_MESSAGE("Voltorb"); + } THEN { + EXPECT_EQ(player->species, SPECIES_VOLTORB); + EXPECT_EQ(opponent->species, SPECIES_VOLTORB); + } +} + TO_DO_BATTLE_TEST("Baton Pass doesn't cause Pursuit to increase its power or priority"); diff --git a/test/battle/move_effect/revelation_dance.c b/test/battle/move_effect/revelation_dance.c index 9ab5d4a8e2..0549abb7b7 100644 --- a/test/battle/move_effect/revelation_dance.c +++ b/test/battle/move_effect/revelation_dance.c @@ -5,9 +5,9 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].effect == EFFECT_REVELATION_DANCE); ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].danceMove == TRUE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE)); + ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE)); ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].effect == EFFECT_THIRD_TYPE); - ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].argument == TYPE_GRASS); + ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].argument.type == TYPE_GRASS); ASSUME(gMovesInfo[MOVE_ROOST].effect == EFFECT_ROOST); } diff --git a/test/battle/move_effect/salt_cure.c b/test/battle/move_effect/salt_cure.c index 495a7e8c80..afe811da50 100644 --- a/test/battle/move_effect/salt_cure.c +++ b/test/battle/move_effect/salt_cure.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SALT_CURE].effect == EFFECT_SALT_CURE); + ASSUME(MoveHasAdditionalEffect(MOVE_SALT_CURE, MOVE_EFFECT_SALT_CURE) == TRUE); } SINGLE_BATTLE_TEST("Salt Cure inflicts 1/8 of the target's maximum HP as damage per turn") diff --git a/test/battle/move_effect/semi_invulnerable.c b/test/battle/move_effect/semi_invulnerable.c index d3869bfe54..d5bf909488 100644 --- a/test/battle/move_effect/semi_invulnerable.c +++ b/test/battle/move_effect/semi_invulnerable.c @@ -4,17 +4,17 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_FLY].argument)) == STATUS3_ON_AIR); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_FLY].argument.twoTurnAttack.status) == STATUS3_ON_AIR); ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_DIG].argument)) == STATUS3_UNDERGROUND); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_DIG].argument.twoTurnAttack.status) == STATUS3_UNDERGROUND); ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_BOUNCE].argument)) == STATUS3_ON_AIR); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_BOUNCE].argument.twoTurnAttack.status) == STATUS3_ON_AIR); ASSUME(gMovesInfo[MOVE_DIVE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_DIVE].argument)) == STATUS3_UNDERWATER); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_DIVE].argument.twoTurnAttack.status) == STATUS3_UNDERWATER); ASSUME(gMovesInfo[MOVE_PHANTOM_FORCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_PHANTOM_FORCE].argument)) == STATUS3_PHANTOM_FORCE); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_PHANTOM_FORCE].argument.twoTurnAttack.status) == STATUS3_PHANTOM_FORCE); ASSUME(gMovesInfo[MOVE_SHADOW_FORCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_SHADOW_FORCE].argument)) == STATUS3_PHANTOM_FORCE); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_SHADOW_FORCE].argument.twoTurnAttack.status) == STATUS3_PHANTOM_FORCE); } SINGLE_BATTLE_TEST("Semi-invulnerable moves make the user semi-invulnerable turn 1, then strike turn 2") diff --git a/test/battle/move_effect/shed_tail.c b/test/battle/move_effect/shed_tail.c index 796defb455..1cdf74b0fd 100644 --- a/test/battle/move_effect/shed_tail.c +++ b/test/battle/move_effect/shed_tail.c @@ -87,16 +87,41 @@ SINGLE_BATTLE_TEST("Shed Tail's HP cost doesn't trigger effects that trigger on } // Passes for some reason even though it seems there is some code missing -// AI_SINGLE_BATTLE_TEST("AI will use Shed Tail to pivot to another mon while in damage stalemate with player") -// { -// KNOWN_FAILING; // missing AI code -// GIVEN { -// AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); -// PLAYER(SPECIES_WOBBUFFET) { Speed(100); Ability(ABILITY_RUN_AWAY); Moves(MOVE_TACKLE, MOVE_CELEBRATE); } -// OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Ability(ABILITY_RUN_AWAY); Moves(MOVE_CONFUSION, MOVE_SHED_TAIL); } -// OPPONENT(SPECIES_SCIZOR) { Speed(101); Moves(MOVE_CELEBRATE, MOVE_X_SCISSOR); } -// } WHEN { -// TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_CONFUSION); } -// TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_SHED_TAIL); } -// } -// } +/* +AI_SINGLE_BATTLE_TEST("AI will use Shed Tail to pivot to another mon while in damage stalemate with player") +{ + KNOWN_FAILING; // missing AI code + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET) { Speed(100); Ability(ABILITY_RUN_AWAY); Moves(MOVE_TACKLE, MOVE_CELEBRATE); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(50); Ability(ABILITY_RUN_AWAY); Moves(MOVE_CONFUSION, MOVE_SHED_TAIL); } + OPPONENT(SPECIES_SCIZOR) { Speed(101); Moves(MOVE_CELEBRATE, MOVE_X_SCISSOR); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_CONFUSION); } + TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, MOVE_SHED_TAIL); } + } +} +*/ + +SINGLE_BATTLE_TEST("Shed Tail creates a Substitute with 1/4 of user maximum health") +{ + u32 hp; + PARAMETRIZE { hp = 160; } + PARAMETRIZE { hp = 164; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); + PLAYER(SPECIES_BULBASAUR) { MaxHP(hp); } + PLAYER(SPECIES_BULBASAUR); + OPPONENT(SPECIES_CHARMANDER); + } WHEN { + TURN { MOVE(player, MOVE_SHED_TAIL); MOVE(opponent, MOVE_DRAGON_RAGE); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHED_TAIL, player); + if (hp == 160) + MESSAGE("Bulbasaur's substitute faded!"); + else + NOT MESSAGE("Bulbasaur's substitute faded!"); + } +} diff --git a/test/battle/move_effect/smelling_salts.c b/test/battle/move_effect/smelling_salts.c index bb3f333a42..8d97ab8f09 100644 --- a/test/battle/move_effect/smelling_salts.c +++ b/test/battle/move_effect/smelling_salts.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_SMELLING_SALTS, MOVE_EFFECT_REMOVE_STATUS) == TRUE); - ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument == STATUS1_PARALYSIS); + ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument.status == STATUS1_PARALYSIS); } SINGLE_BATTLE_TEST("Smelling Salts does not cure paralyzed pokemons behind substitutes or get increased power") diff --git a/test/battle/move_effect/solar_beam.c b/test/battle/move_effect/solar_beam.c new file mode 100644 index 0000000000..6fca334dee --- /dev/null +++ b/test/battle/move_effect/solar_beam.c @@ -0,0 +1,34 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); + ASSUME(gMovesInfo[MOVE_SOLAR_BLADE].argument.twoTurnAttack.status == B_WEATHER_SUN); +} + +SINGLE_BATTLE_TEST("Solar Beam does not need a charging turn if Sun is up") +{ + u32 ability; + + PARAMETRIZE { ability = ABILITY_DROUGHT; } + PARAMETRIZE { ability = ABILITY_WHITE_SMOKE; } + + GIVEN { + PLAYER(SPECIES_TORKOAL) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SOLAR_BEAM); } + if (ability == ABILITY_WHITE_SMOKE) { + TURN { SKIP_TURN(player); } + } + } SCENE { + if (ability == ABILITY_WHITE_SMOKE) { + MESSAGE("Torkoal used Solar Beam!"); + MESSAGE("Torkoal absorbed light!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } + MESSAGE("Torkoal used Solar Beam!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SOLAR_BEAM, player); + } +} diff --git a/test/battle/move_effect/sparkling_aria.c b/test/battle/move_effect/sparkling_aria.c index 332cf8165c..24ac3c84bb 100644 --- a/test/battle/move_effect/sparkling_aria.c +++ b/test/battle/move_effect/sparkling_aria.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_SPARKLING_ARIA, MOVE_EFFECT_REMOVE_STATUS) == TRUE); - ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].argument == STATUS1_BURN); + ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].argument.status == STATUS1_BURN); ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].soundMove == TRUE); } diff --git a/test/battle/move_effect/sticky_web.c b/test/battle/move_effect/sticky_web.c index f1fff0fd1e..e99368aa7d 100644 --- a/test/battle/move_effect/sticky_web.c +++ b/test/battle/move_effect/sticky_web.c @@ -271,3 +271,31 @@ SINGLE_BATTLE_TEST("Sticky Web is placed on the correct side after Memento") MESSAGE("A sticky web has been laid out on the ground around your team!"); } } + +DOUBLE_BATTLE_TEST("Sticky Web setter has their speed lowered with Mirror Armor even after Ally Switch") +{ + GIVEN { + PLAYER(SPECIES_SQUIRTLE); + PLAYER(SPECIES_CHARMANDER); + PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web. + OPPONENT(SPECIES_CATERPIE); + OPPONENT(SPECIES_NATU); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); } + TURN { MOVE(opponentRight, MOVE_ALLY_SWITCH); } + TURN { SWITCH(playerRight, 2); } + } SCENE { + // Turn 1 - set up sticky web + ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft); + MESSAGE("A sticky web has been laid out on the ground around your team!"); + // Turn 2 - ally switch + MESSAGE("The opposing Natu used Ally Switch!"); + // turn 3 - send our corviknight + SEND_IN_MESSAGE("Corviknight"); + MESSAGE("Corviknight was caught in a sticky web!"); + ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR); + // sticky web setter - caterpie (now opponentRight) gets speed lowered + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + MESSAGE("The opposing Caterpie's Speed fell!"); + } +} diff --git a/test/battle/move_effect/tidy_up.c b/test/battle/move_effect/tidy_up.c index 986e9a2ba3..fcb78ba962 100644 --- a/test/battle/move_effect/tidy_up.c +++ b/test/battle/move_effect/tidy_up.c @@ -99,3 +99,24 @@ AI_SINGLE_BATTLE_TEST("AI will try to remove hazards if slower then target even TURN { EXPECT_MOVE(opponent, MOVE_TIDY_UP); } } } + +SINGLE_BATTLE_TEST("Tidy Up raises Attack and Speed by one after clearing hazards on opposing field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STEALTH_ROCK); } + TURN { MOVE(player, MOVE_TIDY_UP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TIDY_UP, player); + MESSAGE("Tidying up complete!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Attack rose!"); + MESSAGE("Wobbuffet's Speed rose!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + } +} diff --git a/test/battle/move_effect/two_turns_attack.c b/test/battle/move_effect/two_turns_attack.c index efeb419ce5..8010d14356 100644 --- a/test/battle/move_effect/two_turns_attack.c +++ b/test/battle/move_effect/two_turns_attack.c @@ -8,14 +8,8 @@ ASSUMPTIONS ASSUME(MoveHasAdditionalEffectSelf(MOVE_SKULL_BASH, MOVE_EFFECT_DEF_PLUS_1) == TRUE); ASSUME(gMovesInfo[MOVE_SKY_ATTACK].effect == EFFECT_TWO_TURNS_ATTACK); - // Solar Beam - check for sun - ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); - ASSUME(HIHALF(gMovesInfo[MOVE_SOLAR_BLADE].argument) == B_WEATHER_SUN); - ASSUME(gMovesInfo[MOVE_SOLAR_BLADE].effect == EFFECT_SOLAR_BEAM); - ASSUME(HIHALF(gMovesInfo[MOVE_SOLAR_BLADE].argument) == B_WEATHER_SUN); - // Electro shot - check for rain - ASSUME(HIHALF(gMovesInfo[MOVE_ELECTRO_SHOT].argument) == B_WEATHER_RAIN); + ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].argument.twoTurnAttack.status == B_WEATHER_RAIN); ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].effect == EFFECT_TWO_TURNS_ATTACK); ASSUME(MoveHasAdditionalEffectSelf(MOVE_ELECTRO_SHOT, MOVE_EFFECT_SP_ATK_PLUS_1) == TRUE); } diff --git a/test/battle/move_effect/wake_up_slap.c b/test/battle/move_effect/wake_up_slap.c index 0a881be100..e4d7c2e616 100644 --- a/test/battle/move_effect/wake_up_slap.c +++ b/test/battle/move_effect/wake_up_slap.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_WAKE_UP_SLAP, MOVE_EFFECT_REMOVE_STATUS) == TRUE); - ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument == STATUS1_SLEEP); + ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument.status == STATUS1_SLEEP); } SINGLE_BATTLE_TEST("Wake-Up Slap does not cure paralyzed pokemons behind substitutes or get increased power") diff --git a/test/battle/move_effect_secondary/double_power_on_arg_status.c b/test/battle/move_effect_secondary/double_power_on_arg_status.c index d147264470..1d3563c427 100644 --- a/test/battle/move_effect_secondary/double_power_on_arg_status.c +++ b/test/battle/move_effect_secondary/double_power_on_arg_status.c @@ -13,7 +13,7 @@ SINGLE_BATTLE_TEST("Hex deals double damage to foes with a status", s16 damage) PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } GIVEN { ASSUME(gMovesInfo[MOVE_HEX].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_HEX].argument == STATUS1_ANY); + ASSUME(gMovesInfo[MOVE_HEX].argument.status == STATUS1_ANY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } } WHEN { @@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Venoshock's power doubles if the target is poisoned/badly po PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } GIVEN { ASSUME(gMovesInfo[MOVE_VENOSHOCK].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_VENOSHOCK].argument == STATUS1_PSN_ANY); + ASSUME(gMovesInfo[MOVE_VENOSHOCK].argument.status == STATUS1_PSN_ANY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } } WHEN { diff --git a/test/battle/move_effect_secondary/haze.c b/test/battle/move_effect_secondary/haze.c new file mode 100644 index 0000000000..c3831f0768 --- /dev/null +++ b/test/battle/move_effect_secondary/haze.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_FREEZY_FROST, MOVE_EFFECT_HAZE) == TRUE); +} + +SINGLE_BATTLE_TEST("Freeze Frost restores stat changes when it was succesful") +{ + bool32 moveSuccess; + PARAMETRIZE { moveSuccess = FALSE; } + PARAMETRIZE { moveSuccess = TRUE; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FREEZY_FROST, hit: moveSuccess); } + } SCENE { + if (moveSuccess == TRUE) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FREEZY_FROST, player); + MESSAGE("All stat changes were eliminated!"); + } else { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FREEZY_FROST, player); + MESSAGE("All stat changes were eliminated!"); + } + } + } +} diff --git a/test/battle/move_effect/plasma_fists.c b/test/battle/move_effect_secondary/ion_deluge.c similarity index 80% rename from test/battle/move_effect/plasma_fists.c rename to test/battle/move_effect_secondary/ion_deluge.c index 93c8869026..efc66903bc 100644 --- a/test/battle/move_effect/plasma_fists.c +++ b/test/battle/move_effect_secondary/ion_deluge.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_PLASMA_FISTS].effect == EFFECT_PLASMA_FISTS); + ASSUME(MoveHasAdditionalEffect(MOVE_PLASMA_FISTS, MOVE_EFFECT_ION_DELUGE) == TRUE); } SINGLE_BATTLE_TEST("Ion Duldge turns normal moves into electric for the remainder of the current turn") @@ -47,6 +47,26 @@ SINGLE_BATTLE_TEST("Plasma Fists turns normal moves into electric for the remain } } +SINGLE_BATTLE_TEST("Plasma Fists does not set up Ion Deluge if it does not connect") +{ + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_PHANPY].types[0] == TYPE_GROUND || gSpeciesInfo[SPECIES_PHANPY].types[1] == TYPE_GROUND); + PLAYER(SPECIES_KRABBY); + OPPONENT(SPECIES_PHANPY); + } WHEN { + TURN { MOVE(player, MOVE_PLASMA_FISTS); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + MESSAGE("Krabby used Plasma Fists!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLASMA_FISTS, player); + MESSAGE("A deluge of ions showers the battlefield!"); + } + MESSAGE("The opposing Phanpy used Tackle!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + NOT MESSAGE("It's super effective!"); + } +} + SINGLE_BATTLE_TEST("Plasma Fists type-changing effect does not override Pixilate") { GIVEN { diff --git a/test/battle/move_effect_secondary/leech_seed.c b/test/battle/move_effect_secondary/leech_seed.c new file mode 100644 index 0000000000..c5a8db57cc --- /dev/null +++ b/test/battle/move_effect_secondary/leech_seed.c @@ -0,0 +1,37 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_SAPPY_SEED, MOVE_EFFECT_LEECH_SEED) == TRUE); +} + +SINGLE_BATTLE_TEST("Sappy Seed can seed the target") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SAPPY_SEED); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SAPPY_SEED, player); + MESSAGE("The opposing Wobbuffet was seeded!"); + MESSAGE("The opposing Wobbuffet's health is sapped by Leech Seed!"); + } +} + +SINGLE_BATTLE_TEST("Sappy Seed is not going to seed the target if it fails") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SAPPY_SEED, hit: FALSE); } + } SCENE { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SAPPY_SEED, player); + MESSAGE("The opposing Wobbuffet was seeded!"); + MESSAGE("The opposing Wobbuffet's health is sapped by Leech Seed!"); + } + } +} diff --git a/test/battle/move_effect_secondary/light_screen.c b/test/battle/move_effect_secondary/light_screen.c new file mode 100644 index 0000000000..244e469893 --- /dev/null +++ b/test/battle/move_effect_secondary/light_screen.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_GLITZY_GLOW, MOVE_EFFECT_LIGHT_SCREEN) == TRUE); +} + +SINGLE_BATTLE_TEST("Glitzy Glow sets up Light Screen when it was succesful") +{ + bool32 moveSuccess; + PARAMETRIZE { moveSuccess = FALSE; } + PARAMETRIZE { moveSuccess = TRUE; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GLITZY_GLOW, hit: moveSuccess); } + } SCENE { + if (moveSuccess == TRUE) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLITZY_GLOW, player); + MESSAGE("Light Screen made your team stronger against special moves!"); + } else { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_GLITZY_GLOW, player); + MESSAGE("Light Screen made your team stronger against special moves!"); + } + } + } +} diff --git a/test/battle/move_effect_secondary/reflect.c b/test/battle/move_effect_secondary/reflect.c new file mode 100644 index 0000000000..6a0dda06d8 --- /dev/null +++ b/test/battle/move_effect_secondary/reflect.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_BADDY_BAD, MOVE_EFFECT_REFLECT) == TRUE); +} + +SINGLE_BATTLE_TEST("Baddy Bad sets up Reflect when it was succesful") +{ + bool32 moveSuccess; + PARAMETRIZE { moveSuccess = FALSE; } + PARAMETRIZE { moveSuccess = TRUE; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BADDY_BAD, hit: moveSuccess); } + } SCENE { + if (moveSuccess == TRUE) + { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BADDY_BAD, player); + MESSAGE("Reflect made your team stronger against physical moves!"); + } else { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BADDY_BAD, player); + MESSAGE("Reflect made your team stronger against physical moves!"); + } + } + } +} diff --git a/test/battle/move_effect_secondary/steal_item.c b/test/battle/move_effect_secondary/steal_item.c new file mode 100644 index 0000000000..8a4ae931d2 --- /dev/null +++ b/test/battle/move_effect_secondary/steal_item.c @@ -0,0 +1,129 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE); + ASSUME(MoveHasAdditionalEffect(MOVE_COVET, MOVE_EFFECT_STEAL_ITEM) == TRUE); +} + +SINGLE_BATTLE_TEST("Thief and Covet steal target's held item") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); + } THEN { + EXPECT_EQ(player->item, ITEM_HYPER_POTION); + EXPECT_EQ(opponent->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Thief and Covet steal player's held item if opponent is a trainer") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + GIVEN { + ASSUME(B_TRAINERS_KNOCK_OFF_ITEMS == TRUE); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, player); + } THEN { + EXPECT_EQ(opponent->item, ITEM_HYPER_POTION); + EXPECT_EQ(player->item, ITEM_NONE); + } +} + +WILD_BATTLE_TEST("Thief and Covet don't steal player's held item if opponent is a wild mon") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + GIVEN { + ASSUME(B_TRAINERS_KNOCK_OFF_ITEMS == TRUE); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + HP_BAR(player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, player); + } THEN { + EXPECT_EQ(player->item, ITEM_HYPER_POTION); + EXPECT_EQ(opponent->item, ITEM_NONE); + } +} + +SINGLE_BATTLE_TEST("Thief and Covet don't steal target's held item if user is holding an item") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POTION); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); + } THEN { + EXPECT_EQ(player->item, ITEM_POTION); + EXPECT_EQ(opponent->item, ITEM_HYPER_POTION); + } +} + +SINGLE_BATTLE_TEST("Thief and Covet don't steal target's held item if target has no item") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); + } +} + +// Test can't currently verify if the item is sent to Bag +WILD_BATTLE_TEST("Thief and Covet steal target's held item and it's added to Bag in wild battles (Gen 9)") +{ + u32 move; + PARAMETRIZE { move = MOVE_THIEF; } + PARAMETRIZE { move = MOVE_COVET; } + GIVEN { + ASSUME(B_STEAL_WILD_ITEMS >= GEN_9); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_HYPER_POTION); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_STEAL, opponent); + } THEN { + EXPECT_EQ(player->item, ITEM_NONE); + EXPECT_EQ(opponent->item, ITEM_NONE); + } +} diff --git a/test/battle/move_effects_combined/barb_barrage.c b/test/battle/move_effects_combined/barb_barrage.c index e2e5059fee..cedb671b86 100644 --- a/test/battle/move_effects_combined/barb_barrage.c +++ b/test/battle/move_effects_combined/barb_barrage.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].argument == STATUS1_PSN_ANY); + ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].argument.status == STATUS1_PSN_ANY); ASSUME(MoveHasAdditionalEffect(MOVE_BARB_BARRAGE, MOVE_EFFECT_POISON) == TRUE); } diff --git a/test/battle/move_effects_combined/hurricane.c b/test/battle/move_effects_combined/hurricane.c index 61acac6649..6e9228ddaf 100644 --- a/test/battle/move_effects_combined/hurricane.c +++ b/test/battle/move_effects_combined/hurricane.c @@ -40,9 +40,9 @@ SINGLE_BATTLE_TEST("Hurricane can hit airborne targets (Fly, Bounce)") PARAMETRIZE { move = MOVE_BOUNCE; } GIVEN { ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_FLY].argument)) == STATUS3_ON_AIR); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_FLY].argument.twoTurnAttack.status) == STATUS3_ON_AIR); ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_BOUNCE].argument)) == STATUS3_ON_AIR); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_BOUNCE].argument.twoTurnAttack.status) == STATUS3_ON_AIR); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(move); } } WHEN { @@ -58,7 +58,7 @@ DOUBLE_BATTLE_TEST("Hurricane can hit airborne targets (Sky Drop)") { GIVEN { ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP); - ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_SKY_DROP].argument)) == STATUS3_ON_AIR); + ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_SKY_DROP].argument.twoTurnAttack.status) == STATUS3_ON_AIR); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effects_combined/infernal_parade.c b/test/battle/move_effects_combined/infernal_parade.c index 6aa46ef8cb..890f8f9dc5 100644 --- a/test/battle/move_effects_combined/infernal_parade.c +++ b/test/battle/move_effects_combined/infernal_parade.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].argument == STATUS1_ANY); + ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].argument.status == STATUS1_ANY); ASSUME(MoveHasAdditionalEffect(MOVE_INFERNAL_PARADE, MOVE_EFFECT_BURN) == TRUE); } diff --git a/test/battle/sleep_clause.c b/test/battle/sleep_clause.c index c8393685b8..f0f8f2906d 100644 --- a/test/battle/sleep_clause.c +++ b/test/battle/sleep_clause.c @@ -215,7 +215,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Psycho Shift'ing sleep will fail if sleep clau STATUS_ICON(opponent, sleep: TRUE); } MESSAGE("Sleep Clause kept the opposing Wobbuffet awake!"); - } + } } SINGLE_BATTLE_TEST("Sleep Clause: Psycho Shift'ing sleep will activate sleep clause") @@ -245,7 +245,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Psycho Shift'ing sleep will activate sleep cla STATUS_ICON(opponent, sleep: TRUE); } MESSAGE("Sleep Clause kept Zigzagoon awake!"); - } + } } AI_SINGLE_BATTLE_TEST("Sleep Clause: AI will not use Yawn while sleep clause is active") @@ -507,7 +507,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: G-Max Befuddle can only sleep one opposing mon { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_G_MAX_BEFUDDLE].argument == MAX_EFFECT_EFFECT_SPORE_FOES); + ASSUME(gMovesInfo[MOVE_G_MAX_BEFUDDLE].argument.maxEffect == MAX_EFFECT_EFFECT_SPORE_FOES); PLAYER(SPECIES_BUTTERFREE) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_CATERPIE); OPPONENT(SPECIES_WOBBUFFET); @@ -682,7 +682,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo STATUS_ICON(opponentLeft, sleep: TRUE); MESSAGE("Zigzagoon used Uproar!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_UPROAR, playerRight); - MESSAGE("Zigzagoon caused an uproar!"); + MESSAGE("Zigzagoon caused an uproar!"); MESSAGE("The uproar woke the opposing Zigzagoon!"); STATUS_ICON(opponentLeft, sleep: FALSE); MESSAGE("The opposing Zigzagoon used Roar!"); @@ -1131,7 +1131,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_G_MAX_SWEETNESS].argument == MAX_EFFECT_AROMATHERAPY); + ASSUME(gMovesInfo[MOVE_G_MAX_SWEETNESS].argument.maxEffect == MAX_EFFECT_AROMATHERAPY); ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); PLAYER(SPECIES_APPLETUN) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_WOBBUFFET); @@ -1467,7 +1467,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Yawn'd Pokémon who's partner is slept before ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponentLeft); MESSAGE("The opposing Zigzagoon fell asleep!"); STATUS_ICON(opponentLeft, sleep: TRUE); - NONE_OF { + NONE_OF { MESSAGE( "The opposing Zigzagoon fell asleep!"); STATUS_ICON(opponentRight, sleep: TRUE); } @@ -1638,13 +1638,13 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep Clause does not prevent sleeping your pa FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); - PLAYER(SPECIES_ZIGZAGOON); + PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); - OPPONENT(SPECIES_ZIGZAGOON); + OPPONENT(SPECIES_ZIGZAGOON); } WHEN { TURN { MOVE(playerLeft, MOVE_SPORE, target: playerRight); } TURN { SWITCH(playerRight, 2); MOVE(playerLeft, MOVE_SPORE, target: playerRight); } @@ -1681,13 +1681,13 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep Clause does not prevent sleeping your pa FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); PLAYER(SPECIES_ZIGZAGOON); - PLAYER(SPECIES_ZIGZAGOON); + PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); - OPPONENT(SPECIES_ZIGZAGOON); + OPPONENT(SPECIES_ZIGZAGOON); } WHEN { TURN { MOVE(playerLeft, MOVE_YAWN, target: playerRight); } TURN {} diff --git a/test/pokemon.c b/test/pokemon.c index f5431559ee..00b08ebb79 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -210,6 +210,50 @@ TEST("givemon [simple]") EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); } +TEST("givemon respects perfectIVCount") +{ + ZeroPlayerPartyMons(); + u32 perfectIVs[6] = {0}; + + ASSUME(gSpeciesInfo[SPECIES_MEW].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_CELEBI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_JIRACHI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_MANAPHY].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_VICTINI].perfectIVCount == 3); + ASSUME(gSpeciesInfo[SPECIES_DIANCIE].perfectIVCount == 3); + + RUN_OVERWORLD_SCRIPT( + givemon SPECIES_MEW, 100; + givemon SPECIES_CELEBI, 100; + givemon SPECIES_JIRACHI, 100; + givemon SPECIES_MANAPHY, 100; + givemon SPECIES_VICTINI, 100; + givemon SPECIES_DIANCIE, 100; + ); + + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_MEW); + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_SPECIES), SPECIES_CELEBI); + EXPECT_EQ(GetMonData(&gPlayerParty[2], MON_DATA_SPECIES), SPECIES_JIRACHI); + EXPECT_EQ(GetMonData(&gPlayerParty[3], MON_DATA_SPECIES), SPECIES_MANAPHY); + EXPECT_EQ(GetMonData(&gPlayerParty[4], MON_DATA_SPECIES), SPECIES_VICTINI); + EXPECT_EQ(GetMonData(&gPlayerParty[5], MON_DATA_SPECIES), SPECIES_DIANCIE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[1], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[2], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[3], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[4], MON_DATA_LEVEL), 100); + EXPECT_EQ(GetMonData(&gPlayerParty[5], MON_DATA_LEVEL), 100); + for (u32 j = 0; j < 6; j++) + { + for (u32 k = 0; k < NUM_STATS; k++) + { + if (GetMonData(&gPlayerParty[j], MON_DATA_HP_IV + k) == MAX_PER_STAT_IVS) + perfectIVs[j]++; + } + EXPECT_GE(perfectIVs[j], 3); + } +} + TEST("givemon [moves]") { ZeroPlayerPartyMons();