diff --git a/.all-contributorsrc b/.all-contributorsrc index 0ae8f41116..aa76ec1a65 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -459,6 +459,25 @@ "contributions": [ "code" ] + }, + { + "login": "fdeblasio", + "name": "Frank DeBlasio", + "avatar_url": "https://avatars.githubusercontent.com/u/35279583?v=4", + "profile": "https://github.com/fdeblasio", + "contributions": [ + "code" + ] + }, + { + "login": "leo60228", + "name": "leo60228", + "avatar_url": "https://avatars.githubusercontent.com/u/8355305?v=4", + "profile": "https://vriska.dev", + "contributions": [ + "doc", + "data" + ] } ], "contributorsPerLine": 7, diff --git a/.gitignore b/.gitignore index 2db597f092..1ac6e11c9a 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ prefabs.json /pokeemerald-*.png src/data/map_group_count.h include/constants/heal_locations.h +include/constants/script_commands.h tools/trainerproc/trainerproc src/data/battle_partners.h src/data/trainers.h diff --git a/CREDITS.md b/CREDITS.md index 64a31a4077..e9d1e53354 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -76,6 +76,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Marky
Marky

💻 MandL27
MandL27

💻 cawtds
cawtds

💻 + Frank DeBlasio
Frank DeBlasio

💻 + leo60228
leo60228

📖 🔣 diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index e5da506a4d..754a5221f6 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1841,7 +1841,6 @@ .macro setmoveeffect effect:req sethword sMOVE_EFFECT, \effect - sethword sSAVED_MOVE_EFFECT, \effect .endm .macro sethword dst:req, value:req diff --git a/asm/macros/event.inc b/asm/macros/event.inc index bc55661bd6..6e08a3cdff 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -169,7 +169,10 @@ .endm @ Copies the value of source into destination. - .macro copyvar destination:req, source:req + .macro copyvar destination:req, source:req, warn=TRUE + .if \warn && !((\source >= VARS_START && \source <= VARS_END) || (\source >= SPECIAL_VARS_START && \source <= SPECIAL_VARS_END)) + .warning "copyvar with a value that is not a VAR_ constant; did you mean setvar instead?" + .endif .byte SCR_OP_COPYVAR .2byte \destination .2byte \source diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 4df85854dc..b546558daa 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -255,23 +255,23 @@ gBattleAnimMove_Tailwind:: createvisualtask AnimTask_TranslateMonEllipticalRespectSide, 2, ANIM_ATTACKER, 24, 6, 4, 4 createvisualtask AnimTask_TraceMonBlended, 2, 0, 4, 7, 10 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 10, 2304, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 10, 2304, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 90, 2048, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 90, 2048, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 50, 2560, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 50, 2560, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 20, 2304, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 20, 2304, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 70, 1984, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 70, 1984, 96, 1 delay 12 - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 0, 2816, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 0, 2816, 96, 1 delay 10 - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 60, 2560, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 60, 2560, 96, 1 waitforvisualfinish stopsound call UnsetHighSpeedBg @@ -285,23 +285,23 @@ gBattleAnimGeneral_Tailwind:: playsewithpan SE_M_GUST, SOUND_PAN_ATTACKER call SetHighSpeedBg setalpha 12, 8 - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 10, 2304, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 10, 2304, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 90, 2048, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 90, 2048, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 50, 2560, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 50, 2560, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 20, 2304, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 20, 2304, 96, 1 delay 12 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 70, 1984, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 70, 1984, 96, 1 delay 12 - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 0, 2816, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 0, 2816, 96, 1 delay 10 - createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 60, 2560, 96, 0 + createsprite gFlyingSandCrescentSpriteTemplate, ANIM_ATTACKER, 40, 60, 2560, 96, 1 waitforvisualfinish stopsound call UnsetHighSpeedBg @@ -11932,7 +11932,6 @@ gBattleAnimMove_PrismaticLaser:: loadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT @charge animation loadspritegfx ANIM_TAG_TEAL_ALERT @straight lines loadspritegfx ANIM_TAG_GREEN_SPIKE @needle arm animation - loadspritegfx ANIM_TAG_NEEDLE @sting monbg ANIM_ATTACKER setalpha 14, 8 createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 1, 0, 16, RGB_BLACK @@ -11961,6 +11960,7 @@ gBattleAnimMove_PrismaticLaser:: unloadspritegfx ANIM_TAG_GREEN_SPIKE unloadspritegfx ANIM_TAG_ICE_CHUNK unloadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT + loadspritegfx ANIM_TAG_NEEDLE @sting delay 30 createvisualtask AnimTask_HorizontalShake, 5, (MAX_BATTLERS_COUNT + 1), 10, 0x32 createvisualtask AnimTask_HorizontalShake, 5, MAX_BATTLERS_COUNT, 10, 0x32 @@ -15059,6 +15059,7 @@ gBattleAnimMove_Poltergeist:: waitbgfadein clearmonbg 0x3 blendoff + unloadspritegfx ANIM_TAG_ITEM_BAG end @Credits to Skeli @@ -32015,7 +32016,8 @@ gBattleAnimGeneral_Rainbow:: createvisualtask AnimTask_BlendBattleAnimPal, 10, (F_PAL_BG | F_PAL_BATTLERS_2), 1, 6, 0, RGB_WHITE waitforvisualfinish delay 30 - fadetobg BG_RAINBOW + goto SetRainbowBackground +AnimGeneral_RainbowContinue: panse_adjustnone SE_M_ABSORB_2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, +1, 0 delay 90 blendoff @@ -32023,6 +32025,14 @@ gBattleAnimGeneral_Rainbow:: waitbgfadein clearmonbg ANIM_ATK_PARTNER end +SetRainbowBackground: + createvisualtask AnimTask_GetAttackerSide, 2 + jumprettrue SetRainbowBgOppoentSide + fadetobg BG_RAINBOW_PLAYER + goto AnimGeneral_RainbowContinue +SetRainbowBgOppoentSide: + fadetobg BG_RAINBOW_OPPONENT + goto AnimGeneral_RainbowContinue gBattleAnimGeneral_SeaOfFire:: loadspritegfx ANIM_TAG_SMALL_EMBER @@ -32836,7 +32846,6 @@ gBattleAnimMove_SavageSpinOut:: blendoff waitforvisualfinish unloadspritegfx ANIM_TAG_STRING - unloadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT loadspritegfx ANIM_TAG_COCOON loadspritegfx ANIM_TAG_IMPACT @hit delay 1 @@ -33306,7 +33315,6 @@ FinishInfernoOverdrive: delay 16 createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 8, 0, 16, 1 playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET - unloadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 2, 79, 1 call InfernoOverdriveExplosion delay 6 @@ -34486,7 +34494,6 @@ gBattleAnimMove_BlackHoleEclipse:: unloadspritegfx ANIM_TAG_VERTICAL_HEX @red unloadspritegfx ANIM_TAG_SHADOW_BALL unloadspritegfx ANIM_TAG_BLACK_BALL_2 - unloadspritegfx ANIM_TAG_FOCUS_ENERGY loadspritegfx ANIM_TAG_EXPLOSION_2 call BlackHoleEclipseExplosion createvisualtask AnimTask_BlendBattleAnimPal, 10, (F_PAL_BG | F_PAL_BATTLERS_2), 1, 0, 16, RGB_WHITE @ bg to white pal @@ -36718,8 +36725,6 @@ gBattleAnimMove_ClangorousSoulblaze:: playsewithpan SE_SHINY, SOUND_PAN_ATTACKER createsprite gClangorousSoulRedRingTemplate, ANIM_ATTACKER, 3, 0x0, 0x0, 0x0, 0x0 waitforvisualfinish - unloadspritegfx ANIM_TAG_HORSESHOE_SIDE_FIST - unloadspritegfx ANIM_TAG_SPARKLE_2 @stars loadspritegfx ANIM_TAG_ROUND_SHADOW @ fly playsewithpan SE_M_FLY, SOUND_PAN_ATTACKER createsprite gClangoorousSoulblazeWhiteFlySpriteTemplate, ANIM_ATTACKER, 2, 0x0, 0x0, 0xd, 0x150 @@ -37197,8 +37202,6 @@ SearingSunrazeSmashImpact: loadspritegfx ANIM_TAG_CROSS_IMPACT @x delay 0 unloadspritegfx ANIM_TAG_METEOR @superpower - unloadspritegfx ANIM_TAG_DRAGON_ASCENT @dragon ascent 1 - unloadspritegfx ANIM_TAG_DRAGON_ASCENT_FOE @dragon ascent 2 createsprite gSearingSunrazeSmashCrossImpactSpriteTemplate, ANIM_TARGET, 2, 0x0, 0x0, 0x1, 0x24 playsewithpan SE_M_LEER, SOUND_PAN_TARGET visible ANIM_ATTACKER @@ -37760,7 +37763,6 @@ gBattleAnimMove_SoulStealing7StarStrike:: call SoulStealingSevenStarStrikeBlueParalysis waitforvisualfinish visible ANIM_ATTACKER - unloadspritegfx ANIM_TAG_ROUND_SHADOW loadspritegfx ANIM_TAG_SPARKLE_4 @ detect loadspritegfx ANIM_TAG_EXPLOSION @ explosion playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index a353b44ba8..638f81bf7b 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -309,10 +309,10 @@ BattleScript_MoveSwitch: waitmessage B_WAIT_TIME_SHORT BattleScript_MoveSwitchOpenPartyScreen:: openpartyscreen BS_ATTACKER, BattleScript_MoveSwitchEnd - switchoutabilities BS_ATTACKER waitstate - switchhandleorder BS_ATTACKER, 2 returntoball BS_ATTACKER, FALSE + switchoutabilities BS_ATTACKER + switchhandleorder BS_ATTACKER, 2 getswitchedmondata BS_ATTACKER switchindataupdate BS_ATTACKER hpthresholds BS_ATTACKER @@ -4099,10 +4099,10 @@ BattleScript_EffectBatonPass:: attackanimation waitanimation openpartyscreen BS_ATTACKER, BattleScript_ButItFailed - switchoutabilities BS_ATTACKER waitstate - switchhandleorder BS_ATTACKER, 2 returntoball BS_ATTACKER, FALSE + switchoutabilities BS_ATTACKER + switchhandleorder BS_ATTACKER, 2 getswitchedmondata BS_ATTACKER switchindataupdate BS_ATTACKER hpthresholds BS_ATTACKER @@ -5418,11 +5418,11 @@ BattleScript_ActionSwitch:: end2 BattleScript_DoSwitchOut:: - switchoutabilities BS_ATTACKER undodynamax BS_ATTACKER waitstate returnatktoball waitstate + switchoutabilities BS_ATTACKER drawpartystatussummary BS_ATTACKER switchhandleorder BS_ATTACKER, 1 getswitchedmondata BS_ATTACKER @@ -5724,9 +5724,9 @@ BattleScript_RoarSuccessRet: attackanimation waitanimation BattleScript_RoarSuccessRet_Ret: - switchoutabilities BS_TARGET returntoball BS_TARGET, FALSE waitstate + switchoutabilities BS_TARGET return BattleScript_WeaknessPolicy:: @@ -6834,10 +6834,11 @@ BattleScript_PowderMoveNoEffect:: pause B_WAIT_TIME_SHORT jumpiftype BS_TARGET, TYPE_GRASS, BattleScript_PowderMoveNoEffectPrint jumpifability BS_TARGET, ABILITY_OVERCOAT, BattleScript_PowderMoveNoEffectOvercoat + setlastuseditem BS_TARGET printstring STRINGID_SAFETYGOGGLESPROTECTED goto BattleScript_PowderMoveNoEffectWaitMsg BattleScript_PowderMoveNoEffectOvercoat: - call BattleScript_AbilityPopUp + call BattleScript_AbilityPopUpTarget BattleScript_PowderMoveNoEffectPrint: printstring STRINGID_ITDOESNTAFFECT BattleScript_PowderMoveNoEffectWaitMsg: @@ -7218,10 +7219,10 @@ BattleScript_EmergencyExit:: playanimation BS_SCRIPTING, B_ANIM_SLIDE_OFFSCREEN waitanimation openpartyscreen BS_SCRIPTING, BattleScript_EmergencyExitRet - switchoutabilities BS_SCRIPTING waitstate - switchhandleorder BS_SCRIPTING, 2 returntoball BS_SCRIPTING, FALSE + switchoutabilities BS_SCRIPTING + switchhandleorder BS_SCRIPTING, 2 getswitchedmondata BS_SCRIPTING switchindataupdate BS_SCRIPTING hpthresholds BS_SCRIPTING @@ -7251,10 +7252,10 @@ BattleScript_EmergencyExitEnd2:: playanimation BS_ATTACKER, B_ANIM_SLIDE_OFFSCREEN waitanimation openpartyscreen BS_ATTACKER, BattleScript_EmergencyExitRetEnd2 - switchoutabilities BS_ATTACKER waitstate - switchhandleorder BS_ATTACKER, 2 returntoball BS_ATTACKER, FALSE + switchoutabilities BS_ATTACKER + switchhandleorder BS_ATTACKER, 2 getswitchedmondata BS_ATTACKER switchindataupdate BS_ATTACKER hpthresholds BS_ATTACKER @@ -9190,12 +9191,12 @@ BattleScript_EjectButtonActivates:: undodynamax BS_SCRIPTING makeinvisible BS_SCRIPTING openpartyscreen BS_SCRIPTING, BattleScript_EjectButtonEnd + waitstate + returntoball BS_SCRIPTING, FALSE copybyte sSAVED_BATTLER, sBATTLER switchoutabilities BS_SCRIPTING copybyte sBATTLER, sSAVED_BATTLER - waitstate switchhandleorder BS_SCRIPTING, 0x2 - returntoball BS_SCRIPTING, FALSE getswitchedmondata BS_SCRIPTING switchindataupdate BS_SCRIPTING hpthresholds BS_SCRIPTING @@ -9338,8 +9339,10 @@ BattleScript_EffectMaxMove:: BattleScript_EffectRaiseStatAllies:: savetarget copybyte gBattlerTarget, gBattlerAttacker + copybyte sSAVED_STAT_CHANGER, sSTATCHANGER BattleScript_RaiseSideStatsLoop: jumpifabsent BS_TARGET, BattleScript_RaiseSideStatsIncrement + copybyte sSTATCHANGER, sSAVED_STAT_CHANGER statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_RaiseSideStatsIncrement jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_RaiseSideStatsIncrement printfromtable gStatUpStringIds @@ -9354,8 +9357,10 @@ BattleScript_RaiseSideStatsEnd: BattleScript_EffectLowerStatFoes:: savetarget copybyte sBATTLER, gBattlerTarget + copybyte sSAVED_STAT_CHANGER, sSTATCHANGER BattleScript_LowerSideStatsLoop: jumpifabsent BS_TARGET, BattleScript_LowerSideStatsIncrement + copybyte sSTATCHANGER, sSAVED_STAT_CHANGER statbuffchange BS_TARGET, STAT_CHANGE_ALLOW_PTR, BattleScript_LowerSideStatsIncrement jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_LowerSideStatsIncrement printfromtable gStatDownStringIds diff --git a/data/maps/LilycoveCity_ContestLobby/scripts.inc b/data/maps/LilycoveCity_ContestLobby/scripts.inc index 08c1625114..1ce260673f 100644 --- a/data/maps/LilycoveCity_ContestLobby/scripts.inc +++ b/data/maps/LilycoveCity_ContestLobby/scripts.inc @@ -349,7 +349,11 @@ LilycoveCity_ContestLobby_EventScript_SetMasterContestType:: @ Functionally unused LilycoveCity_ContestLobby_EventScript_SetDebug:: setflag FLAG_HIDE_LILYCOVE_MUSEUM_CURATOR - copyvar VAR_LILYCOVE_MUSEUM_2F_STATE, 1 +#ifdef UBFIX + setvar VAR_LILYCOVE_MUSEUM_2F_STATE, 1 +#else + copyvar VAR_LILYCOVE_MUSEUM_2F_STATE, 1, warn=FALSE +#endif additem ITEM_CONTEST_PASS setvar VAR_0x800B, 8 setvar VAR_CONTEST_RANK, CONTEST_RANK_MASTER diff --git a/data/maps/LilycoveCity_LilycoveMuseum_2F/scripts.inc b/data/maps/LilycoveCity_LilycoveMuseum_2F/scripts.inc index e1ead22521..42abb46b6b 100644 --- a/data/maps/LilycoveCity_LilycoveMuseum_2F/scripts.inc +++ b/data/maps/LilycoveCity_LilycoveMuseum_2F/scripts.inc @@ -76,7 +76,11 @@ LilycoveCity_LilycoveMuseum_2F_EventScript_ShowExhibitHall:: applymovement LOCALID_PLAYER, LilycoveCity_LilycoveMuseum_2F_Movement_PlayerWalkInPlaceLeft waitmovement 0 msgbox LilycoveCity_LilycoveMuseum_2F_Text_PleaseObtainPaintingsForExhibit, MSGBOX_SIGN - copyvar VAR_LILYCOVE_MUSEUM_2F_STATE, 1 +#ifdef UBFIX + setvar VAR_LILYCOVE_MUSEUM_2F_STATE, 1 +#else + copyvar VAR_LILYCOVE_MUSEUM_2F_STATE, 1, warn=FALSE +#endif releaseall end diff --git a/data/maps/SkyPillar_2F/scripts.inc b/data/maps/SkyPillar_2F/scripts.inc index bad2488f0b..a530e01113 100644 --- a/data/maps/SkyPillar_2F/scripts.inc +++ b/data/maps/SkyPillar_2F/scripts.inc @@ -6,7 +6,11 @@ SkyPillar_2F_MapScripts:: SkyPillar_2F_OnTransition: call_if_lt VAR_SKY_PILLAR_STATE, 2, SkyPillar_2F_EventScript_CleanFloor - copyvar VAR_ICE_STEP_COUNT, 1 +#ifdef UBFIX + setvar VAR_ICE_STEP_COUNT, 1 +#else + copyvar VAR_ICE_STEP_COUNT, 1, warn=FALSE +#endif end SkyPillar_2F_EventScript_CleanFloor:: diff --git a/data/maps/SkyPillar_4F/scripts.inc b/data/maps/SkyPillar_4F/scripts.inc index 9e8f1e80ea..603144f04b 100644 --- a/data/maps/SkyPillar_4F/scripts.inc +++ b/data/maps/SkyPillar_4F/scripts.inc @@ -6,7 +6,11 @@ SkyPillar_4F_MapScripts:: SkyPillar_4F_OnTransition: call_if_lt VAR_SKY_PILLAR_STATE, 2, SkyPillar_4F_EventScript_CleanFloor - copyvar VAR_ICE_STEP_COUNT, 1 +#ifdef UBFIX + setvar VAR_ICE_STEP_COUNT, 1 +#else + copyvar VAR_ICE_STEP_COUNT, 1, warn=FALSE +#endif end SkyPillar_4F_EventScript_CleanFloor:: diff --git a/data/scripts/cave_hole.inc b/data/scripts/cave_hole.inc index fc4962912a..e6f9084705 100644 --- a/data/scripts/cave_hole.inc +++ b/data/scripts/cave_hole.inc @@ -3,7 +3,11 @@ CaveHole_CheckFallDownHole: .2byte 0 CaveHole_FixCrackedGround: - copyvar VAR_ICE_STEP_COUNT, 1 +#ifdef UBFIX + setvar VAR_ICE_STEP_COUNT, 1 +#else + copyvar VAR_ICE_STEP_COUNT, 1, warn=FALSE +#endif end EventScript_FallDownHole:: diff --git a/graphics/battle_anims/backgrounds/rainbow.pal b/graphics/battle_anims/backgrounds/rainbow.pal deleted file mode 100644 index 9b62b7b25b..0000000000 --- a/graphics/battle_anims/backgrounds/rainbow.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -109 92 75 -255 255 255 -255 107 122 -255 200 102 -255 255 107 -143 255 160 -107 255 255 -107 129 255 -220 114 255 -199 255 250 -232 240 248 -224 232 240 -208 224 240 -191 202 224 -183 189 202 -157 166 181 diff --git a/graphics/battle_anims/backgrounds/rainbow.png b/graphics/battle_anims/backgrounds/rainbow.png deleted file mode 100644 index bd41645b35..0000000000 Binary files a/graphics/battle_anims/backgrounds/rainbow.png and /dev/null differ diff --git a/graphics/battle_anims/backgrounds/rainbow.bin b/graphics/battle_anims/backgrounds/rainbow_opponent_tile.bin similarity index 53% rename from graphics/battle_anims/backgrounds/rainbow.bin rename to graphics/battle_anims/backgrounds/rainbow_opponent_tile.bin index 770389abf4..3aedd149cb 100644 Binary files a/graphics/battle_anims/backgrounds/rainbow.bin and b/graphics/battle_anims/backgrounds/rainbow_opponent_tile.bin differ diff --git a/graphics/battle_anims/backgrounds/rainbow_opponent_tile.png b/graphics/battle_anims/backgrounds/rainbow_opponent_tile.png new file mode 100644 index 0000000000..2737714805 Binary files /dev/null and b/graphics/battle_anims/backgrounds/rainbow_opponent_tile.png differ diff --git a/graphics/battle_anims/backgrounds/rainbow_player_tile.bin b/graphics/battle_anims/backgrounds/rainbow_player_tile.bin new file mode 100644 index 0000000000..a4f509ebe9 Binary files /dev/null and b/graphics/battle_anims/backgrounds/rainbow_player_tile.bin differ diff --git a/graphics/battle_anims/backgrounds/rainbow_player_tile.png b/graphics/battle_anims/backgrounds/rainbow_player_tile.png new file mode 100644 index 0000000000..5597a2fa92 Binary files /dev/null and b/graphics/battle_anims/backgrounds/rainbow_player_tile.png differ diff --git a/graphics/pokemon/chesnaught/overworld.png b/graphics/pokemon/chesnaught/overworld.png index 7902feaf57..99c5d10cba 100644 Binary files a/graphics/pokemon/chesnaught/overworld.png and b/graphics/pokemon/chesnaught/overworld.png differ diff --git a/graphics/pokemon/chespin/overworld.png b/graphics/pokemon/chespin/overworld.png index 5056ad774a..92df00e97d 100644 Binary files a/graphics/pokemon/chespin/overworld.png and b/graphics/pokemon/chespin/overworld.png differ diff --git a/graphics/pokemon/delphox/overworld.png b/graphics/pokemon/delphox/overworld.png index e490e31cd8..dbf3da76ea 100644 Binary files a/graphics/pokemon/delphox/overworld.png and b/graphics/pokemon/delphox/overworld.png differ diff --git a/graphics/pokemon/diggersby/overworld.png b/graphics/pokemon/diggersby/overworld.png index 03d6b59066..39f72f5531 100644 Binary files a/graphics/pokemon/diggersby/overworld.png and b/graphics/pokemon/diggersby/overworld.png differ diff --git a/graphics/pokemon/espurr/overworld.png b/graphics/pokemon/espurr/overworld.png index f7ba8e08a0..6df4dddb3e 100644 Binary files a/graphics/pokemon/espurr/overworld.png and b/graphics/pokemon/espurr/overworld.png differ diff --git a/graphics/pokemon/fletchinder/overworld.png b/graphics/pokemon/fletchinder/overworld.png index a987365357..949b3e308d 100644 Binary files a/graphics/pokemon/fletchinder/overworld.png and b/graphics/pokemon/fletchinder/overworld.png differ diff --git a/graphics/pokemon/fletchling/overworld.png b/graphics/pokemon/fletchling/overworld.png index acfc95f616..4c35d25d17 100644 Binary files a/graphics/pokemon/fletchling/overworld.png and b/graphics/pokemon/fletchling/overworld.png differ diff --git a/graphics/pokemon/greninja/overworld.png b/graphics/pokemon/greninja/overworld.png index bb08608ca5..6e14bb60eb 100644 Binary files a/graphics/pokemon/greninja/overworld.png and b/graphics/pokemon/greninja/overworld.png differ diff --git a/graphics/pokemon/lillipup/overworld.png b/graphics/pokemon/lillipup/overworld.png index ef88414713..14f876a2c6 100644 Binary files a/graphics/pokemon/lillipup/overworld.png and b/graphics/pokemon/lillipup/overworld.png differ diff --git a/graphics/pokemon/litleo/overworld.png b/graphics/pokemon/litleo/overworld.png index 2c128f3184..a419a8327d 100644 Binary files a/graphics/pokemon/litleo/overworld.png and b/graphics/pokemon/litleo/overworld.png differ diff --git a/graphics/pokemon/pancham/overworld.png b/graphics/pokemon/pancham/overworld.png index 90d10d9bfa..a54ddda99d 100644 Binary files a/graphics/pokemon/pancham/overworld.png and b/graphics/pokemon/pancham/overworld.png differ diff --git a/graphics/pokemon/scatterbug/overworld.png b/graphics/pokemon/scatterbug/overworld.png index 2da700223d..41de917984 100644 Binary files a/graphics/pokemon/scatterbug/overworld.png and b/graphics/pokemon/scatterbug/overworld.png differ diff --git a/graphics/pokemon/talonflame/overworld.png b/graphics/pokemon/talonflame/overworld.png index 43760d9e85..67fc802f44 100644 Binary files a/graphics/pokemon/talonflame/overworld.png and b/graphics/pokemon/talonflame/overworld.png differ diff --git a/graphics/pokemon/watchog/overworld.png b/graphics/pokemon/watchog/overworld.png index e9184c7375..092d97f508 100644 Binary files a/graphics/pokemon/watchog/overworld.png and b/graphics/pokemon/watchog/overworld.png differ diff --git a/include/battle.h b/include/battle.h old mode 100644 new mode 100755 index 15b37d62c8..6c93e91d66 --- a/include/battle.h +++ b/include/battle.h @@ -693,7 +693,7 @@ struct BattleStruct u8 fickleBeamBoosted:1; u8 poisonPuppeteerConfusion:1; u16 startingStatusTimer; - u8 atkCancellerTracker; + u8 atkCancelerTracker; struct BattleTvMovePoints tvMovePoints; struct BattleTv tv; u8 AI_monToSwitchIntoId[MAX_BATTLERS_COUNT]; @@ -904,7 +904,7 @@ struct BattleScripting u8 specialTrainerBattleType; bool8 monCaught; s32 savedDmg; - u16 savedMoveEffect; // For moves hitting multiple targets. + u16 unused_0x2c; u16 moveEffect; u16 multihitMoveEffect; u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN. @@ -1249,4 +1249,9 @@ static inline bool32 IsBattlerInvalidForSpreadMove(u32 battlerAtk, u32 battlerDe || (battlerDef == BATTLE_PARTNER(battlerAtk) && (moveTarget == MOVE_TARGET_BOTH)); } +static inline u32 GetChosenMoveFromPosition(u32 battler) +{ + return gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; +} + #endif // GUARD_BATTLE_H diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 1964e45d53..46e1e2d7b7 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -151,7 +151,6 @@ u32 CountPositiveStatStages(u32 battlerId); u32 CountNegativeStatStages(u32 battlerId); // move checks -bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect); bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category); enum MoveComparisonResult AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32 noOfHitsToKo); struct SimulatedDamage AI_CalcDamageSaveBattlers(u32 move, u32 battlerAtk, u32 battlerDef, uq4_12_t *typeEffectiveness, enum AIConsiderGimmick considerGimmickAtk, enum AIConsiderGimmick considerGimmickDef); diff --git a/include/battle_util.h b/include/battle_util.h index 7bb8bc7292..c91078db2b 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -106,35 +106,35 @@ struct TypePower enum MoveSuccessOrder { - CANCELLER_FLAGS, - CANCELLER_STANCE_CHANGE_1, - CANCELLER_SKY_DROP, - CANCELLER_RECHARGE, - CANCELLER_ASLEEP_OR_FROZEN, - CANCELLER_OBEDIENCE, - CANCELLER_TRUANT, - CANCELLER_FLINCH, - CANCELLER_DISABLED, - CANCELLER_VOLATILE_BLOCKED, - CANCELLER_TAUNTED, - CANCELLER_IMPRISONED, - CANCELLER_CONFUSED, - CANCELLER_PARALYSED, - CANCELLER_INFATUATION, - CANCELLER_BIDE, - CANCELLER_THAW, - CANCELLER_STANCE_CHANGE_2, - CANCELLER_CHOICE_LOCK, - CANCELLER_WEATHER_PRIMAL, - CANCELLER_DYNAMAX_BLOCKED, - CANCELLER_POWDER_STATUS, - CANCELLER_PROTEAN, - CANCELLER_PSYCHIC_TERRAIN, - CANCELLER_EXPLODING_DAMP, - CANCELLER_MULTIHIT_MOVES, - CANCELLER_Z_MOVES, - CANCELLER_MULTI_TARGET_MOVES, - CANCELLER_END, + CANCELER_FLAGS, + CANCELER_STANCE_CHANGE_1, + CANCELER_SKY_DROP, + CANCELER_RECHARGE, + CANCELER_ASLEEP_OR_FROZEN, + CANCELER_OBEDIENCE, + CANCELER_TRUANT, + CANCELER_FLINCH, + CANCELER_DISABLED, + CANCELER_VOLATILE_BLOCKED, + CANCELER_TAUNTED, + CANCELER_IMPRISONED, + CANCELER_CONFUSED, + CANCELER_PARALYSED, + CANCELER_INFATUATION, + CANCELER_BIDE, + CANCELER_THAW, + CANCELER_STANCE_CHANGE_2, + CANCELER_CHOICE_LOCK, + CANCELER_WEATHER_PRIMAL, + CANCELER_DYNAMAX_BLOCKED, + CANCELER_POWDER_STATUS, + CANCELER_PROTEAN, + CANCELER_PSYCHIC_TERRAIN, + CANCELER_EXPLODING_DAMP, + CANCELER_MULTIHIT_MOVES, + CANCELER_Z_MOVES, + CANCELER_MULTI_TARGET_MOVES, + CANCELER_END, }; enum Obedience @@ -147,7 +147,7 @@ enum Obedience DISOBEYS_RANDOM_MOVE, }; -enum MoveCanceller +enum MoveCanceler { MOVE_STEP_SUCCESS, MOVE_STEP_BREAK, @@ -166,7 +166,7 @@ struct DamageContext u32 randomFactor:1; u32 updateFlags:1; u32 isAnticipation:1; - u32 padding1:1; + u32 isSelfInflicted:1; u32 weather:16; u32 fixedBasePower:8; u32 padding2:8; @@ -186,7 +186,7 @@ enum SleepClauseBlock enum SkyDropState { SKY_DROP_IGNORE, - SKY_DROP_ATTACKCANCELLER_CHECK, + SKY_DROP_ATTACKCANCELER_CHECK, SKY_DROP_GRAVITY_ON_AIRBORNE, SKY_DROP_CANCEL_MULTI_TURN_MOVES, SKY_DROP_STATUS_YAWN, @@ -239,8 +239,8 @@ bool32 IsAbilityAndRecord(u32 battler, u32 battlerAbility, u32 abilityToCheck); u32 DoEndTurnEffects(void); bool32 HandleFaintedMonActions(void); void TryClearRageAndFuryCutter(void); -enum MoveCanceller AtkCanceller_MoveSuccessOrder(void); -void SetAtkCancellerForCalledMove(void); +enum MoveCanceler AtkCanceler_MoveSuccessOrder(void); +void SetAtkCancelerForCalledMove(void); bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2); bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, u32 ability); bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag); @@ -416,5 +416,6 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u bool32 IsSemiInvulnerable(u32 battler, enum SemiInvulnerableExclusion excludeCommander); bool32 BreaksThroughSemiInvulnerablity(u32 battler, u32 move); bool32 HasPartnerTrainer(u32 battler); +bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum ItemHoldEffect holdEffect); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/config/battle.h b/include/config/battle.h index 2b9e9fdecc..67008ba027 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -166,6 +166,7 @@ #define B_BATTLE_BOND GEN_LATEST // In Gen9+, Battle Bond increases Atk, SpAtk and Speed by one stage, once per battle #define B_ATE_MULTIPLIER GEN_LATEST // In Gen7+, -ate abilities (Aerilate, Galvanize, Normalize, Pixilate, Refrigerate) multiply damage by 1.2. Otherwise, it's 1.3, except Normalize which has no multiplier. #define B_DEFIANT_STICKY_WEB GEN_LATEST // In Gen9+, Defiant activates on Sticky Web regardless of who set it up. In Gen8, Defiant does not activate on Sticky Web set up by an ally after Court Change swaps its side. +#define B_POWDER_OVERCOAT GEN_LATEST // In Gen6+, Overcoat blocks powder and spore moves from affecting the user. // 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. diff --git a/include/constants/battle.h b/include/constants/battle.h index d2913d6fc6..8527ec800f 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -169,7 +169,7 @@ enum VolatileFlags F(VOLATILE_FORESIGHT, foresight, (u32, 1)) \ F(VOLATILE_DRAGON_CHEER, dragonCheer, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_FOCUS_ENERGY, focusEnergy, (u32, 1), V_BATON_PASSABLE) \ - F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, 5)) \ + F(VOLATILE_SEMI_INVULNERABLE, semiInvulnerable, (u32, SEMI_INVULNERABLE_COUNT - 1)) \ F(VOLATILE_ELECTRIFIED, electrified, (u32, 1)) \ F(VOLATILE_MUD_SPORT, mudSport, (u32, 1), V_BATON_PASSABLE) \ F(VOLATILE_WATER_SPORT, waterSport, (u32, 1), V_BATON_PASSABLE) \ @@ -224,6 +224,7 @@ enum SemiInvulnerableState STATE_PHANTOM_FORCE, STATE_SKY_DROP, STATE_COMMANDER, + SEMI_INVULNERABLE_COUNT, }; enum SemiInvulnerableExclusion diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index 74683a70b6..e169b29cf3 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -533,8 +533,9 @@ #define BG_STEEL_BEAM_OPPONENT 78 #define BG_STEEL_BEAM_PLAYER 79 #define BG_CHLOROBLAST 80 -#define BG_RAINBOW 81 -#define BG_SWAMP 82 +#define BG_RAINBOW_PLAYER 81 +#define BG_RAINBOW_OPPONENT 82 +#define BG_SWAMP 83 // table ids for general animations (sBattleAnims_General) #define B_ANIM_STATS_CHANGE 0 diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 94d2a2bd48..2cadf215af 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -31,7 +31,7 @@ #define sSPECIAL_TRAINER_BATTLE_TYPE (gBattleScripting + 0x26) // specialTrainerBattleType #define sMON_CAUGHT (gBattleScripting + 0x27) // monCaught #define sSAVED_DMG (gBattleScripting + 0x28) // savedDmg -#define sSAVED_MOVE_EFFECT (gBattleScripting + 0x2C) // savedMoveEffect +#define sUNUSED_0x2C (gBattleScripting + 0x2C) // unused_0x2c #define sMOVE_EFFECT (gBattleScripting + 0x2E) // moveEffect #define sMULTIHIT_EFFECT (gBattleScripting + 0x30) // multihitMoveEffect #define sILLUSION_NICK_HACK (gBattleScripting + 0x32) // illusionNickHack diff --git a/include/constants/generational_changes.h b/include/constants/generational_changes.h index 7be7998d9e..381c77ca13 100644 --- a/include/constants/generational_changes.h +++ b/include/constants/generational_changes.h @@ -42,10 +42,12 @@ enum GenConfigTag GEN_CONFIG_DESTINY_BOND_FAIL, GEN_CONFIG_POWDER_RAIN, GEN_CONFIG_POWDER_GRASS, + GEN_CONFIG_POWDER_OVERCOAT, GEN_CONFIG_OBLIVIOUS_TAUNT, GEN_CONFIG_TOXIC_NEVER_MISS, GEN_CONFIG_PARALYZE_ELECTRIC, GEN_CONFIG_BADGE_BOOST, + GEN_CONFIG_LEAF_GUARD_PREVENTS_REST, GEN_CONFIG_COUNT }; diff --git a/include/generational_changes.h b/include/generational_changes.h index 9b6b385c7e..0068d74428 100644 --- a/include/generational_changes.h +++ b/include/generational_changes.h @@ -45,10 +45,12 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] = [GEN_CONFIG_DESTINY_BOND_FAIL] = B_DESTINY_BOND_FAIL, [GEN_CONFIG_POWDER_RAIN] = B_POWDER_RAIN, [GEN_CONFIG_POWDER_GRASS] = B_POWDER_GRASS, + [GEN_CONFIG_POWDER_OVERCOAT] = B_POWDER_OVERCOAT, [GEN_CONFIG_OBLIVIOUS_TAUNT] = B_OBLIVIOUS_TAUNT, [GEN_CONFIG_TOXIC_NEVER_MISS] = B_TOXIC_NEVER_MISS, [GEN_CONFIG_PARALYZE_ELECTRIC] = B_PARALYZE_ELECTRIC, - [GEN_CONFIG_BADGE_BOOST] = B_BADGE_BOOST + [GEN_CONFIG_BADGE_BOOST] = B_BADGE_BOOST, + [GEN_CONFIG_LEAF_GUARD_PREVENTS_REST] = B_LEAF_GUARD_PREVENTS_REST, }; #if TESTING diff --git a/include/global.h b/include/global.h index ff0b6f79e1..a3dacfb3d4 100644 --- a/include/global.h +++ b/include/global.h @@ -1180,6 +1180,8 @@ struct MapPosition #if T_SHOULD_RUN_MOVE_ANIM extern bool32 gLoadFail; +extern bool32 gCountAllocs; +extern s32 gSpriteAllocs; #endif // T_SHOULD_RUN_MOVE_ANIM #endif // GUARD_GLOBAL_H diff --git a/include/graphics.h b/include/graphics.h index 82bf2691eb..bc168e39a1 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -3196,9 +3196,11 @@ extern const u32 gBattleAnimBgTilemap_Sandstorm[]; extern const u32 gBattleAnimBgImage_Sandstorm[]; // Pledge Effect field status - Rainbow -extern const u32 gBattleAnimBgImage_Rainbow[]; +extern const u32 gBattleAnimBgImage_RainbowPlayer[]; +extern const u32 gBattleAnimBgImage_RainbowOpponent[]; extern const u16 gBattleAnimBGPalette_Rainbow[]; -extern const u32 gBattleAnimBgTilemap_Rainbow[]; +extern const u32 gBattleAnimBgTilemap_RainbowPlayer[]; +extern const u32 gBattleAnimBgTilemap_RainbowOpponent[]; // Pledge Effect field status - Swamp extern const u32 gBattleAnimBgImage_Swamp[]; diff --git a/include/test_runner.h b/include/test_runner.h index 9e0d96ff5b..b7aa69a076 100644 --- a/include/test_runner.h +++ b/include/test_runner.h @@ -2,7 +2,11 @@ #define GUARD_TEST_RUNNER_H extern const bool8 gTestRunnerEnabled; +#if TESTING extern const bool8 gTestRunnerHeadless; +#else +#define gTestRunnerHeadless FALSE +#endif extern const bool8 gTestRunnerSkipIsFail; #if TESTING diff --git a/sound/song_table.inc b/sound/song_table.inc index c551a656b9..6e4237b998 100644 --- a/sound/song_table.inc +++ b/sound/song_table.inc @@ -1,616 +1,621 @@ + .equiv MUSIC_PLAYER_BGM,0 + .equiv MUSIC_PLAYER_SE1,1 + .equiv MUSIC_PLAYER_SE2,2 + .equiv MUSIC_PLAYER_SE3,3 + .align 2 gSongTable:: - song mus_dummy, 0, 0 - song se_use_item, 1, 1 - song se_pc_login, 1, 1 - song se_pc_off, 1, 1 - song se_pc_on, 1, 1 - song se_select, 2, 2 - song se_win_open, 1, 1 - song se_wall_hit, 2, 2 - song se_door, 1, 1 - song se_exit, 1, 1 - song se_ledge, 1, 1 - song se_bike_bell, 1, 1 - song se_not_effective, 1, 1 - song se_effective, 1, 1 - song se_super_effective, 1, 1 - song se_ball_open, 1, 1 - song se_faint, 1, 1 - song se_flee, 1, 1 - song se_sliding_door, 1, 1 - song se_ship, 1, 1 - song se_bang, 1, 1 - song se_pin, 1, 1 - song se_boo, 1, 1 - song se_ball, 1, 1 - song se_contest_place, 2, 2 - song se_a, 1, 1 - song se_i, 1, 1 - song se_u, 1, 1 - song se_e, 1, 1 - song se_o, 1, 1 - song se_n, 1, 1 - song se_success, 1, 1 - song se_failure, 1, 1 - song se_exp, 1, 1 - song se_bike_hop, 1, 1 - song se_switch, 1, 1 - song se_click, 1, 1 - song se_fu_zaku, 1, 1 - song se_contest_condition_lose, 1, 1 - song se_lavaridge_fall_warp, 1, 1 - song se_ice_stairs, 1, 1 - song se_ice_break, 1, 1 - song se_ice_crack, 1, 1 - song se_fall, 1, 1 - song se_unlock, 2, 2 - song se_warp_in, 1, 1 - song se_warp_out, 1, 1 - song se_repel, 1, 1 - song se_rotating_gate, 1, 1 - song se_truck_move, 1, 1 - song se_truck_stop, 1, 1 - song se_truck_unload, 2, 2 - song se_truck_door, 1, 1 - song se_berry_blender, 2, 2 - song se_card, 1, 1 - song se_save, 1, 1 - song se_ball_bounce_1, 1, 1 - song se_ball_bounce_2, 1, 1 - song se_ball_bounce_3, 1, 1 - song se_ball_bounce_4, 1, 1 - song se_ball_trade, 2, 2 - song se_ball_throw, 1, 1 - song se_note_c, 2, 2 - song se_note_d, 2, 2 - song se_note_e, 2, 2 - song se_note_f, 2, 2 - song se_note_g, 2, 2 - song se_note_a, 2, 2 - song se_note_b, 2, 2 - song se_note_c_high, 2, 2 - song se_puddle, 2, 2 - song se_bridge_walk, 2, 2 - song se_itemfinder, 1, 1 - song se_ding_dong, 1, 1 - song se_balloon_red, 2, 2 - song se_balloon_blue, 2, 2 - song se_balloon_yellow, 2, 2 - song se_breakable_door, 2, 2 - song se_mud_ball, 2, 2 - song se_field_poison, 1, 1 - song se_escalator, 1, 1 - song se_thunderstorm, 3, 3 - song se_thunderstorm_stop, 3, 3 - song se_downpour, 3, 3 - song se_downpour_stop, 3, 3 - song se_rain, 3, 3 - song se_rain_stop, 3, 3 - song se_thunder, 1, 1 - song se_thunder2, 1, 1 - song se_elevator, 1, 1 - song se_low_health, 3, 3 - song se_exp_max, 1, 1 - song se_roulette_ball, 2, 2 - song se_roulette_ball2, 2, 2 - song se_taillow_wing_flap, 1, 1 - song se_shop, 1, 1 - song se_contest_heart, 1, 1 - song se_contest_curtain_rise, 1, 1 - song se_contest_curtain_fall, 1, 1 - song se_contest_icon_change, 1, 1 - song se_contest_icon_clear, 1, 1 - song se_contest_mons_turn, 1, 1 - song se_shiny, 1, 1 - song se_intro_blast, 1, 1 - song se_mugshot, 1, 1 - song se_applause, 1, 1 - song se_vend, 1, 1 - song se_orb, 1, 1 - song se_dex_scroll, 1, 1 - song se_dex_page, 1, 1 - song se_pokenav_on, 1, 1 - song se_pokenav_off, 1, 1 - song se_dex_search, 1, 1 - song se_egg_hatch, 1, 1 - song se_ball_tray_enter, 1, 1 - song se_ball_tray_ball, 1, 1 - song se_ball_tray_exit, 2, 2 - song se_glass_flute, 1, 1 - song se_m_thunderbolt, 2, 2 - song se_m_thunderbolt2, 1, 1 - song se_m_harden, 1, 1 - song se_m_nightmare, 1, 1 - song se_m_vital_throw, 1, 1 - song se_m_vital_throw2, 1, 1 - song se_m_bubble, 1, 1 - song se_m_bubble2, 1, 1 - song se_m_bubble3, 1, 1 - song se_m_rain_dance, 1, 1 - song se_m_cut, 1, 1 - song se_m_string_shot, 1, 1 - song se_m_string_shot2, 1, 1 - song se_m_rock_throw, 1, 1 - song se_m_gust, 2, 2 - song se_m_gust2, 2, 2 - song se_m_double_slap, 1, 1 - song se_m_double_team, 1, 1 - song se_m_razor_wind, 1, 1 - song se_m_icy_wind, 1, 1 - song se_m_thunder_wave, 1, 1 - song se_m_comet_punch, 1, 1 - song se_m_mega_kick, 1, 1 - song se_m_mega_kick2, 1, 1 - song se_m_crabhammer, 1, 1 - song se_m_jump_kick, 1, 1 - song se_m_flame_wheel, 1, 1 - song se_m_flame_wheel2, 1, 1 - song se_m_flamethrower, 1, 1 - song se_m_fire_punch, 1, 1 - song se_m_toxic, 1, 1 - song se_m_sacred_fire, 1, 1 - song se_m_sacred_fire2, 2, 2 - song se_m_ember, 1, 1 - song se_m_take_down, 2, 2 - song se_m_blizzard, 1, 1 - song se_m_blizzard2, 1, 1 - song se_m_scratch, 1, 1 - song se_m_vicegrip, 1, 1 - song se_m_wing_attack, 1, 1 - song se_m_fly, 1, 1 - song se_m_sand_attack, 1, 1 - song se_m_razor_wind2, 1, 1 - song se_m_bite, 1, 1 - song se_m_headbutt, 1, 1 - song se_m_surf, 1, 1 - song se_m_hydro_pump, 1, 1 - song se_m_whirlpool, 1, 1 - song se_m_horn_attack, 1, 1 - song se_m_tail_whip, 2, 2 - song se_m_mist, 1, 1 - song se_m_poison_powder, 1, 1 - song se_m_bind, 2, 2 - song se_m_dragon_rage, 1, 1 - song se_m_sing, 1, 1 - song se_m_perish_song, 1, 1 - song se_m_pay_day, 1, 1 - song se_m_dig, 1, 1 - song se_m_dizzy_punch, 1, 1 - song se_m_self_destruct, 1, 1 - song se_m_explosion, 1, 1 - song se_m_absorb_2, 1, 1 - song se_m_absorb, 1, 1 - song se_m_screech, 1, 1 - song se_m_bubble_beam, 1, 1 - song se_m_bubble_beam2, 1, 1 - song se_m_supersonic, 1, 1 - song se_m_belly_drum, 1, 1 - song se_m_metronome, 1, 1 - song se_m_bonemerang, 1, 1 - song se_m_lick, 1, 1 - song se_m_psybeam, 1, 1 - song se_m_faint_attack, 1, 1 - song se_m_swords_dance, 1, 1 - song se_m_leer, 1, 1 - song se_m_swagger, 1, 1 - song se_m_swagger2, 1, 1 - song se_m_heal_bell, 1, 1 - song se_m_confuse_ray, 1, 1 - song se_m_snore, 1, 1 - song se_m_brick_break, 1, 1 - song se_m_giga_drain, 1, 1 - song se_m_psybeam2, 1, 1 - song se_m_solar_beam, 2, 2 - song se_m_petal_dance, 1, 1 - song se_m_teleport, 1, 1 - song se_m_minimize, 1, 1 - song se_m_sketch, 1, 1 - song se_m_swift, 1, 1 - song se_m_reflect, 1, 1 - song se_m_barrier, 1, 1 - song se_m_detect, 2, 2 - song se_m_lock_on, 1, 1 - song se_m_moonlight, 1, 1 - song se_m_charm, 1, 1 - song se_m_charge, 1, 1 - song se_m_strength, 1, 1 - song se_m_hyper_beam, 1, 1 - song se_m_waterfall, 1, 1 - song se_m_reversal, 1, 1 - song se_m_acid_armor, 1, 1 - song se_m_sandstorm, 1, 1 - song se_m_tri_attack, 1, 1 - song se_m_tri_attack2, 1, 1 - song se_m_encore, 1, 1 - song se_m_encore2, 2, 2 - song se_m_baton_pass, 1, 1 - song se_m_milk_drink, 1, 1 - song se_m_attract, 1, 1 - song se_m_attract2, 1, 1 - song se_m_morning_sun, 1, 1 - song se_m_flatter, 1, 1 - song se_m_sand_tomb, 1, 1 - song se_m_grasswhistle, 1, 1 - song se_m_spit_up, 1, 1 - song se_m_dive, 1, 1 - song se_m_earthquake, 2, 2 - song se_m_twister, 2, 2 - song se_m_sweet_scent, 1, 1 - song se_m_yawn, 1, 1 - song se_m_sky_uppercut, 2, 2 - song se_m_stat_increase, 1, 1 - song se_m_heat_wave, 1, 1 - song se_m_uproar, 1, 1 - song se_m_hail, 1, 1 - song se_m_cosmic_power, 2, 2 - song se_m_teeter_dance, 1, 1 - song se_m_stat_decrease, 1, 1 - song se_m_haze, 1, 1 - song se_m_hyper_beam2, 1, 1 - song se_rg_door, 1, 1 - song se_rg_card_flip, 1, 1 - song se_rg_card_flipping, 1, 1 - song se_rg_card_open, 1, 1 - song se_rg_bag_cursor, 1, 1 - song se_rg_bag_pocket, 1, 1 - song se_rg_ball_click, 1, 1 - song se_rg_shop, 1, 1 - song se_rg_ss_anne_horn, 1, 1 - song se_rg_help_open, 1, 1 - song se_rg_help_close, 1, 1 - song se_rg_help_error, 1, 1 - song se_rg_deoxys_move, 1, 1 - song se_rg_poke_jump_success, 1, 1 - song se_rg_poke_jump_failure, 1, 1 - song se_pokenav_call, 1, 1 - song se_pokenav_hang_up, 1, 1 - song se_arena_timeup1, 1, 1 - song se_arena_timeup2, 1, 1 - song se_pike_curtain_close, 1, 1 - song se_pike_curtain_open, 1, 1 - song se_sudowoodo_shake, 1, 1 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song dummy_song_header, 0, 0 - song mus_littleroot_test, 0, 0 - song mus_gsc_route38, 0, 0 - song mus_caught, 0, 0 - song mus_victory_wild, 0, 0 - song mus_victory_gym_leader, 0, 0 - song mus_victory_league, 0, 0 - song mus_c_comm_center, 0, 0 - song mus_gsc_pewter, 0, 0 - song mus_c_vs_legend_beast, 0, 0 - song mus_route101, 0, 0 - song mus_route110, 0, 0 - song mus_route120, 0, 0 - song mus_petalburg, 0, 0 - song mus_oldale, 0, 0 - song mus_gym, 0, 0 - song mus_surf, 0, 0 - song mus_petalburg_woods, 0, 0 - song mus_level_up, 2, 2 - song mus_heal, 2, 2 - song mus_obtain_badge, 2, 2 - song mus_obtain_item, 2, 2 - song mus_evolved, 2, 2 - song mus_obtain_tmhm, 2, 2 - song mus_lilycove_museum, 0, 0 - song mus_route122, 0, 0 - song mus_oceanic_museum, 0, 0 - song mus_evolution_intro, 2, 2 - song mus_evolution, 0, 0 - song mus_move_deleted, 2, 2 - song mus_encounter_girl, 0, 0 - song mus_encounter_male, 0, 0 - song mus_abandoned_ship, 0, 0 - song mus_fortree, 0, 0 - song mus_birch_lab, 0, 0 - song mus_b_tower_rs, 0, 0 - song mus_encounter_swimmer, 0, 0 - song mus_cave_of_origin, 0, 0 - song mus_obtain_berry, 2, 2 - song mus_awaken_legend, 2, 2 - song mus_slots_jackpot, 2, 2 - song mus_slots_win, 2, 2 - song mus_too_bad, 2, 2 - song mus_roulette, 0, 0 - song mus_link_contest_p1, 0, 0 - song mus_link_contest_p2, 0, 0 - song mus_link_contest_p3, 0, 0 - song mus_link_contest_p4, 0, 0 - song mus_encounter_rich, 0, 0 - song mus_verdanturf, 0, 0 - song mus_rustboro, 0, 0 - song mus_poke_center, 0, 0 - song mus_route104, 0, 0 - song mus_route119, 0, 0 - song mus_cycling, 0, 0 - song mus_poke_mart, 0, 0 - song mus_littleroot, 0, 0 - song mus_mt_chimney, 0, 0 - song mus_encounter_female, 0, 0 - song mus_lilycove, 0, 0 - song mus_route111, 0, 0 - song mus_help, 0, 0 - song mus_underwater, 0, 0 - song mus_victory_trainer, 0, 0 - song mus_title, 0, 0 - song mus_intro, 0, 0 - song mus_encounter_may, 0, 0 - song mus_encounter_intense, 0, 0 - song mus_encounter_cool, 0, 0 - song mus_route113, 0, 0 - song mus_encounter_aqua, 0, 0 - song mus_follow_me, 0, 0 - song mus_encounter_brendan, 0, 0 - song mus_ever_grande, 0, 0 - song mus_encounter_suspicious, 0, 0 - song mus_victory_aqua_magma, 0, 0 - song mus_cable_car, 0, 0 - song mus_game_corner, 0, 0 - song mus_dewford, 0, 0 - song mus_safari_zone, 0, 0 - song mus_victory_road, 0, 0 - song mus_aqua_magma_hideout, 0, 0 - song mus_sailing, 0, 0 - song mus_mt_pyre, 0, 0 - song mus_slateport, 0, 0 - song mus_mt_pyre_exterior, 0, 0 - song mus_school, 0, 0 - song mus_hall_of_fame, 0, 0 - song mus_fallarbor, 0, 0 - song mus_sealed_chamber, 0, 0 - song mus_contest_winner, 0, 0 - song mus_contest, 0, 0 - song mus_encounter_magma, 0, 0 - song mus_intro_battle, 0, 0 - song mus_abnormal_weather, 0, 0 - song mus_weather_groudon, 0, 0 - song mus_sootopolis, 0, 0 - song mus_contest_results, 0, 0 - song mus_hall_of_fame_room, 0, 0 - song mus_trick_house, 0, 0 - song mus_encounter_twins, 0, 0 - song mus_encounter_elite_four, 0, 0 - song mus_encounter_hiker, 0, 0 - song mus_contest_lobby, 0, 0 - song mus_encounter_interviewer, 0, 0 - song mus_encounter_champion, 0, 0 - song mus_credits, 0, 0 - song mus_end, 0, 0 - song mus_b_frontier, 0, 0 - song mus_b_arena, 0, 0 - song mus_obtain_b_points, 2, 2 - song mus_register_match_call, 2, 2 - song mus_b_pyramid, 0, 0 - song mus_b_pyramid_top, 0, 0 - song mus_b_palace, 0, 0 - song mus_rayquaza_appears, 0, 0 - song mus_b_tower, 0, 0 - song mus_obtain_symbol, 2, 2 - song mus_b_dome, 0, 0 - song mus_b_pike, 0, 0 - song mus_b_factory, 0, 0 - song mus_vs_rayquaza, 0, 0 - song mus_vs_frontier_brain, 0, 0 - song mus_vs_mew, 0, 0 - song mus_b_dome_lobby, 0, 0 - song mus_vs_wild, 0, 0 - song mus_vs_aqua_magma, 0, 0 - song mus_vs_trainer, 0, 0 - song mus_vs_gym_leader, 0, 0 - song mus_vs_champion, 0, 0 - song mus_vs_regi, 0, 0 - song mus_vs_kyogre_groudon, 0, 0 - song mus_vs_rival, 0, 0 - song mus_vs_elite_four, 0, 0 - song mus_vs_aqua_magma_leader, 0, 0 - song mus_rg_follow_me, 0, 0 - song mus_rg_game_corner, 0, 0 - song mus_rg_rocket_hideout, 0, 0 - song mus_rg_gym, 0, 0 - song mus_rg_jigglypuff, 2, 2 - song mus_rg_intro_fight, 0, 0 - song mus_rg_title, 0, 0 - song mus_rg_cinnabar, 0, 0 - song mus_rg_lavender, 0, 0 - song mus_rg_heal, 0, 0 - song mus_rg_cycling, 0, 0 - song mus_rg_encounter_rocket, 0, 0 - song mus_rg_encounter_girl, 0, 0 - song mus_rg_encounter_boy, 0, 0 - song mus_rg_hall_of_fame, 0, 0 - song mus_rg_viridian_forest, 0, 0 - song mus_rg_mt_moon, 0, 0 - song mus_rg_poke_mansion, 0, 0 - song mus_rg_credits, 0, 0 - song mus_rg_route1, 0, 0 - song mus_rg_route24, 0, 0 - song mus_rg_route3, 0, 0 - song mus_rg_route11, 0, 0 - song mus_rg_victory_road, 0, 0 - song mus_rg_vs_gym_leader, 0, 0 - song mus_rg_vs_trainer, 0, 0 - song mus_rg_vs_wild, 0, 0 - song mus_rg_vs_champion, 0, 0 - song mus_rg_pallet, 0, 0 - song mus_rg_oak_lab, 0, 0 - song mus_rg_oak, 0, 0 - song mus_rg_poke_center, 0, 0 - song mus_rg_ss_anne, 0, 0 - song mus_rg_surf, 0, 0 - song mus_rg_poke_tower, 0, 0 - song mus_rg_silph, 0, 0 - song mus_rg_fuchsia, 0, 0 - song mus_rg_celadon, 0, 0 - song mus_rg_victory_trainer, 0, 0 - song mus_rg_victory_wild, 0, 0 - song mus_rg_victory_gym_leader, 0, 0 - song mus_rg_vermillion, 0, 0 - song mus_rg_pewter, 0, 0 - song mus_rg_encounter_rival, 0, 0 - song mus_rg_rival_exit, 0, 0 - song mus_rg_dex_rating, 2, 2 - song mus_rg_obtain_key_item, 2, 2 - song mus_rg_caught_intro, 2, 2 - song mus_rg_photo, 2, 2 - song mus_rg_game_freak, 0, 0 - song mus_rg_caught, 0, 0 - song mus_rg_new_game_instruct, 0, 0 - song mus_rg_new_game_intro, 0, 0 - song mus_rg_new_game_exit, 0, 0 - song mus_rg_poke_jump, 0, 0 - song mus_rg_union_room, 0, 0 - song mus_rg_net_center, 0, 0 - song mus_rg_mystery_gift, 0, 0 - song mus_rg_berry_pick, 0, 0 - song mus_rg_sevii_cave, 0, 0 - song mus_rg_teachy_tv_show, 0, 0 - song mus_rg_sevii_route, 0, 0 - song mus_rg_sevii_dungeon, 0, 0 - song mus_rg_sevii_123, 0, 0 - song mus_rg_sevii_45, 0, 0 - song mus_rg_sevii_67, 0, 0 - song mus_rg_poke_flute, 2, 2 - song mus_rg_vs_deoxys, 0, 0 - song mus_rg_vs_mewtwo, 0, 0 - song mus_rg_vs_legend, 0, 0 - song mus_rg_encounter_gym_leader, 0, 0 - song mus_rg_encounter_deoxys, 0, 0 - song mus_rg_trainer_tower, 0, 0 - song mus_rg_slow_pallet, 0, 0 - song mus_rg_teachy_tv_menu, 0, 0 - song ph_trap_blend, 2, 2 - song ph_trap_held, 2, 2 - song ph_trap_solo, 2, 2 - song ph_face_blend, 2, 2 - song ph_face_held, 2, 2 - song ph_face_solo, 2, 2 - song ph_cloth_blend, 2, 2 - song ph_cloth_held, 2, 2 - song ph_cloth_solo, 2, 2 - song ph_dress_blend, 2, 2 - song ph_dress_held, 2, 2 - song ph_dress_solo, 2, 2 - song ph_fleece_blend, 2, 2 - song ph_fleece_held, 2, 2 - song ph_fleece_solo, 2, 2 - song ph_kit_blend, 2, 2 - song ph_kit_held, 2, 2 - song ph_kit_solo, 2, 2 - song ph_price_blend, 2, 2 - song ph_price_held, 2, 2 - song ph_price_solo, 2, 2 - song ph_lot_blend, 2, 2 - song ph_lot_held, 2, 2 - song ph_lot_solo, 2, 2 - song ph_goat_blend, 2, 2 - song ph_goat_held, 2, 2 - song ph_goat_solo, 2, 2 - song ph_thought_blend, 2, 2 - song ph_thought_held, 2, 2 - song ph_thought_solo, 2, 2 - song ph_choice_blend, 2, 2 - song ph_choice_held, 2, 2 - song ph_choice_solo, 2, 2 - song ph_mouth_blend, 2, 2 - song ph_mouth_held, 2, 2 - song ph_mouth_solo, 2, 2 - song ph_foot_blend, 2, 2 - song ph_foot_held, 2, 2 - song ph_foot_solo, 2, 2 - song ph_goose_blend, 2, 2 - song ph_goose_held, 2, 2 - song ph_goose_solo, 2, 2 - song ph_strut_blend, 2, 2 - song ph_strut_held, 2, 2 - song ph_strut_solo, 2, 2 - song ph_cure_blend, 2, 2 - song ph_cure_held, 2, 2 - song ph_cure_solo, 2, 2 - song ph_nurse_blend, 2, 2 - song ph_nurse_held, 2, 2 - song ph_nurse_solo, 2, 2 + song mus_dummy, MUSIC_PLAYER_BGM, 0 + song se_use_item, MUSIC_PLAYER_SE1, 1 + song se_pc_login, MUSIC_PLAYER_SE1, 1 + song se_pc_off, MUSIC_PLAYER_SE1, 1 + song se_pc_on, MUSIC_PLAYER_SE1, 1 + song se_select, MUSIC_PLAYER_SE2, 2 + song se_win_open, MUSIC_PLAYER_SE1, 1 + song se_wall_hit, MUSIC_PLAYER_SE2, 2 + song se_door, MUSIC_PLAYER_SE1, 1 + song se_exit, MUSIC_PLAYER_SE1, 1 + song se_ledge, MUSIC_PLAYER_SE1, 1 + song se_bike_bell, MUSIC_PLAYER_SE1, 1 + song se_not_effective, MUSIC_PLAYER_SE1, 1 + song se_effective, MUSIC_PLAYER_SE1, 1 + song se_super_effective, MUSIC_PLAYER_SE1, 1 + song se_ball_open, MUSIC_PLAYER_SE1, 1 + song se_faint, MUSIC_PLAYER_SE1, 1 + song se_flee, MUSIC_PLAYER_SE1, 1 + song se_sliding_door, MUSIC_PLAYER_SE1, 1 + song se_ship, MUSIC_PLAYER_SE1, 1 + song se_bang, MUSIC_PLAYER_SE1, 1 + song se_pin, MUSIC_PLAYER_SE1, 1 + song se_boo, MUSIC_PLAYER_SE1, 1 + song se_ball, MUSIC_PLAYER_SE1, 1 + song se_contest_place, MUSIC_PLAYER_SE2, 2 + song se_a, MUSIC_PLAYER_SE1, 1 + song se_i, MUSIC_PLAYER_SE1, 1 + song se_u, MUSIC_PLAYER_SE1, 1 + song se_e, MUSIC_PLAYER_SE1, 1 + song se_o, MUSIC_PLAYER_SE1, 1 + song se_n, MUSIC_PLAYER_SE1, 1 + song se_success, MUSIC_PLAYER_SE1, 1 + song se_failure, MUSIC_PLAYER_SE1, 1 + song se_exp, MUSIC_PLAYER_SE1, 1 + song se_bike_hop, MUSIC_PLAYER_SE1, 1 + song se_switch, MUSIC_PLAYER_SE1, 1 + song se_click, MUSIC_PLAYER_SE1, 1 + song se_fu_zaku, MUSIC_PLAYER_SE1, 1 + song se_contest_condition_lose, MUSIC_PLAYER_SE1, 1 + song se_lavaridge_fall_warp, MUSIC_PLAYER_SE1, 1 + song se_ice_stairs, MUSIC_PLAYER_SE1, 1 + song se_ice_break, MUSIC_PLAYER_SE1, 1 + song se_ice_crack, MUSIC_PLAYER_SE1, 1 + song se_fall, MUSIC_PLAYER_SE1, 1 + song se_unlock, MUSIC_PLAYER_SE2, 2 + song se_warp_in, MUSIC_PLAYER_SE1, 1 + song se_warp_out, MUSIC_PLAYER_SE1, 1 + song se_repel, MUSIC_PLAYER_SE1, 1 + song se_rotating_gate, MUSIC_PLAYER_SE1, 1 + song se_truck_move, MUSIC_PLAYER_SE1, 1 + song se_truck_stop, MUSIC_PLAYER_SE1, 1 + song se_truck_unload, MUSIC_PLAYER_SE2, 2 + song se_truck_door, MUSIC_PLAYER_SE1, 1 + song se_berry_blender, MUSIC_PLAYER_SE2, 2 + song se_card, MUSIC_PLAYER_SE1, 1 + song se_save, MUSIC_PLAYER_SE1, 1 + song se_ball_bounce_1, MUSIC_PLAYER_SE1, 1 + song se_ball_bounce_2, MUSIC_PLAYER_SE1, 1 + song se_ball_bounce_3, MUSIC_PLAYER_SE1, 1 + song se_ball_bounce_4, MUSIC_PLAYER_SE1, 1 + song se_ball_trade, MUSIC_PLAYER_SE2, 2 + song se_ball_throw, MUSIC_PLAYER_SE1, 1 + song se_note_c, MUSIC_PLAYER_SE2, 2 + song se_note_d, MUSIC_PLAYER_SE2, 2 + song se_note_e, MUSIC_PLAYER_SE2, 2 + song se_note_f, MUSIC_PLAYER_SE2, 2 + song se_note_g, MUSIC_PLAYER_SE2, 2 + song se_note_a, MUSIC_PLAYER_SE2, 2 + song se_note_b, MUSIC_PLAYER_SE2, 2 + song se_note_c_high, MUSIC_PLAYER_SE2, 2 + song se_puddle, MUSIC_PLAYER_SE2, 2 + song se_bridge_walk, MUSIC_PLAYER_SE2, 2 + song se_itemfinder, MUSIC_PLAYER_SE1, 1 + song se_ding_dong, MUSIC_PLAYER_SE1, 1 + song se_balloon_red, MUSIC_PLAYER_SE2, 2 + song se_balloon_blue, MUSIC_PLAYER_SE2, 2 + song se_balloon_yellow, MUSIC_PLAYER_SE2, 2 + song se_breakable_door, MUSIC_PLAYER_SE2, 2 + song se_mud_ball, MUSIC_PLAYER_SE2, 2 + song se_field_poison, MUSIC_PLAYER_SE1, 1 + song se_escalator, MUSIC_PLAYER_SE1, 1 + song se_thunderstorm, MUSIC_PLAYER_SE3, 3 + song se_thunderstorm_stop, MUSIC_PLAYER_SE3, 3 + song se_downpour, MUSIC_PLAYER_SE3, 3 + song se_downpour_stop, MUSIC_PLAYER_SE3, 3 + song se_rain, MUSIC_PLAYER_SE3, 3 + song se_rain_stop, MUSIC_PLAYER_SE3, 3 + song se_thunder, MUSIC_PLAYER_SE1, 1 + song se_thunder2, MUSIC_PLAYER_SE1, 1 + song se_elevator, MUSIC_PLAYER_SE1, 1 + song se_low_health, MUSIC_PLAYER_SE3, 3 + song se_exp_max, MUSIC_PLAYER_SE1, 1 + song se_roulette_ball, MUSIC_PLAYER_SE2, 2 + song se_roulette_ball2, MUSIC_PLAYER_SE2, 2 + song se_taillow_wing_flap, MUSIC_PLAYER_SE1, 1 + song se_shop, MUSIC_PLAYER_SE1, 1 + song se_contest_heart, MUSIC_PLAYER_SE1, 1 + song se_contest_curtain_rise, MUSIC_PLAYER_SE1, 1 + song se_contest_curtain_fall, MUSIC_PLAYER_SE1, 1 + song se_contest_icon_change, MUSIC_PLAYER_SE1, 1 + song se_contest_icon_clear, MUSIC_PLAYER_SE1, 1 + song se_contest_mons_turn, MUSIC_PLAYER_SE1, 1 + song se_shiny, MUSIC_PLAYER_SE1, 1 + song se_intro_blast, MUSIC_PLAYER_SE1, 1 + song se_mugshot, MUSIC_PLAYER_SE1, 1 + song se_applause, MUSIC_PLAYER_SE1, 1 + song se_vend, MUSIC_PLAYER_SE1, 1 + song se_orb, MUSIC_PLAYER_SE1, 1 + song se_dex_scroll, MUSIC_PLAYER_SE1, 1 + song se_dex_page, MUSIC_PLAYER_SE1, 1 + song se_pokenav_on, MUSIC_PLAYER_SE1, 1 + song se_pokenav_off, MUSIC_PLAYER_SE1, 1 + song se_dex_search, MUSIC_PLAYER_SE1, 1 + song se_egg_hatch, MUSIC_PLAYER_SE1, 1 + song se_ball_tray_enter, MUSIC_PLAYER_SE1, 1 + song se_ball_tray_ball, MUSIC_PLAYER_SE1, 1 + song se_ball_tray_exit, MUSIC_PLAYER_SE2, 2 + song se_glass_flute, MUSIC_PLAYER_SE1, 1 + song se_m_thunderbolt, MUSIC_PLAYER_SE2, 2 + song se_m_thunderbolt2, MUSIC_PLAYER_SE1, 1 + song se_m_harden, MUSIC_PLAYER_SE1, 1 + song se_m_nightmare, MUSIC_PLAYER_SE1, 1 + song se_m_vital_throw, MUSIC_PLAYER_SE1, 1 + song se_m_vital_throw2, MUSIC_PLAYER_SE1, 1 + song se_m_bubble, MUSIC_PLAYER_SE1, 1 + song se_m_bubble2, MUSIC_PLAYER_SE1, 1 + song se_m_bubble3, MUSIC_PLAYER_SE1, 1 + song se_m_rain_dance, MUSIC_PLAYER_SE1, 1 + song se_m_cut, MUSIC_PLAYER_SE1, 1 + song se_m_string_shot, MUSIC_PLAYER_SE1, 1 + song se_m_string_shot2, MUSIC_PLAYER_SE1, 1 + song se_m_rock_throw, MUSIC_PLAYER_SE1, 1 + song se_m_gust, MUSIC_PLAYER_SE2, 2 + song se_m_gust2, MUSIC_PLAYER_SE2, 2 + song se_m_double_slap, MUSIC_PLAYER_SE1, 1 + song se_m_double_team, MUSIC_PLAYER_SE1, 1 + song se_m_razor_wind, MUSIC_PLAYER_SE1, 1 + song se_m_icy_wind, MUSIC_PLAYER_SE1, 1 + song se_m_thunder_wave, MUSIC_PLAYER_SE1, 1 + song se_m_comet_punch, MUSIC_PLAYER_SE1, 1 + song se_m_mega_kick, MUSIC_PLAYER_SE1, 1 + song se_m_mega_kick2, MUSIC_PLAYER_SE1, 1 + song se_m_crabhammer, MUSIC_PLAYER_SE1, 1 + song se_m_jump_kick, MUSIC_PLAYER_SE1, 1 + song se_m_flame_wheel, MUSIC_PLAYER_SE1, 1 + song se_m_flame_wheel2, MUSIC_PLAYER_SE1, 1 + song se_m_flamethrower, MUSIC_PLAYER_SE1, 1 + song se_m_fire_punch, MUSIC_PLAYER_SE1, 1 + song se_m_toxic, MUSIC_PLAYER_SE1, 1 + song se_m_sacred_fire, MUSIC_PLAYER_SE1, 1 + song se_m_sacred_fire2, MUSIC_PLAYER_SE2, 2 + song se_m_ember, MUSIC_PLAYER_SE1, 1 + song se_m_take_down, MUSIC_PLAYER_SE2, 2 + song se_m_blizzard, MUSIC_PLAYER_SE1, 1 + song se_m_blizzard2, MUSIC_PLAYER_SE1, 1 + song se_m_scratch, MUSIC_PLAYER_SE1, 1 + song se_m_vicegrip, MUSIC_PLAYER_SE1, 1 + song se_m_wing_attack, MUSIC_PLAYER_SE1, 1 + song se_m_fly, MUSIC_PLAYER_SE1, 1 + song se_m_sand_attack, MUSIC_PLAYER_SE1, 1 + song se_m_razor_wind2, MUSIC_PLAYER_SE1, 1 + song se_m_bite, MUSIC_PLAYER_SE1, 1 + song se_m_headbutt, MUSIC_PLAYER_SE1, 1 + song se_m_surf, MUSIC_PLAYER_SE1, 1 + song se_m_hydro_pump, MUSIC_PLAYER_SE1, 1 + song se_m_whirlpool, MUSIC_PLAYER_SE1, 1 + song se_m_horn_attack, MUSIC_PLAYER_SE1, 1 + song se_m_tail_whip, MUSIC_PLAYER_SE2, 2 + song se_m_mist, MUSIC_PLAYER_SE1, 1 + song se_m_poison_powder, MUSIC_PLAYER_SE1, 1 + song se_m_bind, MUSIC_PLAYER_SE2, 2 + song se_m_dragon_rage, MUSIC_PLAYER_SE1, 1 + song se_m_sing, MUSIC_PLAYER_SE1, 1 + song se_m_perish_song, MUSIC_PLAYER_SE1, 1 + song se_m_pay_day, MUSIC_PLAYER_SE1, 1 + song se_m_dig, MUSIC_PLAYER_SE1, 1 + song se_m_dizzy_punch, MUSIC_PLAYER_SE1, 1 + song se_m_self_destruct, MUSIC_PLAYER_SE1, 1 + song se_m_explosion, MUSIC_PLAYER_SE1, 1 + song se_m_absorb_2, MUSIC_PLAYER_SE1, 1 + song se_m_absorb, MUSIC_PLAYER_SE1, 1 + song se_m_screech, MUSIC_PLAYER_SE1, 1 + song se_m_bubble_beam, MUSIC_PLAYER_SE1, 1 + song se_m_bubble_beam2, MUSIC_PLAYER_SE1, 1 + song se_m_supersonic, MUSIC_PLAYER_SE1, 1 + song se_m_belly_drum, MUSIC_PLAYER_SE1, 1 + song se_m_metronome, MUSIC_PLAYER_SE1, 1 + song se_m_bonemerang, MUSIC_PLAYER_SE1, 1 + song se_m_lick, MUSIC_PLAYER_SE1, 1 + song se_m_psybeam, MUSIC_PLAYER_SE1, 1 + song se_m_faint_attack, MUSIC_PLAYER_SE1, 1 + song se_m_swords_dance, MUSIC_PLAYER_SE1, 1 + song se_m_leer, MUSIC_PLAYER_SE1, 1 + song se_m_swagger, MUSIC_PLAYER_SE1, 1 + song se_m_swagger2, MUSIC_PLAYER_SE1, 1 + song se_m_heal_bell, MUSIC_PLAYER_SE1, 1 + song se_m_confuse_ray, MUSIC_PLAYER_SE1, 1 + song se_m_snore, MUSIC_PLAYER_SE1, 1 + song se_m_brick_break, MUSIC_PLAYER_SE1, 1 + song se_m_giga_drain, MUSIC_PLAYER_SE1, 1 + song se_m_psybeam2, MUSIC_PLAYER_SE1, 1 + song se_m_solar_beam, MUSIC_PLAYER_SE2, 2 + song se_m_petal_dance, MUSIC_PLAYER_SE1, 1 + song se_m_teleport, MUSIC_PLAYER_SE1, 1 + song se_m_minimize, MUSIC_PLAYER_SE1, 1 + song se_m_sketch, MUSIC_PLAYER_SE1, 1 + song se_m_swift, MUSIC_PLAYER_SE1, 1 + song se_m_reflect, MUSIC_PLAYER_SE1, 1 + song se_m_barrier, MUSIC_PLAYER_SE1, 1 + song se_m_detect, MUSIC_PLAYER_SE2, 2 + song se_m_lock_on, MUSIC_PLAYER_SE1, 1 + song se_m_moonlight, MUSIC_PLAYER_SE1, 1 + song se_m_charm, MUSIC_PLAYER_SE1, 1 + song se_m_charge, MUSIC_PLAYER_SE1, 1 + song se_m_strength, MUSIC_PLAYER_SE1, 1 + song se_m_hyper_beam, MUSIC_PLAYER_SE1, 1 + song se_m_waterfall, MUSIC_PLAYER_SE1, 1 + song se_m_reversal, MUSIC_PLAYER_SE1, 1 + song se_m_acid_armor, MUSIC_PLAYER_SE1, 1 + song se_m_sandstorm, MUSIC_PLAYER_SE1, 1 + song se_m_tri_attack, MUSIC_PLAYER_SE1, 1 + song se_m_tri_attack2, MUSIC_PLAYER_SE1, 1 + song se_m_encore, MUSIC_PLAYER_SE1, 1 + song se_m_encore2, MUSIC_PLAYER_SE2, 2 + song se_m_baton_pass, MUSIC_PLAYER_SE1, 1 + song se_m_milk_drink, MUSIC_PLAYER_SE1, 1 + song se_m_attract, MUSIC_PLAYER_SE1, 1 + song se_m_attract2, MUSIC_PLAYER_SE1, 1 + song se_m_morning_sun, MUSIC_PLAYER_SE1, 1 + song se_m_flatter, MUSIC_PLAYER_SE1, 1 + song se_m_sand_tomb, MUSIC_PLAYER_SE1, 1 + song se_m_grasswhistle, MUSIC_PLAYER_SE1, 1 + song se_m_spit_up, MUSIC_PLAYER_SE1, 1 + song se_m_dive, MUSIC_PLAYER_SE1, 1 + song se_m_earthquake, MUSIC_PLAYER_SE2, 2 + song se_m_twister, MUSIC_PLAYER_SE2, 2 + song se_m_sweet_scent, MUSIC_PLAYER_SE1, 1 + song se_m_yawn, MUSIC_PLAYER_SE1, 1 + song se_m_sky_uppercut, MUSIC_PLAYER_SE2, 2 + song se_m_stat_increase, MUSIC_PLAYER_SE1, 1 + song se_m_heat_wave, MUSIC_PLAYER_SE1, 1 + song se_m_uproar, MUSIC_PLAYER_SE1, 1 + song se_m_hail, MUSIC_PLAYER_SE1, 1 + song se_m_cosmic_power, MUSIC_PLAYER_SE2, 2 + song se_m_teeter_dance, MUSIC_PLAYER_SE1, 1 + song se_m_stat_decrease, MUSIC_PLAYER_SE1, 1 + song se_m_haze, MUSIC_PLAYER_SE1, 1 + song se_m_hyper_beam2, MUSIC_PLAYER_SE1, 1 + song se_rg_door, MUSIC_PLAYER_SE1, 1 + song se_rg_card_flip, MUSIC_PLAYER_SE1, 1 + song se_rg_card_flipping, MUSIC_PLAYER_SE1, 1 + song se_rg_card_open, MUSIC_PLAYER_SE1, 1 + song se_rg_bag_cursor, MUSIC_PLAYER_SE1, 1 + song se_rg_bag_pocket, MUSIC_PLAYER_SE1, 1 + song se_rg_ball_click, MUSIC_PLAYER_SE1, 1 + song se_rg_shop, MUSIC_PLAYER_SE1, 1 + song se_rg_ss_anne_horn, MUSIC_PLAYER_SE1, 1 + song se_rg_help_open, MUSIC_PLAYER_SE1, 1 + song se_rg_help_close, MUSIC_PLAYER_SE1, 1 + song se_rg_help_error, MUSIC_PLAYER_SE1, 1 + song se_rg_deoxys_move, MUSIC_PLAYER_SE1, 1 + song se_rg_poke_jump_success, MUSIC_PLAYER_SE1, 1 + song se_rg_poke_jump_failure, MUSIC_PLAYER_SE1, 1 + song se_pokenav_call, MUSIC_PLAYER_SE1, 1 + song se_pokenav_hang_up, MUSIC_PLAYER_SE1, 1 + song se_arena_timeup1, MUSIC_PLAYER_SE1, 1 + song se_arena_timeup2, MUSIC_PLAYER_SE1, 1 + song se_pike_curtain_close, MUSIC_PLAYER_SE1, 1 + song se_pike_curtain_open, MUSIC_PLAYER_SE1, 1 + song se_sudowoodo_shake, MUSIC_PLAYER_SE1, 1 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song dummy_song_header, MUSIC_PLAYER_BGM, 0 + song mus_littleroot_test, MUSIC_PLAYER_BGM, 0 + song mus_gsc_route38, MUSIC_PLAYER_BGM, 0 + song mus_caught, MUSIC_PLAYER_BGM, 0 + song mus_victory_wild, MUSIC_PLAYER_BGM, 0 + song mus_victory_gym_leader, MUSIC_PLAYER_BGM, 0 + song mus_victory_league, MUSIC_PLAYER_BGM, 0 + song mus_c_comm_center, MUSIC_PLAYER_BGM, 0 + song mus_gsc_pewter, MUSIC_PLAYER_BGM, 0 + song mus_c_vs_legend_beast, MUSIC_PLAYER_BGM, 0 + song mus_route101, MUSIC_PLAYER_BGM, 0 + song mus_route110, MUSIC_PLAYER_BGM, 0 + song mus_route120, MUSIC_PLAYER_BGM, 0 + song mus_petalburg, MUSIC_PLAYER_BGM, 0 + song mus_oldale, MUSIC_PLAYER_BGM, 0 + song mus_gym, MUSIC_PLAYER_BGM, 0 + song mus_surf, MUSIC_PLAYER_BGM, 0 + song mus_petalburg_woods, MUSIC_PLAYER_BGM, 0 + song mus_level_up, MUSIC_PLAYER_SE2, 2 + song mus_heal, MUSIC_PLAYER_SE2, 2 + song mus_obtain_badge, MUSIC_PLAYER_SE2, 2 + song mus_obtain_item, MUSIC_PLAYER_SE2, 2 + song mus_evolved, MUSIC_PLAYER_SE2, 2 + song mus_obtain_tmhm, MUSIC_PLAYER_SE2, 2 + song mus_lilycove_museum, MUSIC_PLAYER_BGM, 0 + song mus_route122, MUSIC_PLAYER_BGM, 0 + song mus_oceanic_museum, MUSIC_PLAYER_BGM, 0 + song mus_evolution_intro, MUSIC_PLAYER_SE2, 2 + song mus_evolution, MUSIC_PLAYER_BGM, 0 + song mus_move_deleted, MUSIC_PLAYER_SE2, 2 + song mus_encounter_girl, MUSIC_PLAYER_BGM, 0 + song mus_encounter_male, MUSIC_PLAYER_BGM, 0 + song mus_abandoned_ship, MUSIC_PLAYER_BGM, 0 + song mus_fortree, MUSIC_PLAYER_BGM, 0 + song mus_birch_lab, MUSIC_PLAYER_BGM, 0 + song mus_b_tower_rs, MUSIC_PLAYER_BGM, 0 + song mus_encounter_swimmer, MUSIC_PLAYER_BGM, 0 + song mus_cave_of_origin, MUSIC_PLAYER_BGM, 0 + song mus_obtain_berry, MUSIC_PLAYER_SE2, 2 + song mus_awaken_legend, MUSIC_PLAYER_SE2, 2 + song mus_slots_jackpot, MUSIC_PLAYER_SE2, 2 + song mus_slots_win, MUSIC_PLAYER_SE2, 2 + song mus_too_bad, MUSIC_PLAYER_SE2, 2 + song mus_roulette, MUSIC_PLAYER_BGM, 0 + song mus_link_contest_p1, MUSIC_PLAYER_BGM, 0 + song mus_link_contest_p2, MUSIC_PLAYER_BGM, 0 + song mus_link_contest_p3, MUSIC_PLAYER_BGM, 0 + song mus_link_contest_p4, MUSIC_PLAYER_BGM, 0 + song mus_encounter_rich, MUSIC_PLAYER_BGM, 0 + song mus_verdanturf, MUSIC_PLAYER_BGM, 0 + song mus_rustboro, MUSIC_PLAYER_BGM, 0 + song mus_poke_center, MUSIC_PLAYER_BGM, 0 + song mus_route104, MUSIC_PLAYER_BGM, 0 + song mus_route119, MUSIC_PLAYER_BGM, 0 + song mus_cycling, MUSIC_PLAYER_BGM, 0 + song mus_poke_mart, MUSIC_PLAYER_BGM, 0 + song mus_littleroot, MUSIC_PLAYER_BGM, 0 + song mus_mt_chimney, MUSIC_PLAYER_BGM, 0 + song mus_encounter_female, MUSIC_PLAYER_BGM, 0 + song mus_lilycove, MUSIC_PLAYER_BGM, 0 + song mus_route111, MUSIC_PLAYER_BGM, 0 + song mus_help, MUSIC_PLAYER_BGM, 0 + song mus_underwater, MUSIC_PLAYER_BGM, 0 + song mus_victory_trainer, MUSIC_PLAYER_BGM, 0 + song mus_title, MUSIC_PLAYER_BGM, 0 + song mus_intro, MUSIC_PLAYER_BGM, 0 + song mus_encounter_may, MUSIC_PLAYER_BGM, 0 + song mus_encounter_intense, MUSIC_PLAYER_BGM, 0 + song mus_encounter_cool, MUSIC_PLAYER_BGM, 0 + song mus_route113, MUSIC_PLAYER_BGM, 0 + song mus_encounter_aqua, MUSIC_PLAYER_BGM, 0 + song mus_follow_me, MUSIC_PLAYER_BGM, 0 + song mus_encounter_brendan, MUSIC_PLAYER_BGM, 0 + song mus_ever_grande, MUSIC_PLAYER_BGM, 0 + song mus_encounter_suspicious, MUSIC_PLAYER_BGM, 0 + song mus_victory_aqua_magma, MUSIC_PLAYER_BGM, 0 + song mus_cable_car, MUSIC_PLAYER_BGM, 0 + song mus_game_corner, MUSIC_PLAYER_BGM, 0 + song mus_dewford, MUSIC_PLAYER_BGM, 0 + song mus_safari_zone, MUSIC_PLAYER_BGM, 0 + song mus_victory_road, MUSIC_PLAYER_BGM, 0 + song mus_aqua_magma_hideout, MUSIC_PLAYER_BGM, 0 + song mus_sailing, MUSIC_PLAYER_BGM, 0 + song mus_mt_pyre, MUSIC_PLAYER_BGM, 0 + song mus_slateport, MUSIC_PLAYER_BGM, 0 + song mus_mt_pyre_exterior, MUSIC_PLAYER_BGM, 0 + song mus_school, MUSIC_PLAYER_BGM, 0 + song mus_hall_of_fame, MUSIC_PLAYER_BGM, 0 + song mus_fallarbor, MUSIC_PLAYER_BGM, 0 + song mus_sealed_chamber, MUSIC_PLAYER_BGM, 0 + song mus_contest_winner, MUSIC_PLAYER_BGM, 0 + song mus_contest, MUSIC_PLAYER_BGM, 0 + song mus_encounter_magma, MUSIC_PLAYER_BGM, 0 + song mus_intro_battle, MUSIC_PLAYER_BGM, 0 + song mus_abnormal_weather, MUSIC_PLAYER_BGM, 0 + song mus_weather_groudon, MUSIC_PLAYER_BGM, 0 + song mus_sootopolis, MUSIC_PLAYER_BGM, 0 + song mus_contest_results, MUSIC_PLAYER_BGM, 0 + song mus_hall_of_fame_room, MUSIC_PLAYER_BGM, 0 + song mus_trick_house, MUSIC_PLAYER_BGM, 0 + song mus_encounter_twins, MUSIC_PLAYER_BGM, 0 + song mus_encounter_elite_four, MUSIC_PLAYER_BGM, 0 + song mus_encounter_hiker, MUSIC_PLAYER_BGM, 0 + song mus_contest_lobby, MUSIC_PLAYER_BGM, 0 + song mus_encounter_interviewer, MUSIC_PLAYER_BGM, 0 + song mus_encounter_champion, MUSIC_PLAYER_BGM, 0 + song mus_credits, MUSIC_PLAYER_BGM, 0 + song mus_end, MUSIC_PLAYER_BGM, 0 + song mus_b_frontier, MUSIC_PLAYER_BGM, 0 + song mus_b_arena, MUSIC_PLAYER_BGM, 0 + song mus_obtain_b_points, MUSIC_PLAYER_SE2, 2 + song mus_register_match_call, MUSIC_PLAYER_SE2, 2 + song mus_b_pyramid, MUSIC_PLAYER_BGM, 0 + song mus_b_pyramid_top, MUSIC_PLAYER_BGM, 0 + song mus_b_palace, MUSIC_PLAYER_BGM, 0 + song mus_rayquaza_appears, MUSIC_PLAYER_BGM, 0 + song mus_b_tower, MUSIC_PLAYER_BGM, 0 + song mus_obtain_symbol, MUSIC_PLAYER_SE2, 2 + song mus_b_dome, MUSIC_PLAYER_BGM, 0 + song mus_b_pike, MUSIC_PLAYER_BGM, 0 + song mus_b_factory, MUSIC_PLAYER_BGM, 0 + song mus_vs_rayquaza, MUSIC_PLAYER_BGM, 0 + song mus_vs_frontier_brain, MUSIC_PLAYER_BGM, 0 + song mus_vs_mew, MUSIC_PLAYER_BGM, 0 + song mus_b_dome_lobby, MUSIC_PLAYER_BGM, 0 + song mus_vs_wild, MUSIC_PLAYER_BGM, 0 + song mus_vs_aqua_magma, MUSIC_PLAYER_BGM, 0 + song mus_vs_trainer, MUSIC_PLAYER_BGM, 0 + song mus_vs_gym_leader, MUSIC_PLAYER_BGM, 0 + song mus_vs_champion, MUSIC_PLAYER_BGM, 0 + song mus_vs_regi, MUSIC_PLAYER_BGM, 0 + song mus_vs_kyogre_groudon, MUSIC_PLAYER_BGM, 0 + song mus_vs_rival, MUSIC_PLAYER_BGM, 0 + song mus_vs_elite_four, MUSIC_PLAYER_BGM, 0 + song mus_vs_aqua_magma_leader, MUSIC_PLAYER_BGM, 0 + song mus_rg_follow_me, MUSIC_PLAYER_BGM, 0 + song mus_rg_game_corner, MUSIC_PLAYER_BGM, 0 + song mus_rg_rocket_hideout, MUSIC_PLAYER_BGM, 0 + song mus_rg_gym, MUSIC_PLAYER_BGM, 0 + song mus_rg_jigglypuff, MUSIC_PLAYER_SE2, 2 + song mus_rg_intro_fight, MUSIC_PLAYER_BGM, 0 + song mus_rg_title, MUSIC_PLAYER_BGM, 0 + song mus_rg_cinnabar, MUSIC_PLAYER_BGM, 0 + song mus_rg_lavender, MUSIC_PLAYER_BGM, 0 + song mus_rg_heal, MUSIC_PLAYER_BGM, 0 + song mus_rg_cycling, MUSIC_PLAYER_BGM, 0 + song mus_rg_encounter_rocket, MUSIC_PLAYER_BGM, 0 + song mus_rg_encounter_girl, MUSIC_PLAYER_BGM, 0 + song mus_rg_encounter_boy, MUSIC_PLAYER_BGM, 0 + song mus_rg_hall_of_fame, MUSIC_PLAYER_BGM, 0 + song mus_rg_viridian_forest, MUSIC_PLAYER_BGM, 0 + song mus_rg_mt_moon, MUSIC_PLAYER_BGM, 0 + song mus_rg_poke_mansion, MUSIC_PLAYER_BGM, 0 + song mus_rg_credits, MUSIC_PLAYER_BGM, 0 + song mus_rg_route1, MUSIC_PLAYER_BGM, 0 + song mus_rg_route24, MUSIC_PLAYER_BGM, 0 + song mus_rg_route3, MUSIC_PLAYER_BGM, 0 + song mus_rg_route11, MUSIC_PLAYER_BGM, 0 + song mus_rg_victory_road, MUSIC_PLAYER_BGM, 0 + song mus_rg_vs_gym_leader, MUSIC_PLAYER_BGM, 0 + song mus_rg_vs_trainer, MUSIC_PLAYER_BGM, 0 + song mus_rg_vs_wild, MUSIC_PLAYER_BGM, 0 + song mus_rg_vs_champion, MUSIC_PLAYER_BGM, 0 + song mus_rg_pallet, MUSIC_PLAYER_BGM, 0 + song mus_rg_oak_lab, MUSIC_PLAYER_BGM, 0 + song mus_rg_oak, MUSIC_PLAYER_BGM, 0 + song mus_rg_poke_center, MUSIC_PLAYER_BGM, 0 + song mus_rg_ss_anne, MUSIC_PLAYER_BGM, 0 + song mus_rg_surf, MUSIC_PLAYER_BGM, 0 + song mus_rg_poke_tower, MUSIC_PLAYER_BGM, 0 + song mus_rg_silph, MUSIC_PLAYER_BGM, 0 + song mus_rg_fuchsia, MUSIC_PLAYER_BGM, 0 + song mus_rg_celadon, MUSIC_PLAYER_BGM, 0 + song mus_rg_victory_trainer, MUSIC_PLAYER_BGM, 0 + song mus_rg_victory_wild, MUSIC_PLAYER_BGM, 0 + song mus_rg_victory_gym_leader, MUSIC_PLAYER_BGM, 0 + song mus_rg_vermillion, MUSIC_PLAYER_BGM, 0 + song mus_rg_pewter, MUSIC_PLAYER_BGM, 0 + song mus_rg_encounter_rival, MUSIC_PLAYER_BGM, 0 + song mus_rg_rival_exit, MUSIC_PLAYER_BGM, 0 + song mus_rg_dex_rating, MUSIC_PLAYER_SE2, 2 + song mus_rg_obtain_key_item, MUSIC_PLAYER_SE2, 2 + song mus_rg_caught_intro, MUSIC_PLAYER_SE2, 2 + song mus_rg_photo, MUSIC_PLAYER_SE2, 2 + song mus_rg_game_freak, MUSIC_PLAYER_BGM, 0 + song mus_rg_caught, MUSIC_PLAYER_BGM, 0 + song mus_rg_new_game_instruct, MUSIC_PLAYER_BGM, 0 + song mus_rg_new_game_intro, MUSIC_PLAYER_BGM, 0 + song mus_rg_new_game_exit, MUSIC_PLAYER_BGM, 0 + song mus_rg_poke_jump, MUSIC_PLAYER_BGM, 0 + song mus_rg_union_room, MUSIC_PLAYER_BGM, 0 + song mus_rg_net_center, MUSIC_PLAYER_BGM, 0 + song mus_rg_mystery_gift, MUSIC_PLAYER_BGM, 0 + song mus_rg_berry_pick, MUSIC_PLAYER_BGM, 0 + song mus_rg_sevii_cave, MUSIC_PLAYER_BGM, 0 + song mus_rg_teachy_tv_show, MUSIC_PLAYER_BGM, 0 + song mus_rg_sevii_route, MUSIC_PLAYER_BGM, 0 + song mus_rg_sevii_dungeon, MUSIC_PLAYER_BGM, 0 + song mus_rg_sevii_123, MUSIC_PLAYER_BGM, 0 + song mus_rg_sevii_45, MUSIC_PLAYER_BGM, 0 + song mus_rg_sevii_67, MUSIC_PLAYER_BGM, 0 + song mus_rg_poke_flute, MUSIC_PLAYER_SE2, 2 + song mus_rg_vs_deoxys, MUSIC_PLAYER_BGM, 0 + song mus_rg_vs_mewtwo, MUSIC_PLAYER_BGM, 0 + song mus_rg_vs_legend, MUSIC_PLAYER_BGM, 0 + song mus_rg_encounter_gym_leader, MUSIC_PLAYER_BGM, 0 + song mus_rg_encounter_deoxys, MUSIC_PLAYER_BGM, 0 + song mus_rg_trainer_tower, MUSIC_PLAYER_BGM, 0 + song mus_rg_slow_pallet, MUSIC_PLAYER_BGM, 0 + song mus_rg_teachy_tv_menu, MUSIC_PLAYER_BGM, 0 + song ph_trap_blend, MUSIC_PLAYER_SE2, 2 + song ph_trap_held, MUSIC_PLAYER_SE2, 2 + song ph_trap_solo, MUSIC_PLAYER_SE2, 2 + song ph_face_blend, MUSIC_PLAYER_SE2, 2 + song ph_face_held, MUSIC_PLAYER_SE2, 2 + song ph_face_solo, MUSIC_PLAYER_SE2, 2 + song ph_cloth_blend, MUSIC_PLAYER_SE2, 2 + song ph_cloth_held, MUSIC_PLAYER_SE2, 2 + song ph_cloth_solo, MUSIC_PLAYER_SE2, 2 + song ph_dress_blend, MUSIC_PLAYER_SE2, 2 + song ph_dress_held, MUSIC_PLAYER_SE2, 2 + song ph_dress_solo, MUSIC_PLAYER_SE2, 2 + song ph_fleece_blend, MUSIC_PLAYER_SE2, 2 + song ph_fleece_held, MUSIC_PLAYER_SE2, 2 + song ph_fleece_solo, MUSIC_PLAYER_SE2, 2 + song ph_kit_blend, MUSIC_PLAYER_SE2, 2 + song ph_kit_held, MUSIC_PLAYER_SE2, 2 + song ph_kit_solo, MUSIC_PLAYER_SE2, 2 + song ph_price_blend, MUSIC_PLAYER_SE2, 2 + song ph_price_held, MUSIC_PLAYER_SE2, 2 + song ph_price_solo, MUSIC_PLAYER_SE2, 2 + song ph_lot_blend, MUSIC_PLAYER_SE2, 2 + song ph_lot_held, MUSIC_PLAYER_SE2, 2 + song ph_lot_solo, MUSIC_PLAYER_SE2, 2 + song ph_goat_blend, MUSIC_PLAYER_SE2, 2 + song ph_goat_held, MUSIC_PLAYER_SE2, 2 + song ph_goat_solo, MUSIC_PLAYER_SE2, 2 + song ph_thought_blend, MUSIC_PLAYER_SE2, 2 + song ph_thought_held, MUSIC_PLAYER_SE2, 2 + song ph_thought_solo, MUSIC_PLAYER_SE2, 2 + song ph_choice_blend, MUSIC_PLAYER_SE2, 2 + song ph_choice_held, MUSIC_PLAYER_SE2, 2 + song ph_choice_solo, MUSIC_PLAYER_SE2, 2 + song ph_mouth_blend, MUSIC_PLAYER_SE2, 2 + song ph_mouth_held, MUSIC_PLAYER_SE2, 2 + song ph_mouth_solo, MUSIC_PLAYER_SE2, 2 + song ph_foot_blend, MUSIC_PLAYER_SE2, 2 + song ph_foot_held, MUSIC_PLAYER_SE2, 2 + song ph_foot_solo, MUSIC_PLAYER_SE2, 2 + song ph_goose_blend, MUSIC_PLAYER_SE2, 2 + song ph_goose_held, MUSIC_PLAYER_SE2, 2 + song ph_goose_solo, MUSIC_PLAYER_SE2, 2 + song ph_strut_blend, MUSIC_PLAYER_SE2, 2 + song ph_strut_held, MUSIC_PLAYER_SE2, 2 + song ph_strut_solo, MUSIC_PLAYER_SE2, 2 + song ph_cure_blend, MUSIC_PLAYER_SE2, 2 + song ph_cure_held, MUSIC_PLAYER_SE2, 2 + song ph_cure_solo, MUSIC_PLAYER_SE2, 2 + song ph_nurse_blend, MUSIC_PLAYER_SE2, 2 + song ph_nurse_held, MUSIC_PLAYER_SE2, 2 + song ph_nurse_solo, MUSIC_PLAYER_SE2, 2 .align 2 dummy_song_header: diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 0c8c0bb1cd..d2d81c2a53 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1089,7 +1089,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) SetTypeBeforeUsingMove(move, battlerAtk); moveType = GetBattleMoveType(move); - if (IsPowderMove(move) && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) + if (IsPowderMove(move) && !IsAffectedByPowderMove(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) RETURN_SCORE_MINUS(10); if (!BreaksThroughSemiInvulnerablity(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move, predictedMoveSpeedCheck, CONSIDER_PRIORITY)) @@ -4008,7 +4008,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) bool32 isBattle1v1 = IsBattle1v1(); bool32 hasTwoOpponents = HasTwoOpponents(battlerAtk); bool32 hasPartner = HasPartner(battlerAtk); - bool32 moveTargetsBothOpponents = hasTwoOpponents && (gMovesInfo[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_ALL_BATTLERS)); + bool32 moveTargetsBothOpponents = hasTwoOpponents && (GetMoveTarget(move) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_ALL_BATTLERS)); u32 i; // The AI should understand that while Dynamaxed, status moves function like Protect. @@ -4768,7 +4768,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) if (hasPartner && GetMoveTarget(move) == MOVE_TARGET_USER && !IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) - && (!IsPowderMove(move) || IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))) + && (!IsPowderMove(move) || IsAffectedByPowderMove(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))) // Rage Powder doesn't affect powder immunities { u32 predictedMoveOnPartner = gLastMoves[BATTLE_PARTNER(battlerAtk)]; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index f300741675..29b58ed9e6 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -387,7 +387,7 @@ static u32 FindMonWithMoveOfEffectiveness(u32 battler, u32 opposingBattler, uq4_ for (j = 0; j < MAX_MON_MOVES; j++) { move = GetMonData(&party[i], MON_DATA_MOVE1 + j); - if (move != MOVE_NONE && AI_GetMoveEffectiveness(move, battler, opposingBattler) >= effectiveness && gMovesInfo[move].power != 0) + if (move != MOVE_NONE && AI_GetMoveEffectiveness(move, battler, opposingBattler) >= effectiveness && GetMovePower(move) != 0) return SetSwitchinAndSwitch(battler, i); } } @@ -422,7 +422,7 @@ static bool32 ShouldSwitchIfAllMovesBad(u32 battler) if (AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) > UQ_4_12(0.0) && aiMove != MOVE_NONE && !CanAbilityAbsorbMove(battler, opposingBattler, gAiLogicData->abilities[opposingBattler], aiMove, GetBattleMoveType(aiMove), AI_CHECK) && !CanAbilityBlockMove(battler, opposingBattler, gBattleMons[battler].ability, gAiLogicData->abilities[opposingBattler], aiMove, AI_CHECK) - && (!ALL_MOVES_BAD_STATUS_MOVES_BAD || gMovesInfo[aiMove].power != 0)) // If using ALL_MOVES_BAD_STATUS_MOVES_BAD, then need power to be non-zero + && (!ALL_MOVES_BAD_STATUS_MOVES_BAD || GetMovePower(aiMove) != 0)) // If using ALL_MOVES_BAD_STATUS_MOVES_BAD, then need power to be non-zero return FALSE; } } @@ -2414,6 +2414,9 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType) if (bestMonId != PARTY_SIZE) return bestMonId; + if (aceMonId != PARTY_SIZE && aliveCount == 0) + return aceMonId; + bestMonId = GetBestMonTypeMatchup(party, firstId, lastId, invalidMons, battler, opposingBattler); if (bestMonId != PARTY_SIZE) return bestMonId; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 8bed0234ee..e39e80a2d2 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -530,16 +530,6 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler) return FALSE; } -// move checks -bool32 IsAffectedByPowder(u32 battler, u32 ability, enum ItemHoldEffect holdEffect) -{ - if (ability == ABILITY_OVERCOAT - || (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) - || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) - return FALSE; - return TRUE; -} - // This function checks if all physical/special moves are either unusable or unreasonable to use. // Consider a pokemon boosting their attack against a ghost pokemon having only normal-type physical attacks. bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, enum DamageCategory category) @@ -1443,7 +1433,7 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 aiMoveConsidered, u32 pla bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move) { enum BattleMoveEffects effect = GetMoveEffect(move); - if (!AI_BattlerAtMaxHp(battlerTarget) || effect == EFFECT_MULTI_HIT) + if (!AI_BattlerAtMaxHp(battlerTarget) || effect == EFFECT_MULTI_HIT || gAiLogicData->abilities[battler] == ABILITY_PARENTAL_BOND) return FALSE; if (GetMoveStrikeCount(move) > 1 && !(effect == EFFECT_DRAGON_DARTS && !HasTwoOpponents(battler))) return FALSE; @@ -3975,7 +3965,7 @@ bool32 AreMovesEquivalent(u32 battlerAtk, u32 battlerAtkPartner, u32 move, u32 p // shared bits indicate they're meaningfully the same in some way if (atkEffect & partnerEffect) { - if (gMovesInfo[move].target == MOVE_TARGET_SELECTED && gMovesInfo[partnerMove].target == MOVE_TARGET_SELECTED) + if (GetMoveTarget(move) == MOVE_TARGET_SELECTED && GetMoveTarget(partnerMove) == MOVE_TARGET_SELECTED) { if (battlerDef == gBattleStruct->moveTarget[battlerAtkPartner]) return TRUE; @@ -4121,7 +4111,7 @@ bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32 if (GetMoveEffect(move) == GetMoveEffect(partnerMove) && partnerMove != MOVE_NONE) { - if (gMovesInfo[move].target == MOVE_TARGET_SELECTED && gMovesInfo[partnerMove].target == MOVE_TARGET_SELECTED) + if (GetMoveTarget(move) == MOVE_TARGET_SELECTED && GetMoveTarget(partnerMove) == MOVE_TARGET_SELECTED) { return gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef; } @@ -4522,7 +4512,7 @@ bool32 IsRecycleEncouragedItem(u32 item) static bool32 HasMoveThatChangesKOThreshold(u32 battlerId, u32 noOfHitsToFaint, u32 aiIsFaster) { - s32 i; + s32 i, j; u16 *moves = GetMovesArray(battlerId); for (i = 0; i < MAX_MON_MOVES; i++) @@ -4534,16 +4524,21 @@ static bool32 HasMoveThatChangesKOThreshold(u32 battlerId, u32 noOfHitsToFaint, if (GetMovePriority(moves[i]) > 0) return TRUE; - switch (gMovesInfo[moves[i]].additionalEffects[i].moveEffect) + u32 additionalEffectCount = GetMoveAdditionalEffectCount(moves[i]); + for (j = 0; j < additionalEffectCount; j++) { - case MOVE_EFFECT_SPD_MINUS_1: - case MOVE_EFFECT_SPD_MINUS_2: - { - if(aiIsFaster) - return TRUE; - } - default: - break; + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(moves[i], j); + switch (additionalEffect->moveEffect) + { + case MOVE_EFFECT_SPD_MINUS_1: + case MOVE_EFFECT_SPD_MINUS_2: + { + if(aiIsFaster) + return TRUE; + } + default: + break; + } } } } diff --git a/src/battle_anim.c b/src/battle_anim.c index 76e37b7eea..839f319031 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -13,6 +13,7 @@ #include "graphics.h" #include "main.h" #include "malloc.h" +#include "menu.h" #include "m4a.h" #include "palette.h" #include "pokemon.h" @@ -1568,10 +1569,7 @@ void LoadMoveBg(u16 bgId) { if (IsContest()) { - void *decompressionBuffer = Alloc(0x800); - const u32 *tilemap = gBattleAnimBackgroundTable[bgId].tilemap; - - DecompressDataWithHeaderWram(tilemap, decompressionBuffer); + void *decompressionBuffer = malloc_and_decompress(gBattleAnimBackgroundTable[bgId].tilemap, NULL); RelocateBattleBgPal(GetBattleBgPaletteNum(), decompressionBuffer, 0x100, FALSE); DmaCopy32(3, decompressionBuffer, (void *)BG_SCREEN_ADDR(26), 0x800); DecompressDataWithHeaderVram(gBattleAnimBackgroundTable[bgId].image, (void *)BG_SCREEN_ADDR(4)); diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index 128862994b..49ec4e5e3a 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -5189,7 +5189,7 @@ void AnimNeedleArmSpike(struct Sprite *sprite) { if (gBattleAnimArgs[0] == 0) { - if (gMovesInfo[gAnimMoveIndex].target == MOVE_TARGET_BOTH) + if (GetMoveTarget(gAnimMoveIndex) == MOVE_TARGET_BOTH) { SetAverageBattlerPositions(gBattleAnimAttacker, TRUE, &a, &b); } @@ -5201,7 +5201,7 @@ void AnimNeedleArmSpike(struct Sprite *sprite) } else { - if (gMovesInfo[gAnimMoveIndex].target == MOVE_TARGET_BOTH) + if (GetMoveTarget(gAnimMoveIndex) == MOVE_TARGET_BOTH) { SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &a, &b); } diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 1263632ab7..378fde42a4 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -9431,7 +9431,7 @@ static void SpriteCB_MaxFlutterby(struct Sprite* sprite) { s16 target_x; s16 target_y; - if (gMovesInfo[gAnimMoveIndex].target == MOVE_TARGET_BOTH) + if (GetMoveTarget(gAnimMoveIndex) == MOVE_TARGET_BOTH) { SetAverageBattlerPositions(gBattleAnimTarget, TRUE, &target_x, &target_y); } diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index 54f16003be..5860a57630 100644 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -14,6 +14,7 @@ #include "sound.h" #include "sprite.h" #include "task.h" +#include "test_runner.h" #include "trig.h" #include "util.h" #include "data.h" @@ -2435,7 +2436,7 @@ void TryShinyAnimation(u8 battler, struct Pokemon *mon) if (illusionMon != NULL) mon = illusionMon; - if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon)) + if (IsBattlerSpriteVisible(battler) && IsValidForBattle(mon) && !gTestRunnerHeadless) { if (isShiny) { @@ -2768,4 +2769,3 @@ static void CB_CriticalCaptureThrownBallMovement(struct Sprite *sprite) sprite->callback = SpriteCB_Ball_Bounce_Step; } } - diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 19aeef3f4f..1f1953ea61 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -512,13 +512,57 @@ static inline bool32 IsAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 batt && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle; } +static inline bool32 IsDoubleAceSlot(u32 battler, u32 partyId) +{ + u32 partyCountEnd; + + if (!(gAiThinkingStruct->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON)) + return FALSE; + + partyCountEnd = CalculateEnemyPartyCountInSide(battler); + if (partyCountEnd == 0) + return FALSE; + + if (partyId == partyCountEnd - 1) + return TRUE; + if (partyCountEnd > 1 && partyId == partyCountEnd - 2) + return TRUE; + + return FALSE; +} + static inline bool32 IsDoubleAcePokemon(u32 chosenMonId, u32 pokemonInBattle, u32 battler) { - return gAiThinkingStruct->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON - && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 1) - && (chosenMonId == CalculateEnemyPartyCountInSide(battler) - 2) - && CountAIAliveNonEggMonsExcept(PARTY_SIZE) != pokemonInBattle - && CountAIAliveNonEggMonsExcept(PARTY_SIZE-1) != pokemonInBattle; + s32 battler1, battler2, firstId, lastId; + s32 i; + + if (!IsDoubleAceSlot(battler, chosenMonId)) + return FALSE; + + if (!IsDoubleBattle()) + { + battler2 = battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + } + else + { + battler1 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + battler2 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + + GetAIPartyIndexes(battler, &firstId, &lastId); + for (i = firstId; i < lastId; i++) + { + if (!IsValidForBattle(&gEnemyParty[i]) + || i == gBattlerPartyIndexes[battler1] + || i == gBattlerPartyIndexes[battler2] + || i == chosenMonId) + continue; + + if (!IsAcePokemon(i, pokemonInBattle, battler) && !IsDoubleAceSlot(battler, i)) + return TRUE; + } + + return FALSE; } static void OpponentHandleChoosePokemon(u32 battler) diff --git a/src/battle_controllers.c b/src/battle_controllers.c index f2880d31af..79828d065d 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -2578,7 +2578,7 @@ void BtlController_HandleStatusAnimation(u32 battler) void BtlController_HandleHitAnimation(u32 battler) { - if (gSprites[gBattlerSpriteIds[battler]].invisible == TRUE) + if (gSprites[gBattlerSpriteIds[battler]].invisible == TRUE || gTestRunnerHeadless) { BtlController_Complete(battler); } @@ -2593,6 +2593,11 @@ void BtlController_HandleHitAnimation(u32 battler) void BtlController_HandlePlaySE(u32 battler) { + if (gTestRunnerHeadless) + { + BtlController_Complete(battler); + return; + } s32 pan = IsOnPlayerSide(battler) ? SOUND_PAN_ATTACKER : SOUND_PAN_TARGET; PlaySE12WithPanning(gBattleResources->bufferA[battler][1] | (gBattleResources->bufferA[battler][2] << 8), pan); @@ -2601,6 +2606,11 @@ void BtlController_HandlePlaySE(u32 battler) void BtlController_HandlePlayFanfareOrBGM(u32 battler) { + if (gTestRunnerHeadless) + { + BtlController_Complete(battler); + return; + } if (gBattleResources->bufferA[battler][3]) { BattleStopLowHpSound(); @@ -2867,7 +2877,7 @@ void AnimateMonAfterPokeBallFail(u32 battler) { if (B_ANIMATE_MON_AFTER_FAILED_POKEBALL == FALSE) return; - + LaunchKOAnimation(battler, ReturnAnimIdForBattler(TRUE, battler), TRUE); TryShinyAnimation(gBattlerTarget, GetBattlerMon(gBattlerTarget)); } diff --git a/src/battle_end_turn.c b/src/battle_end_turn.c index d423659be9..62a8f67006 100644 --- a/src/battle_end_turn.c +++ b/src/battle_end_turn.c @@ -121,19 +121,9 @@ static bool32 HandleEndTurnOrder(u32 battler) gBattleTurnCounter++; gBattleStruct->endTurnEventsCounter++; - u32 i, j; - for (i = 0; i < gBattlersCount; i++) - { + for (u32 i = 0; i < gBattlersCount; i++) gBattlerByTurnOrder[i] = i; - } - for (i = 0; i < gBattlersCount - 1; i++) - { - for (j = i + 1; j < gBattlersCount; j++) - { - if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1) - SwapTurnOrder(i, j); - } - } + SortBattlersBySpeed(gBattlerByTurnOrder, FALSE); return effect; } diff --git a/src/battle_main.c b/src/battle_main.c index 16e0ad1ae1..2c18774f9c 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -4329,7 +4329,7 @@ static void HandleTurnActionSelectionState(void) case B_ACTION_SWITCH: gBattleStruct->battlerPartyIndexes[battler] = gBattlerPartyIndexes[battler]; if (gBattleTypeFlags & BATTLE_TYPE_ARENA - || !CanBattlerEscape(battler)) + || (!CanBattlerEscape(battler) && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SHED_SHELL)) { BtlController_EmitChoosePokemon(battler, B_COMM_TO_CONTROLLER, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, 0, gBattleStruct->battlerPartyOrders[battler]); } @@ -5152,7 +5152,7 @@ static void TurnValuesCleanUp(bool8 var0) gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; - gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller + gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceler ClearPursuitValues(); ClearDamageCalcResults(); } diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index face6eeb08..d8c8e32e91 100755 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1040,31 +1040,15 @@ u32 NumFaintedBattlersByAttacker(u32 battlerAtk) return numMonsFainted; } -bool32 IsMovePowderBlocked(u32 battlerAtk, u32 battlerDef, u32 move) +bool32 IsPowderMoveBlocked(u32 battlerAtk, u32 battlerDef, u32 move) { - bool32 effect = FALSE; + if (!IsPowderMove(move) + || battlerAtk == battlerDef + || IsAffectedByPowderMove(battlerDef, GetBattlerAbility(battlerDef), GetBattlerHoldEffect(battlerDef, TRUE))) + return FALSE; - if (IsPowderMove(move) && (battlerAtk != battlerDef)) - { - if (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 - && (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || GetBattlerAbility(battlerDef) == ABILITY_OVERCOAT)) - { - gBattlerAbility = battlerDef; - RecordAbilityBattle(gBattlerTarget, ABILITY_OVERCOAT); - effect = TRUE; - } - else if (GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_SAFETY_GOGGLES) - { - RecordItemEffectBattle(battlerDef, HOLD_EFFECT_SAFETY_GOGGLES); - gLastUsedItem = gBattleMons[battlerDef].item; - effect = TRUE; - } - - if (effect) - gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; - } - - return effect; + gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; + return TRUE; } bool32 EmergencyExitCanBeTriggered(u32 battler) @@ -1113,7 +1097,7 @@ static void Cmd_attackcanceler(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; return; } - if (AtkCanceller_MoveSuccessOrder() != MOVE_STEP_SUCCESS) + if (AtkCanceler_MoveSuccessOrder() != MOVE_STEP_SUCCESS) return; if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_OFF @@ -1151,7 +1135,7 @@ static void Cmd_attackcanceler(void) return; } - if (IsMovePowderBlocked(gBattlerAttacker, gBattlerTarget, gCurrentMove)) + if (IsPowderMoveBlocked(gBattlerAttacker, gBattlerTarget, gCurrentMove)) return; if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE @@ -1178,12 +1162,31 @@ static void Cmd_attackcanceler(void) gBattlescriptCurrInstr = BattleScript_FailedFromAtkString; if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].volatiles.multipleTurns)) - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); return; } u32 isBounceable = MoveCanBeBouncedBack(gCurrentMove); - if (gProtectStructs[gBattlerTarget].bounceMove + bool32 bounceActive = (gProtectStructs[gBattlerTarget].bounceMove && IsBattlerAlive(gBattlerTarget)); + + if (!bounceActive + && !gBattleStruct->bouncedMoveIsUsed + && isBounceable + && GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) == MOVE_TARGET_OPPONENTS_FIELD) + { + u32 partner = BATTLE_PARTNER(gBattlerTarget); + + if (partner < gBattlersCount + && GetBattlerSide(partner) == GetBattlerSide(gBattlerTarget) + && gProtectStructs[partner].bounceMove + && IsBattlerAlive(partner)) + { + gBattlerTarget = partner; + bounceActive = TRUE; + } + } + + if (bounceActive && isBounceable && !gBattleStruct->bouncedMoveIsUsed) { @@ -1191,7 +1194,7 @@ static void Cmd_attackcanceler(void) // Edge case for bouncing a powder move against a grass type pokemon. ClearDamageCalcResults(); - SetAtkCancellerForCalledMove(); + SetAtkCancelerForCalledMove(); gEffectBattler = gBattlerTarget; if (BlocksPrankster(gCurrentMove, gBattlerTarget, gBattlerAttacker, TRUE)) { @@ -1225,7 +1228,7 @@ static void Cmd_attackcanceler(void) if (gBattleStruct->bouncedMoveIsUsed) { ClearDamageCalcResults(); - SetAtkCancellerForCalledMove(); // Edge case for bouncing a powder move against a grass type pokemon. + SetAtkCancelerForCalledMove(); // Edge case for bouncing a powder move against a grass type pokemon. BattleScriptCall(BattleScript_MagicBounce); gBattlerAbility = battler; return; @@ -1278,7 +1281,7 @@ static void Cmd_attackcanceler(void) { if (!CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), gCurrentMove)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; gLastLandedMoves[gBattlerTarget] = 0; gLastHitByType[gBattlerTarget] = 0; @@ -1840,7 +1843,7 @@ static void Cmd_typecalc(void) { CMD_ARGS(); - if (!IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove))) // Handled in CANCELLER_MULTI_TARGET_MOVES for Spread Moves + if (!IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove))) // Handled in CANCELER_MULTI_TARGET_MOVES for Spread Moves { struct DamageContext ctx = {0}; ctx.battlerAtk = gBattlerAttacker; @@ -2225,6 +2228,10 @@ static void Cmd_attackanimation(void) gBattleMons[gBattlerAttacker].friendship, &gDisableStructs[gBattlerAttacker], multihit); +#if T_SHOULD_RUN_MOVE_ANIM + gCountAllocs = TRUE; + gSpriteAllocs = 0; +#endif gBattleScripting.animTurn++; gBattleScripting.animTargetsHit++; MarkBattlerForControllerExec(gBattlerAttacker); @@ -2243,7 +2250,12 @@ static void Cmd_waitanimation(void) CMD_ARGS(); if (gBattleControllerExecFlags == 0 && gBattleStruct->battlerKOAnimsRunning == 0) + { +#if T_SHOULD_RUN_MOVE_ANIM + gCountAllocs = FALSE; +#endif gBattlescriptCurrInstr = cmd->nextInstr; + } } static void DoublesHPBarReduction(void) @@ -6310,9 +6322,10 @@ static void Cmd_moveend(void) // Set ShellTrap to activate after the attacker's turn if target was hit by a physical move. if (GetMoveEffect(gChosenMoveByBattler[gBattlerTarget]) == EFFECT_SHELL_TRAP + && IsBattleMovePhysical(gCurrentMove) + && IsBattlerTurnDamaged(gBattlerTarget) && gBattlerTarget != gBattlerAttacker && !IsBattlerAlly(gBattlerTarget, gBattlerAttacker) - && gProtectStructs[gBattlerTarget].physicalDmg && gProtectStructs[gBattlerTarget].physicalBattlerId == gBattlerAttacker && !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) { @@ -6448,7 +6461,6 @@ static void Cmd_moveend(void) gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = nextTarget; // Fix for moxie spread moves gBattleScripting.moveendState = 0; MoveValuesCleanUp(); - gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect; if (moveEffect == EFFECT_EXPLOSION || moveEffect == EFFECT_MISTY_EXPLOSION // Edge case for Explosion not changing targets || moveEffect == EFFECT_SYNCHRONOISE) // So we don't go back to the Synchronoise script @@ -6494,7 +6506,7 @@ static void Cmd_moveend(void) if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gMultiHitCounter - && !(moveEffect == EFFECT_PRESENT && gBattleStruct->presentBasePower == 0)) // Silly edge case + && !(moveEffect == EFFECT_PRESENT && gBattleStruct->presentBasePower == 0)) // Parental Bond edge case { gMultiHitCounter--; if (!IsBattlerAlive(gBattlerTarget) && moveEffect != EFFECT_DRAGON_DARTS) @@ -6503,7 +6515,9 @@ static void Cmd_moveend(void) gBattleScripting.multihitString[4]++; if (gMultiHitCounter == 0) { - if (GetMoveEffectArg_MoveProperty(gCurrentMove) == MOVE_EFFECT_SCALE_SHOT && !NoAliveMonsForEitherParty()) + if (moveEffect == EFFECT_MULTI_HIT + && GetMoveEffectArg_MoveProperty(gCurrentMove) == MOVE_EFFECT_SCALE_SHOT + && !NoAliveMonsForEitherParty()) BattleScriptCall(BattleScript_ScaleShot); else BattleScriptCall(BattleScript_MultiHitPrintStrings); @@ -7419,7 +7433,7 @@ static void Cmd_jumpifcantswitch(void) CMD_ARGS(u8 battler:7, u8 ignoreEscapePrevention:1, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (!cmd->ignoreEscapePrevention && !CanBattlerEscape(battler)) + if (!cmd->ignoreEscapePrevention && !CanBattlerEscape(battler) && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_SHED_SHELL) { gBattlescriptCurrInstr = cmd->jumpInstr; } @@ -8517,9 +8531,9 @@ static void Cmd_hidepartystatussummary(void) static void ResetValuesForCalledMove(void) { if (gBattlerByTurnOrder[gCurrentTurnActionNumber] != gBattlerAttacker) - gBattleStruct->atkCancellerTracker = 0; + gBattleStruct->atkCancelerTracker = 0; else - SetAtkCancellerForCalledMove(); + SetAtkCancelerForCalledMove(); gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; SetTypeBeforeUsingMove(gCurrentMove, gBattlerAttacker); @@ -11522,17 +11536,26 @@ static void Cmd_trysetencore(void) } if ((IsMoveEncoreBanned(gLastMoves[gBattlerTarget])) + || i == MAX_MON_MOVES || gLastMoves[gBattlerTarget] == MOVE_NONE - || gLastMoves[gBattlerTarget] == MOVE_UNAVAILABLE) + || gLastMoves[gBattlerTarget] == MOVE_UNAVAILABLE + || gBattleMons[gBattlerTarget].pp[i] == 0 + || gDisableStructs[gBattlerTarget].encoredMove != MOVE_NONE + || GetMoveEffect(gChosenMoveByBattler[gBattlerTarget]) == EFFECT_SHELL_TRAP) { - i = MAX_MON_MOVES; + gBattlescriptCurrInstr = cmd->failInstr; } - - if (gDisableStructs[gBattlerTarget].encoredMove == MOVE_NONE - && i != MAX_MON_MOVES && gBattleMons[gBattlerTarget].pp[i] != 0) + else { gDisableStructs[gBattlerTarget].encoredMove = gBattleMons[gBattlerTarget].moves[i]; gDisableStructs[gBattlerTarget].encoredMovePos = i; + + // If the target's selected move is not the same as the move being Encored into, + // the target will select a random opposing target + // Redirection such as Follow Me is already covered in HandleAction_UseMove of battle_util.c + if (gDisableStructs[gBattlerTarget].encoredMove != GetChosenMoveFromPosition(gBattlerTarget)) + gBattleStruct->moveTarget[gBattlerTarget] = SetRandomTarget(gBattlerTarget); + // Encore always lasts 3 turns, but we need to account for a scenario where Encore changes the move during the same turn. if (HasBattlerActedThisTurn(gBattlerTarget)) gDisableStructs[gBattlerTarget].encoreTimer = 4; @@ -11540,10 +11563,6 @@ static void Cmd_trysetencore(void) gDisableStructs[gBattlerTarget].encoreTimer = 3; gBattlescriptCurrInstr = cmd->nextInstr; } - else - { - gBattlescriptCurrInstr = cmd->failInstr; - } } static void Cmd_painsplitdmgcalc(void) @@ -14285,13 +14304,16 @@ static void Cmd_displaydexinfo(void) { CMD_ARGS(); - struct Pokemon *mon = GetBattlerMon(GetCatchingBattler()); + u32 caughtBattler = GetCatchingBattler(); + struct Pokemon *mon = GetBattlerMon(caughtBattler); u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); switch (gBattleCommunication[0]) { case 0: BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK); + ClearTemporarySpeciesSpriteData(caughtBattler, FALSE, FALSE); + BattleLoadMonSpriteGfx(mon, caughtBattler); gBattleCommunication[0]++; break; case 1: @@ -18295,7 +18317,7 @@ void BS_JumpIfAbilityPreventsRest(void) NATIVE_ARGS(u8 battler, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); u32 ability = GetBattlerAbility(battler); - if (B_LEAF_GUARD_PREVENTS_REST >= GEN_5 && IsLeafGuardProtected(battler, ability)) + if (GetGenConfig(GEN_CONFIG_LEAF_GUARD_PREVENTS_REST) >= GEN_5 && IsLeafGuardProtected(battler, ability)) gBattlescriptCurrInstr = cmd->jumpInstr; else if (IsShieldsDownProtected(battler, ability)) gBattlescriptCurrInstr = cmd->jumpInstr; diff --git a/src/battle_tv.c b/src/battle_tv.c index 6504a3cc43..2fc8fad7b7 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -1267,6 +1267,7 @@ static void TrySetBattleSeminarShow(void) ctx.isCrit = FALSE; ctx.randomFactor = FALSE; ctx.updateFlags = FALSE; + ctx.isSelfInflicted = FALSE; ctx.fixedBasePower = powerOverride; gBattleStruct->moveDamage[gBattlerTarget] = CalculateMoveDamage(&ctx); dmgByMove[i] = gBattleStruct->moveDamage[gBattlerTarget]; diff --git a/src/battle_util.c b/src/battle_util.c index f6a61ffde4..696efdea4d 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -310,7 +310,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) if (effect == EFFECT_PURSUIT && IsPursuitTargetSet()) return FALSE; - if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) + if (gSideTimers[defSide].followmePowder && !IsAffectedByPowderMove(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) return FALSE; return TRUE; @@ -390,12 +390,11 @@ void HandleAction_UseMove(void) return; } - gBattleStruct->atkCancellerTracker = 0; + gBattleStruct->atkCancelerTracker = 0; ClearDamageCalcResults(); gMultiHitCounter = 0; gBattleScripting.savedDmg = 0; gBattleCommunication[MISS_TYPE] = 0; - gBattleScripting.savedMoveEffect = 0; gCurrMovePos = gChosenMovePos = gBattleStruct->chosenMovePositions[gBattlerAttacker]; // choose move @@ -734,7 +733,9 @@ void HandleAction_Run(void) } else { - if (!CanBattlerEscape(gBattlerAttacker)) + if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_CAN_ALWAYS_RUN + && GetBattlerAbility(gBattlerAttacker) != ABILITY_RUN_AWAY + && !CanBattlerEscape(gBattlerAttacker)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ATTACKER_CANT_ESCAPE; gBattlescriptCurrInstr = BattleScript_PrintFailedToRunString; @@ -1077,7 +1078,7 @@ const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState) // Set confused status gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2; - if (skyDropState == SKY_DROP_ATTACKCANCELLER_CHECK) + if (skyDropState == SKY_DROP_ATTACKCANCELER_CHECK) { gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET; } @@ -1893,13 +1894,13 @@ static inline bool32 TryActivatePowderStatus(u32 move) return FALSE; } -void SetAtkCancellerForCalledMove(void) +void SetAtkCancelerForCalledMove(void) { - gBattleStruct->atkCancellerTracker = CANCELLER_VOLATILE_BLOCKED; + gBattleStruct->atkCancelerTracker = CANCELER_VOLATILE_BLOCKED; gBattleStruct->isAtkCancelerForCalledMove = TRUE; } -static enum MoveCanceller CancellerFlags(void) +static enum MoveCanceler CancelerFlags(void) { gBattleMons[gBattlerAttacker].volatiles.destinyBond = FALSE; gBattleMons[gBattlerAttacker].volatiles.grudge = FALSE; @@ -1907,14 +1908,14 @@ static enum MoveCanceller CancellerFlags(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerStanceChangeOne(void) +static enum MoveCanceler CancelerStanceChangeOne(void) { if (B_STANCE_CHANGE_FAIL < GEN_7 && TryFormChangeBeforeMove()) return MOVE_STEP_BREAK; return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerSkyDrop(void) +static enum MoveCanceler CancelerSkyDrop(void) { // If Pokemon is being held in Sky Drop if (gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable == STATE_SKY_DROP) @@ -1926,11 +1927,11 @@ static enum MoveCanceller CancellerSkyDrop(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerRecharge(void) +static enum MoveCanceler CancelerRecharge(void) { if (gDisableStructs[gBattlerAttacker].rechargeTimer > 0) { - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -1938,7 +1939,7 @@ static enum MoveCanceller CancellerRecharge(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerAsleepOrFrozen(void) +static enum MoveCanceler CancelerAsleepOrFrozen(void) { if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) { @@ -2003,7 +2004,7 @@ static enum MoveCanceller CancellerAsleepOrFrozen(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerObedience(void) +static enum MoveCanceler CancelerObedience(void) { enum Obedience obedienceResult = GetAttackerObedienceForAction(); if (!(gHitMarker & HITMARKER_NO_PPDEDUCT) // Don't check obedience after first hit of multi target move or multi hit moves @@ -2030,6 +2031,7 @@ static enum MoveCanceller CancellerObedience(void) ctx.isCrit = FALSE; ctx.randomFactor = FALSE; ctx.updateFlags = TRUE; + ctx.isSelfInflicted = TRUE; ctx.fixedBasePower = 40; gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&ctx); gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself; @@ -2048,7 +2050,7 @@ static enum MoveCanceller CancellerObedience(void) break; case DISOBEYS_RANDOM_MOVE: gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - SetAtkCancellerForCalledMove(); + SetAtkCancelerForCalledMove(); gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gHitMarker |= HITMARKER_OBEYS; @@ -2060,11 +2062,11 @@ static enum MoveCanceller CancellerObedience(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerTruant(void) +static enum MoveCanceler CancelerTruant(void) { if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter) { - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING; gBattlerAbility = gBattlerAttacker; @@ -2075,12 +2077,12 @@ static enum MoveCanceller CancellerTruant(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerFlinch(void) +static enum MoveCanceler CancelerFlinch(void) { if (gBattleMons[gBattlerAttacker].volatiles.flinched) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2088,13 +2090,13 @@ static enum MoveCanceller CancellerFlinch(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerDisabled(void) +static enum MoveCanceler CancelerDisabled(void) { if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].disabledMove == gCurrentMove && gDisableStructs[gBattlerAttacker].disabledMove != MOVE_NONE) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2102,13 +2104,13 @@ static enum MoveCanceller CancellerDisabled(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerVolatileBlocked(void) +static enum MoveCanceler CancelerVolatileBlocked(void) { if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gBattleMons[gBattlerAttacker].volatiles.healBlock && IsHealBlockPreventingMove(gBattlerAttacker, gCurrentMove)) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2117,7 +2119,7 @@ static enum MoveCanceller CancellerVolatileBlocked(void) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; gBattleScripting.battler = gBattlerAttacker; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2125,7 +2127,7 @@ static enum MoveCanceller CancellerVolatileBlocked(void) else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer > gBattleTurnCounter && IsSoundMove(gCurrentMove)) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2133,12 +2135,12 @@ static enum MoveCanceller CancellerVolatileBlocked(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerTaunted(void) +static enum MoveCanceler CancelerTaunted(void) { if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IsBattleMoveStatus(gCurrentMove)) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2146,12 +2148,12 @@ static enum MoveCanceller CancellerTaunted(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerImprisoned(void) +static enum MoveCanceler CancelerImprisoned(void) { if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove)) { gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2159,7 +2161,7 @@ static enum MoveCanceller CancellerImprisoned(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerConfused(void) +static enum MoveCanceler CancelerConfused(void) { if (gBattleStruct->isAtkCancelerForCalledMove) return MOVE_STEP_SUCCESS; @@ -2182,6 +2184,7 @@ static enum MoveCanceller CancellerConfused(void) ctx.isCrit = FALSE; ctx.randomFactor = FALSE; ctx.updateFlags = TRUE; + ctx.isSelfInflicted = TRUE; ctx.fixedBasePower = 40; gBattleStruct->moveDamage[gBattlerAttacker] = CalculateMoveDamage(&ctx); gProtectStructs[gBattlerAttacker].confusionSelfDmg = TRUE; @@ -2203,7 +2206,7 @@ static enum MoveCanceller CancellerConfused(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerParalysed(void) +static enum MoveCanceler CancelerParalysed(void) { if (!gBattleStruct->isAtkCancelerForCalledMove && (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) @@ -2212,7 +2215,7 @@ static enum MoveCanceller CancellerParalysed(void) { gProtectStructs[gBattlerAttacker].nonVolatileStatusImmobility = TRUE; // This is removed in FRLG and Emerald for some reason - //CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + //CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2220,7 +2223,7 @@ static enum MoveCanceller CancellerParalysed(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerInfatuation(void) +static enum MoveCanceler CancelerInfatuation(void) { if (!gBattleStruct->isAtkCancelerForCalledMove && gBattleMons[gBattlerAttacker].volatiles.infatuation) { @@ -2234,7 +2237,7 @@ static enum MoveCanceller CancellerInfatuation(void) BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gProtectStructs[gBattlerAttacker].unableToUseMove = TRUE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove; } return MOVE_STEP_BREAK; @@ -2242,7 +2245,7 @@ static enum MoveCanceller CancellerInfatuation(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerBide(void) +static enum MoveCanceler CancelerBide(void) { if (gBattleMons[gBattlerAttacker].volatiles.bideTurns) { @@ -2272,7 +2275,7 @@ static enum MoveCanceller CancellerBide(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerThaw(void) +static enum MoveCanceler CancelerThaw(void) { if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE) { @@ -2297,14 +2300,14 @@ static enum MoveCanceller CancellerThaw(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerStanceChangeTwo(void) +static enum MoveCanceler CancelerStanceChangeTwo(void) { if (B_STANCE_CHANGE_FAIL >= GEN_7 && !gBattleStruct->isAtkCancelerForCalledMove && TryFormChangeBeforeMove()) return MOVE_STEP_BREAK; return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerChoiceLock(void) +static enum MoveCanceler CancelerChoiceLock(void) { u16 *choicedMoveAtk = &gBattleStruct->choicedMove[gBattlerAttacker]; enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); @@ -2327,9 +2330,9 @@ static enum MoveCanceller CancellerChoiceLock(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerWeatherPrimal(void) +static enum MoveCanceler CancelerWeatherPrimal(void) { - enum MoveCanceller effect = MOVE_STEP_SUCCESS; + enum MoveCanceler effect = MOVE_STEP_SUCCESS; if (HasWeatherEffect() && GetMovePower(gCurrentMove) > 0) { u32 moveType = GetBattleMoveType(gCurrentMove); @@ -2347,7 +2350,7 @@ static enum MoveCanceller CancellerWeatherPrimal(void) { gBattleScripting.moveEffect = MOVE_EFFECT_NONE; gProtectStructs[gBattlerAttacker].chargingTurn = FALSE; - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; BattleScriptCall(BattleScript_PrimalWeatherBlocksMove); } @@ -2355,7 +2358,7 @@ static enum MoveCanceller CancellerWeatherPrimal(void) return effect; } -static enum MoveCanceller CancellerDynamaxBlocked(void) +static enum MoveCanceler CancelerDynamaxBlocked(void) { if ((GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) && IsMoveBlockedByDynamax(gCurrentMove)) { @@ -2366,7 +2369,7 @@ static enum MoveCanceller CancellerDynamaxBlocked(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerPowderStatus(void) +static enum MoveCanceler CancelerPowderStatus(void) { if (TryActivatePowderStatus(gCurrentMove)) { @@ -2383,7 +2386,7 @@ static enum MoveCanceller CancellerPowderStatus(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerProtean(void) +static enum MoveCanceler CancelerProtean(void) { u32 moveType = GetBattleMoveType(gCurrentMove); if (ProteanTryChangeType(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), gCurrentMove, moveType)) @@ -2400,7 +2403,7 @@ static enum MoveCanceller CancellerProtean(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerPsychicTerrain(void) +static enum MoveCanceler CancelerPsychicTerrain(void) { if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_PSYCHIC_TERRAIN) && GetChosenMovePriority(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker)) > 0 @@ -2408,7 +2411,7 @@ static enum MoveCanceller CancellerPsychicTerrain(void) && GetMoveTarget(gCurrentMove) != MOVE_TARGET_OPPONENTS_FIELD && !IsBattlerAlly(gBattlerAttacker, gBattlerTarget)) { - CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK); + CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK); gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents; gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; return MOVE_STEP_BREAK; @@ -2416,7 +2419,7 @@ static enum MoveCanceller CancellerPsychicTerrain(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerExplodingDamp(void) +static enum MoveCanceler CancelerExplodingDamp(void) { u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); if (dampBattler && IsMoveDampBanned(gCurrentMove)) @@ -2429,7 +2432,7 @@ static enum MoveCanceller CancellerExplodingDamp(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerMultihitMoves(void) +static enum MoveCanceler CancelerMultihitMoves(void) { if (GetMoveEffect(gCurrentMove) == EFFECT_MULTI_HIT) { @@ -2501,7 +2504,7 @@ static enum MoveCanceller CancellerMultihitMoves(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerZMoves(void) +static enum MoveCanceler CancelerZMoves(void) { if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) { @@ -2533,7 +2536,7 @@ static enum MoveCanceller CancellerZMoves(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller CancellerMultiTargetMoves(void) +static enum MoveCanceler CancelerMultiTargetMoves(void) { u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); @@ -2581,46 +2584,46 @@ static enum MoveCanceller CancellerMultiTargetMoves(void) return MOVE_STEP_SUCCESS; } -static enum MoveCanceller (*const sMoveSuccessOrderCancellers[])(void) = +static enum MoveCanceler (*const sMoveSuccessOrderCancelers[])(void) = { - [CANCELLER_FLAGS] = CancellerFlags, - [CANCELLER_STANCE_CHANGE_1] = CancellerStanceChangeOne, - [CANCELLER_SKY_DROP] = CancellerSkyDrop, - [CANCELLER_RECHARGE] = CancellerRecharge, - [CANCELLER_ASLEEP_OR_FROZEN] = CancellerAsleepOrFrozen, - [CANCELLER_OBEDIENCE] = CancellerObedience, - [CANCELLER_TRUANT] = CancellerTruant, - [CANCELLER_FLINCH] = CancellerFlinch, - [CANCELLER_INFATUATION] = CancellerInfatuation, - [CANCELLER_DISABLED] = CancellerDisabled, - [CANCELLER_VOLATILE_BLOCKED] = CancellerVolatileBlocked, - [CANCELLER_TAUNTED] = CancellerTaunted, - [CANCELLER_IMPRISONED] = CancellerImprisoned, - [CANCELLER_CONFUSED] = CancellerConfused, - [CANCELLER_PARALYSED] = CancellerParalysed, - [CANCELLER_BIDE] = CancellerBide, - [CANCELLER_THAW] = CancellerThaw, - [CANCELLER_STANCE_CHANGE_2] = CancellerStanceChangeTwo, - [CANCELLER_CHOICE_LOCK] = CancellerChoiceLock, - [CANCELLER_WEATHER_PRIMAL] = CancellerWeatherPrimal, - [CANCELLER_DYNAMAX_BLOCKED] = CancellerDynamaxBlocked, - [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, + [CANCELER_FLAGS] = CancelerFlags, + [CANCELER_STANCE_CHANGE_1] = CancelerStanceChangeOne, + [CANCELER_SKY_DROP] = CancelerSkyDrop, + [CANCELER_RECHARGE] = CancelerRecharge, + [CANCELER_ASLEEP_OR_FROZEN] = CancelerAsleepOrFrozen, + [CANCELER_OBEDIENCE] = CancelerObedience, + [CANCELER_TRUANT] = CancelerTruant, + [CANCELER_FLINCH] = CancelerFlinch, + [CANCELER_INFATUATION] = CancelerInfatuation, + [CANCELER_DISABLED] = CancelerDisabled, + [CANCELER_VOLATILE_BLOCKED] = CancelerVolatileBlocked, + [CANCELER_TAUNTED] = CancelerTaunted, + [CANCELER_IMPRISONED] = CancelerImprisoned, + [CANCELER_CONFUSED] = CancelerConfused, + [CANCELER_PARALYSED] = CancelerParalysed, + [CANCELER_BIDE] = CancelerBide, + [CANCELER_THAW] = CancelerThaw, + [CANCELER_STANCE_CHANGE_2] = CancelerStanceChangeTwo, + [CANCELER_CHOICE_LOCK] = CancelerChoiceLock, + [CANCELER_WEATHER_PRIMAL] = CancelerWeatherPrimal, + [CANCELER_DYNAMAX_BLOCKED] = CancelerDynamaxBlocked, + [CANCELER_POWDER_STATUS] = CancelerPowderStatus, + [CANCELER_PROTEAN] = CancelerProtean, + [CANCELER_PSYCHIC_TERRAIN] = CancelerPsychicTerrain, + [CANCELER_EXPLODING_DAMP] = CancelerExplodingDamp, + [CANCELER_MULTIHIT_MOVES] = CancelerMultihitMoves, + [CANCELER_Z_MOVES] = CancelerZMoves, + [CANCELER_MULTI_TARGET_MOVES] = CancelerMultiTargetMoves, }; -enum MoveCanceller AtkCanceller_MoveSuccessOrder(void) +enum MoveCanceler AtkCanceler_MoveSuccessOrder(void) { - enum MoveCanceller effect = MOVE_STEP_SUCCESS; + enum MoveCanceler effect = MOVE_STEP_SUCCESS; - while (gBattleStruct->atkCancellerTracker < CANCELLER_END && effect == MOVE_STEP_SUCCESS) + while (gBattleStruct->atkCancelerTracker < CANCELER_END && effect == MOVE_STEP_SUCCESS) { - effect = sMoveSuccessOrderCancellers[gBattleStruct->atkCancellerTracker](); - gBattleStruct->atkCancellerTracker++; + effect = sMoveSuccessOrderCancelers[gBattleStruct->atkCancelerTracker](); + gBattleStruct->atkCancelerTracker++; } if (effect == MOVE_STEP_REMOVES_STATUS) @@ -3061,7 +3064,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a && !(IsBattleMoveStatus(move) && (abilityDef == ABILITY_MAGIC_BOUNCE || gProtectStructs[battlerDef].bounceMove))) { if (option == RUN_SCRIPT && !IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, move))) - CancelMultiTurnMoves(battlerAtk, SKY_DROP_ATTACKCANCELLER_CHECK); // Don't cancel moves that can hit two targets bc one target might not be protected + CancelMultiTurnMoves(battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK); // Don't cancel moves that can hit two targets bc one target might not be protected battleScriptBlocksMove = BattleScript_DoesntAffectTargetAtkString; } @@ -4689,9 +4692,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_EFFECT_SPORE: { u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); - if ((GetGenConfig(GEN_CONFIG_POWDER_GRASS) < GEN_6 || !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS)) - && abilityAtk != ABILITY_OVERCOAT - && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_SAFETY_GOGGLES) + enum ItemHoldEffect holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); + if (IsAffectedByPowderMove(gBattlerAttacker, abilityAtk, holdEffectAtk)) { u32 poison, paralysis, sleep; @@ -4718,7 +4720,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && IsBattlerTurnDamaged(gBattlerTarget) && CanBeSlept(gBattlerTarget, gBattlerAttacker, abilityAtk, NOT_BLOCKED_BY_SLEEP_CLAUSE) - && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerAttacker), GetBattlerHoldEffect(gBattlerAttacker, TRUE), move)) + && !CanBattlerAvoidContactEffects(gBattlerAttacker, gBattlerTarget, abilityAtk, holdEffectAtk, move)) { if (IsSleepClauseEnabled()) gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; @@ -5448,8 +5450,6 @@ bool32 CanBattlerEscape(u32 battler) // no ability check { if (gBattleStruct->battlerState[battler].commanderSpecies != SPECIES_NONE) return FALSE; - else if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_SHED_SHELL) - return TRUE; else if (B_GHOSTS_ESCAPE >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return TRUE; else if (gBattleMons[battler].volatiles.escapePrevention) @@ -8501,6 +8501,24 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageContext *ctx) return uq4_12_multiply_by_int_half_down(modifier, basePower); } +static inline uq4_12_t ApplyOffensiveBadgeBoost(uq4_12_t modifier, u32 battler, u32 move) +{ + if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_ATTACK, battler) && IsBattleMovePhysical(move)) + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); + if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPATK, battler) && IsBattleMoveSpecial(move)) + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); + return modifier; +} + +static inline uq4_12_t ApplyDefensiveBadgeBoost(uq4_12_t modifier, u32 battler, u32 move) +{ + if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_DEFENSE, battler) && IsBattleMovePhysical(move)) + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); + if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPDEF, battler) && IsBattleMoveSpecial(move)) + modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); + return modifier; +} + static inline u32 CalcAttackStat(struct DamageContext *ctx) { u8 atkStage; @@ -8572,6 +8590,9 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) // apply attack stat modifiers modifier = UQ_4_12(1.0); + if (ctx->isSelfInflicted) + return uq4_12_multiply_by_int_half_down(ApplyOffensiveBadgeBoost(modifier, battlerAtk, move), atkStat); + // attacker's abilities switch (ctx->abilityAtk) { @@ -8766,11 +8787,7 @@ static inline u32 CalcAttackStat(struct DamageContext *ctx) break; } - // The offensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the corresponding flags set (eg. Badges) - if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_ATTACK, battlerAtk) && IsBattleMovePhysical(move)) - modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); - if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPATK, battlerAtk) && IsBattleMoveSpecial(move)) - modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); + modifier = ApplyOffensiveBadgeBoost(modifier, battlerAtk, move); return uq4_12_multiply_by_int_half_down(modifier, atkStat); } @@ -8855,6 +8872,9 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) // apply defense stat modifiers modifier = UQ_4_12(1.0); + if (ctx->isSelfInflicted) + return uq4_12_multiply_by_int_half_down(ApplyDefensiveBadgeBoost(modifier, battlerDef, move), defStat); + // target's abilities switch (ctx->abilityDef) { @@ -8944,11 +8964,7 @@ static inline u32 CalcDefenseStat(struct DamageContext *ctx) if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ICE) && IsBattlerWeatherAffected(battlerDef, B_WEATHER_SNOW) && usesDefStat) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); - // The defensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the corresponding flags set (eg. Badges) - if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_DEFENSE, battlerDef) && IsBattleMovePhysical(move)) - modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); - if (ShouldGetStatBadgeBoost(B_FLAG_BADGE_BOOST_SPDEF, battlerDef) && IsBattleMoveSpecial(move)) - modifier = uq4_12_multiply_half_down(modifier, GetBadgeBoostModifier()); + modifier = ApplyDefensiveBadgeBoost(modifier, battlerDef, move); return uq4_12_multiply_by_int_half_down(modifier, defStat); } @@ -11487,9 +11503,9 @@ bool32 IsAnyTargetAffected(u32 battlerAtk) void UpdateStallMons(void) { - if (IsBattlerTurnDamaged(gBattlerTarget) || IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) || gMovesInfo[gCurrentMove].category == DAMAGE_CATEGORY_STATUS) + if (IsBattlerTurnDamaged(gBattlerTarget) || IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) || GetMoveCategory(gCurrentMove) == DAMAGE_CATEGORY_STATUS) return; - if (!IsDoubleBattle() || gMovesInfo[gCurrentMove].target == MOVE_TARGET_SELECTED) + if (!IsDoubleBattle() || GetMoveTarget(gCurrentMove) == MOVE_TARGET_SELECTED) { u32 moveType = GetBattleMoveType(gCurrentMove); // Probably doesn't handle dynamic move types right now u32 abilityAtk = GetBattlerAbility(gBattlerAttacker); @@ -11965,3 +11981,12 @@ static bool32 IsOpposingSideEmpty(u32 battler) return FALSE; return TRUE; } + +bool32 IsAffectedByPowderMove(u32 battler, u32 ability, enum ItemHoldEffect holdEffect) +{ + if ((GetGenConfig(GEN_CONFIG_POWDER_OVERCOAT) >= GEN_6 && ability == ABILITY_OVERCOAT) + || (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS)) + || holdEffect == HOLD_EFFECT_SAFETY_GOGGLES) + return FALSE; + return TRUE; +} diff --git a/src/data/battle_anim.h b/src/data/battle_anim.h index 236c7f6dfd..2ee7f4f1b5 100644 --- a/src/data/battle_anim.h +++ b/src/data/battle_anim.h @@ -2031,6 +2031,7 @@ const struct BattleAnimBackground gBattleAnimBackgroundTable[] = [BG_STEEL_BEAM_OPPONENT] = {gBattleAnimBgImage_Highspeed, gBattleAnimBgPalette_SteelBeam, gBattleAnimBgTilemap_HighspeedOpponent}, [BG_STEEL_BEAM_PLAYER] = {gBattleAnimBgImage_Highspeed, gBattleAnimBgPalette_SteelBeam, gBattleAnimBgTilemap_HighspeedPlayer}, [BG_CHLOROBLAST] = {gBattleAnimBgImage_HydroCannon, gBattleAnimBgPalette_Chloroblast, gBattleAnimBgTilemap_HydroCannon}, - [BG_RAINBOW] = {gBattleAnimBgImage_Rainbow, gBattleAnimBGPalette_Rainbow, gBattleAnimBgTilemap_Rainbow}, + [BG_RAINBOW_PLAYER] = {gBattleAnimBgImage_RainbowPlayer, gBattleAnimBGPalette_Rainbow, gBattleAnimBgTilemap_RainbowPlayer}, + [BG_RAINBOW_OPPONENT] = {gBattleAnimBgImage_RainbowOpponent, gBattleAnimBGPalette_Rainbow, gBattleAnimBgTilemap_RainbowOpponent}, [BG_SWAMP] = {gBattleAnimBgImage_Swamp, gBattleAnimBGPalette_Swamp, gBattleAnimBgTilemap_Swamp}, }; diff --git a/src/decompress_error_handler.c b/src/decompress_error_handler.c index 74e28e3ca1..ff332618ff 100644 --- a/src/decompress_error_handler.c +++ b/src/decompress_error_handler.c @@ -47,14 +47,14 @@ static const struct BgTemplate sBgTemplates[3] = }, }; -static void DecompressErrorScreenTextPrint(const u8 *text, u8 x, u8 y) +static void DecompressErrorScreenTextPrint(u32 window, const u8 *text, u8 x, u8 y) { u8 color[3]; color[0] = TEXT_COLOR_TRANSPARENT; color[1] = TEXT_DYNAMIC_COLOR_6; color[2] = TEXT_COLOR_LIGHT_GRAY; - AddTextPrinterParameterized4(0, FONT_NORMAL, x * 8, y * 8 + 1, 0, 0, color, 0, text); + AddTextPrinterParameterized4(window, FONT_NORMAL, x * 8, y * 8 + 1, 0, 0, color, 0, text); } static void GetHexStringFromU32(u8 *str, u32 value) @@ -121,20 +121,19 @@ static void GetHexStringFromU32(u8 *str, u32 value) } } +static const struct WindowTemplate sTextWin = +{ + .bg = 0, + .tilemapLeft = 3, + .tilemapTop = 2, + .width = 24, + .height = 16, + .paletteNum = 15, + .baseBlock = 1, +}; + void DecompressionError_CB2(void) { - static const struct WindowTemplate textWin[] = - { - { - .bg = 0, - .tilemapLeft = 3, - .tilemapTop = 2, - .width = 24, - .height = 16, - .paletteNum = 15, - .baseBlock = 1, - } - }; if (sErrorAddress == 0) return; @@ -159,20 +158,20 @@ void DecompressionError_CB2(void) ResetPaletteFade(); LoadPalette(gTextWindowFrame1_Pal, 0xE0, 0x20); LoadPalette(gStandardMenuPalette, 0xF0, 0x20); - InitWindows(textWin); - DrawStdFrameWithCustomTileAndPalette(0, TRUE, 0x214, 0xE); + u32 window = AddWindow(&sTextWin); + DrawStdFrameWithCustomTileAndPalette(window, TRUE, 0x214, 0xE); static const u8 romCheckFailMessage[] =_( "{COLOR RED}ERROR! {COLOR DARK_GRAY}Decompression Failed!\n" "\n" "Address:\n" "Error:\n"); - DecompressErrorScreenTextPrint(romCheckFailMessage, 1, 0); + DecompressErrorScreenTextPrint(window, romCheckFailMessage, 1, 0); u8 addressStr[11]; u8 errorStr[11]; GetHexStringFromU32(addressStr, sErrorAddress); GetHexStringFromU32(errorStr, sCompressionError); - DecompressErrorScreenTextPrint(addressStr, 7, 4); - DecompressErrorScreenTextPrint(errorStr, 7, 6); + DecompressErrorScreenTextPrint(window, addressStr, 7, 4); + DecompressErrorScreenTextPrint(window, errorStr, 7, 6); TransferPlttBuffer(); *(u16*)PLTT = RGB(17, 18, 31); ShowBg(0); diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 0c17f5c445..8fdd7057b4 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -2627,37 +2627,29 @@ void UpdateLightSprite(struct Sprite *sprite) return; } - // Note: Don't set window registers during hardware fade! - switch (sprite->sLightType) + if (sprite->sLightType == LIGHT_TYPE_BALL) { - default: - case LIGHT_TYPE_BALL: if (gPaletteFade.active) // if palette fade is active, don't flicker since the timer won't be updated { - Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY); sprite->invisible = FALSE; } else if (gPlayerAvatar.tileTransitionState) { - Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY); // As long as the second coefficient stays 12, shadows will not change sprite->invisible = FALSE; if (GetSpritePaletteTagByPaletteNum(sprite->oam.paletteNum) == OBJ_EVENT_PAL_TAG_LIGHT_2) LoadSpritePaletteInSlot(&sObjectEventSpritePalettes[FindObjectEventPaletteIndexByTag(OBJ_EVENT_PAL_TAG_LIGHT)], sprite->oam.paletteNum); } else if ((sprite->invisible = gTimeUpdateCounter & 1)) { - Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY); sprite->invisible = FALSE; if (GetSpritePaletteTagByPaletteNum(sprite->oam.paletteNum) == OBJ_EVENT_PAL_TAG_LIGHT_2) LoadSpritePaletteInSlot(&sObjectEventSpritePalettes[FindObjectEventPaletteIndexByTag(OBJ_EVENT_PAL_TAG_LIGHT)], sprite->oam.paletteNum); } - break; - case LIGHT_TYPE_PKMN_CENTER_SIGN: - case LIGHT_TYPE_POKE_MART_SIGN: - Weather_SetBlendCoeffs(12, BASE_SHADOW_INTENSITY); + } else { sprite->invisible = FALSE; - break; } + // Note: Don't set window registers during hardware fade! + Weather_SetBlendCoeffs(7, BASE_SHADOW_INTENSITY); } // Spawn a light at a map coordinate diff --git a/src/faraway_island.c b/src/faraway_island.c index e275bcfa37..67acf5cc6d 100755 --- a/src/faraway_island.c +++ b/src/faraway_island.c @@ -393,6 +393,7 @@ void SetMewAboveGrass(void) LoadSpritePalette(&gSpritePalette_GeneralFieldEffect1); UpdateSpritePaletteWithWeather(IndexOfSpritePaletteTag(gSpritePalette_GeneralFieldEffect1.tag), FALSE); + gSprites[mew->spriteId].subspriteTableNum = 1; x = mew->currentCoords.x; y = mew->currentCoords.y; diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index bb9723443d..aaf28a6dea 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -2774,7 +2774,6 @@ bool8 ObjectMovingOnRockStairs(struct ObjectEvent *objectEvent, u8 direction) s16 x = objectEvent->currentCoords.x; s16 y = objectEvent->currentCoords.y; - // TODO followers on sideways stairs if (IsFollowerVisible() && GetFollowerObject() != NULL && (objectEvent->isPlayer || objectEvent->localId == OBJ_EVENT_ID_FOLLOWER)) return FALSE; diff --git a/src/follower_npc.c b/src/follower_npc.c index 8bc3a61697..1833d555ab 100644 --- a/src/follower_npc.c +++ b/src/follower_npc.c @@ -954,6 +954,10 @@ u32 DetermineFollowerNPCState(struct ObjectEvent *follower, u32 state, u32 direc RETURN_STATE(MOVEMENT_ACTION_WALK_NORMAL_DOWN, direction); + // Slow stairs. + case MOVEMENT_ACTION_WALK_SLOW_STAIRS_DOWN ... MOVEMENT_ACTION_WALK_SLOW_STAIRS_RIGHT: + RETURN_STATE(MOVEMENT_ACTION_WALK_SLOW_STAIRS_DOWN, direction); + default: return MOVEMENT_INVALID; } diff --git a/src/graphics.c b/src/graphics.c index 925e232dbe..013c2d2b85 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -1673,9 +1673,11 @@ const u32 gBattleAnimSpriteGfx_WhiteShadow[] = INCBIN_U32("graphics/battle_anims const u16 gBattleAnimSpritePal_WhiteShadow[] = INCBIN_U16("graphics/battle_anims/sprites/white_shadow.gbapal"); // Pledge Effect field status - Rainbow -const u32 gBattleAnimBgImage_Rainbow[] = INCBIN_U32("graphics/battle_anims/backgrounds/rainbow.4bpp.smol"); -const u16 gBattleAnimBGPalette_Rainbow[] = INCBIN_U16("graphics/battle_anims/backgrounds/rainbow.gbapal"); -const u32 gBattleAnimBgTilemap_Rainbow[] = INCBIN_U32("graphics/battle_anims/backgrounds/rainbow.bin.smolTM"); +const u32 gBattleAnimBgImage_RainbowPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/rainbow_player_tile.4bpp.smol"); +const u32 gBattleAnimBgImage_RainbowOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/rainbow_opponent_tile.4bpp.smol"); +const u16 gBattleAnimBGPalette_Rainbow[] = INCBIN_U16("graphics/battle_anims/backgrounds/rainbow_player_tile.gbapal"); +const u32 gBattleAnimBgTilemap_RainbowPlayer[] = INCBIN_U32("graphics/battle_anims/backgrounds/rainbow_player_tile.bin.smolTM"); +const u32 gBattleAnimBgTilemap_RainbowOpponent[] = INCBIN_U32("graphics/battle_anims/backgrounds/rainbow_opponent_tile.bin.smolTM"); // Pledge Effect field status - Swamp const u32 gBattleAnimBgImage_Swamp[] = INCBIN_U32("graphics/battle_anims/backgrounds/swampswizzle.4bpp.smol"); diff --git a/src/item_menu.c b/src/item_menu.c index e0f7d156b3..f999b31480 100755 --- a/src/item_menu.c +++ b/src/item_menu.c @@ -2916,8 +2916,8 @@ static s32 CompareItemsAlphabetically(enum Pocket pocketId, struct ItemSlot item if (pocketId == POCKET_TM_HM) { - name1 = gMovesInfo[GetTMHMMoveId(GetItemTMHMIndex(item1.itemId))].name; - name2 = gMovesInfo[GetTMHMMoveId(GetItemTMHMIndex(item2.itemId))].name; + name1 = GetMoveName(GetTMHMMoveId(GetItemTMHMIndex(item1.itemId))); + name2 = GetMoveName(GetTMHMMoveId(GetItemTMHMIndex(item2.itemId))); } else { diff --git a/src/item_use.c b/src/item_use.c index 90b89b6778..9fc4176949 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -1254,7 +1254,7 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon) switch (battleUsage) { case EFFECT_ITEM_INCREASE_STAT: - if (gBattleMons[gBattlerInMenuId].statStages[GetItemEffect(itemId)[1]] == MAX_STAT_STAGE) + if (CompareStat(gBattlerInMenuId, GetItemEffect(itemId)[1], MAX_STAT_STAGE, CMP_EQUAL, GetBattlerAbility(gBattlerInMenuId))) cannotUse = TRUE; break; case EFFECT_ITEM_SET_FOCUS_ENERGY: @@ -1293,11 +1293,12 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon) case EFFECT_ITEM_INCREASE_ALL_STATS: { u32 ability = GetBattlerAbility(gBattlerInMenuId); + cannotUse = TRUE; for (i = STAT_ATK; i < NUM_STATS; i++) { - if (CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL, ability)) + if (!CompareStat(gBattlerInMenuId, i, MAX_STAT_STAGE, CMP_EQUAL, ability)) { - cannotUse = TRUE; + cannotUse = FALSE; break; } } diff --git a/src/line_break.c b/src/line_break.c index a4dd6475af..bb601a0d76 100644 --- a/src/line_break.c +++ b/src/line_break.c @@ -176,7 +176,6 @@ void BreakSubStringNaive(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum Free(allWords); } -#undef SCROLL_PROMPT_WIDTH void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, enum ToggleScrollPrompt toggleScrollPrompt) { @@ -246,6 +245,9 @@ void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, for (u32 i = 1; i < numWords; i++) totalWidth += allWords[i].width + spaceWidth; + if (toggleScrollPrompt == SHOW_SCROLL_PROMPT) + totalWidth += SCROLL_PROMPT_WIDTH; + // If it doesn't fit on 1 line, do fancy line break calculation // NOTE: Currently the line break calculation isn't fancy if (totalWidth > maxWidth) @@ -256,6 +258,8 @@ void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, bool32 shouldTryAgain; for (currWordIndex = 0; currWordIndex < numWords; currWordIndex++) { + if (toggleScrollPrompt == SHOW_SCROLL_PROMPT && currWordIndex + 1 == numWords) + currLineWidth += SCROLL_PROMPT_WIDTH; if (currLineWidth + allWords[currWordIndex].length > maxWidth) { totalLines++; @@ -266,6 +270,10 @@ void BreakSubStringAutomatic(u8 *src, u32 maxWidth, u32 screenLines, u8 fontId, currLineWidth += allWords[currWordIndex].width + spaceWidth; } } + + if (currLineWidth > maxWidth) + totalLines++; + // LINE LAYOUT STARTS HERE struct StringLine *stringLines; do @@ -424,3 +432,4 @@ bool32 StringHasManualBreaks(u8 *src) } return FALSE; } +#undef SCROLL_PROMPT_WIDTH diff --git a/src/mirage_tower.c b/src/mirage_tower.c index e2ed74a21a..bf73692a36 100644 --- a/src/mirage_tower.c +++ b/src/mirage_tower.c @@ -202,7 +202,7 @@ static const struct OamData sOamData_CeilingCrumbleSmall = static const struct SpriteTemplate sSpriteTemplate_CeilingCrumbleSmall = { .tileTag = TAG_CEILING_CRUMBLE, - .paletteTag = TAG_NONE, + .paletteTag = TAG_CEILING_CRUMBLE, .oam = &sOamData_CeilingCrumbleSmall, .anims = sAnims_CeilingCrumbleSmall, .images = NULL, @@ -241,7 +241,7 @@ static const struct OamData sOamData_CeilingCrumbleLarge = static const struct SpriteTemplate sSpriteTemplate_CeilingCrumbleLarge = { .tileTag = TAG_CEILING_CRUMBLE, - .paletteTag = TAG_NONE, + .paletteTag = TAG_CEILING_CRUMBLE, .oam = &sOamData_CeilingCrumbleLarge, .anims = sAnims_CeilingCrumbleLarge, .images = NULL, @@ -420,6 +420,7 @@ static void IncrementCeilingCrumbleFinishedCount(void) void DoMirageTowerCeilingCrumble(void) { + LoadSpritePaletteWithTag(sMirageTowerCrumbles_Palette, TAG_CEILING_CRUMBLE); LoadSpriteSheets(sCeilingCrumbleSpriteSheets); CreateCeilingCrumbleSprites(); CreateTask(WaitCeilingCrumble, 8); @@ -454,17 +455,12 @@ static void CreateCeilingCrumbleSprites(void) { spriteId = CreateSprite(&sSpriteTemplate_CeilingCrumbleLarge, sCeilingCrumblePositions[i][0] + 120, sCeilingCrumblePositions[i][1], 8); gSprites[spriteId].oam.priority = 0; - // These sprites use color index 11 from the player's sprite palette. This probably wasn't intentional. - // The palettes for Brendan and May have different shades of green at this index, so the color of these sprites changes - // depending on the player's gender (and neither shade of green particularly fits a crumbling yellow/brown ceiling). - gSprites[spriteId].oam.paletteNum = PALSLOT_PLAYER; gSprites[spriteId].sIndex = i; } for (i = 0; i < ARRAY_COUNT(sCeilingCrumblePositions); i++) { spriteId = CreateSprite(&sSpriteTemplate_CeilingCrumbleSmall, sCeilingCrumblePositions[i][0] + 115, sCeilingCrumblePositions[i][1] - 3, 8); gSprites[spriteId].oam.priority = 0; - gSprites[spriteId].oam.paletteNum = PALSLOT_PLAYER; gSprites[spriteId].sIndex = i; } } diff --git a/src/party_menu.c b/src/party_menu.c index e9455692bb..5e3bd4629e 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -6300,6 +6300,7 @@ static void DeleteInvalidFusionMoves(struct Pokemon *mon, u32 species) } } +#if P_FUSION_FORMS static void SwapFusionMonMoves(struct Pokemon *mon, const u16 moveTable[][2], u32 mode) { u32 oldMoveIndex, newMoveIndex; @@ -6320,13 +6321,16 @@ static void SwapFusionMonMoves(struct Pokemon *mon, const u16 moveTable[][2], u3 { if (move == moveTable[j][oldMoveIndex]) { + u32 pp = GetMovePP(moveTable[j][newMoveIndex]); SetMonData(mon, MON_DATA_MOVE1 + i, &moveTable[j][newMoveIndex]); - SetMonData(mon, MON_DATA_PP1 + i, &gMovesInfo[moveTable[j][newMoveIndex]].pp); + SetMonData(mon, MON_DATA_PP1 + i, &pp); } } } } +#endif //P_FUSION_FORMS + static void Task_TryItemUseFusionChange(u8 taskId) { struct Pokemon *mon = &gPlayerParty[gTasks[taskId].firstFusionSlot]; @@ -6420,6 +6424,7 @@ static void Task_TryItemUseFusionChange(u8 taskId) { if (gTasks[taskId].fusionType == FUSE_MON) { +#if P_FUSION_FORMS #if P_FAMILY_KYUREM #if P_FAMILY_RESHIRAM if (gTasks[taskId].tExtraMoveHandling == SWAP_EXTRA_MOVES_KYUREM_WHITE) @@ -6430,11 +6435,13 @@ static void Task_TryItemUseFusionChange(u8 taskId) SwapFusionMonMoves(mon, gKyuremBlackSwapMoveTable, FUSE_MON); #endif //P_FAMILY_ZEKROM #endif //P_FAMILY_KYUREM +#endif //P_FUSION_FORMS if (gTasks[taskId].moveToLearn != 0) FormChangeTeachMove(taskId, gTasks[taskId].moveToLearn, gTasks[taskId].firstFusionSlot); } else //(gTasks[taskId].fusionType == UNFUSE_MON) { +#if P_FUSION_FORMS #if P_FAMILY_KYUREM #if P_FAMILY_RESHIRAM if (gTasks[taskId].tExtraMoveHandling == SWAP_EXTRA_MOVES_KYUREM_WHITE) @@ -6445,6 +6452,7 @@ static void Task_TryItemUseFusionChange(u8 taskId) SwapFusionMonMoves(mon, gKyuremBlackSwapMoveTable, UNFUSE_MON); #endif //P_FAMILY_ZEKROM #endif //P_FAMILY_KYUREM +#endif //P_FUSION_FORMS if ( gTasks[taskId].tExtraMoveHandling == FORGET_EXTRA_MOVES) { DeleteInvalidFusionMoves(mon, gTasks[taskId].fusionResult); diff --git a/src/pokeball.c b/src/pokeball.c index 5b32aa7e1d..2b36072e60 100644 --- a/src/pokeball.c +++ b/src/pokeball.c @@ -11,6 +11,7 @@ #include "sprite.h" #include "task.h" #include "trig.h" +#include "test_runner.h" #include "util.h" #include "data.h" #include "item.h" @@ -597,8 +598,8 @@ static void Task_DoPokeballSendOutAnim(u8 taskId) { u32 throwCaseId, ballId, battler, ballSpriteId; bool32 notSendOut = FALSE; - u32 throwXoffset = (B_ENEMY_THROW_BALLS >= GEN_6) ? 24 : 0; - s32 throwYoffset = (B_ENEMY_THROW_BALLS >= GEN_6) ? -16 : 24; + u32 throwXoffset = (B_ENEMY_THROW_BALLS >= GEN_6 && !gTestRunnerHeadless) ? 24 : 0; + s32 throwYoffset = (B_ENEMY_THROW_BALLS >= GEN_6 && !gTestRunnerHeadless) ? -16 : 24; if (gTasks[taskId].tFrames == 0) { @@ -675,7 +676,7 @@ static inline void DoPokeballSendOutSoundEffect(u32 battler) static inline void *GetOpponentMonSendOutCallback(void) { - return (B_ENEMY_THROW_BALLS >= GEN_6) ? SpriteCB_MonSendOut_1 : SpriteCB_OpponentMonSendOut; + return (B_ENEMY_THROW_BALLS >= GEN_6 && !gTestRunnerHeadless) ? SpriteCB_MonSendOut_1 : SpriteCB_OpponentMonSendOut; } // This sequence of functions is very similar to those that get run when @@ -1205,7 +1206,7 @@ static void SpriteCB_MonSendOut_2(struct Sprite *sprite) u32 r7; bool32 rightPosition = (IsBattlerPlayer(sprite->sBattler)) ? B_POSITION_PLAYER_RIGHT : B_POSITION_OPPONENT_RIGHT; - if (HIBYTE(sprite->data[7]) >= 35 && HIBYTE(sprite->data[7]) < 80) + if (HIBYTE(sprite->data[7]) >= 35 && HIBYTE(sprite->data[7]) < 80 && !gTestRunnerHeadless) { s16 r4; @@ -1246,7 +1247,8 @@ static void SpriteCB_MonSendOut_2(struct Sprite *sprite) sprite->data[0] = 0; if (IsDoubleBattle() && gBattleSpritesDataPtr->animationData->introAnimActive - && sprite->sBattler == GetBattlerAtPosition(rightPosition)) + && sprite->sBattler == GetBattlerAtPosition(rightPosition) + && !gTestRunnerHeadless) sprite->callback = SpriteCB_ReleaseMon2FromBall; else sprite->callback = SpriteCB_ReleaseMonFromBall; @@ -1269,12 +1271,15 @@ static void SpriteCB_ReleaseMon2FromBall(struct Sprite *sprite) static void SpriteCB_OpponentMonSendOut(struct Sprite *sprite) { + if (gTestRunnerHeadless) + sprite->data[0] = 15; sprite->data[0]++; if (sprite->data[0] > 15) { sprite->data[0] = 0; if (IsDoubleBattle() && gBattleSpritesDataPtr->animationData->introAnimActive - && sprite->sBattler == GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)) + && sprite->sBattler == GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT) + && !gTestRunnerHeadless) sprite->callback = SpriteCB_ReleaseMon2FromBall; else sprite->callback = SpriteCB_ReleaseMonFromBall; @@ -1534,7 +1539,7 @@ void StartHealthboxSlideIn(u8 battler) healthboxSprite->y2 = -healthboxSprite->y2; } gSprites[healthboxSprite->data[5]].callback(&gSprites[healthboxSprite->data[5]]); - if (GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT) + if (GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT && !gTestRunnerHeadless) healthboxSprite->callback = SpriteCB_HealthboxSlideInDelayed; } diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index c88795693c..607ced5f47 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -4090,6 +4090,12 @@ static void UNUSED HighlightScreenSelectBarItem(u8 selectedScreen, u16 unused) #define tPersonalityLo data[14] #define tPersonalityHi data[15] +// Types palettes need to be loaded at a different slot than anticipated by gTypesInfo +// to avoid overlapping with caught mon sprite palette slot +// Normal type info palette slots: 13, 14 and 15 +// Caught mon palette slot: 15 +#define TYPE_INFO_PALETTE_NUM_OFFSET -1 + void Task_DisplayCaughtMonDexPageHGSS(u8 taskId) { u8 spriteId; @@ -4351,9 +4357,9 @@ static void SetTypeIconPosAndPal(u8 typeId, u8 x, u8 y, u8 spriteArrayId) sprite = &gSprites[sPokedexView->typeIconSpriteIds[spriteArrayId]]; StartSpriteAnim(sprite, typeId); if (typeId < NUMBER_OF_MON_TYPES) - sprite->oam.paletteNum = gTypesInfo[typeId].palette; + sprite->oam.paletteNum = gTypesInfo[typeId].palette + TYPE_INFO_PALETTE_NUM_OFFSET; else - sprite->oam.paletteNum = sContestCategoryToOamPaletteNum[typeId - NUMBER_OF_MON_TYPES]; + sprite->oam.paletteNum = sContestCategoryToOamPaletteNum[typeId - NUMBER_OF_MON_TYPES] + TYPE_INFO_PALETTE_NUM_OFFSET; sprite->x = x + 16; sprite->y = y + 8; SetSpriteInvisibility(spriteArrayId, FALSE); @@ -4394,7 +4400,8 @@ static void CreateTypeIconSprites(void) u8 i; LoadCompressedSpriteSheet(&gSpriteSheet_MoveTypes); - LoadPalette(gMoveTypes_Pal, 0x1D0, 0x60); + u32 paletteNum = gTypesInfo[TYPE_NORMAL].palette + TYPE_INFO_PALETTE_NUM_OFFSET; + LoadPalette(gMoveTypes_Pal, OBJ_PLTT_ID(paletteNum), 3 * PLTT_SIZE_4BPP); for (i = 0; i < 2; i++) { if (sPokedexView->typeIconSpriteIds[i] == 0xFF) @@ -4574,6 +4581,7 @@ static u16 CreateSizeScreenTrainerPic(u16 species, s16 x, s16 y, s8 paletteSlot) return CreateTrainerPicSprite(species, TRUE, x, y, paletteSlot, TAG_NONE); } +#undef TYPE_INFO_PALETTE_NUM_OFFSET //************************************ //* * diff --git a/src/pokemon.c b/src/pokemon.c index c356ac8a97..72b8832052 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2434,7 +2434,7 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) data[retVal++] = substruct0->nickname12; } } - else if (POKEMON_NAME_LENGTH >= 11) + else if (field != MON_DATA_NICKNAME10 && POKEMON_NAME_LENGTH >= 11) { if (substruct0->nickname11 == 0) { diff --git a/src/sound.c b/src/sound.c index 0eec129dde..80676a4920 100644 --- a/src/sound.c +++ b/src/sound.c @@ -34,6 +34,7 @@ static void Task_Fanfare(u8 taskId); static void CreateFanfareTask(void); static void RestoreBGMVolumeAfterPokemonCry(void); +// The 1st argument in the table is the length of the fanfare, measured in frames. This is calculated by taking the duration of the midi file, multiplying by 59.72750056960583, and rounding up to the next nearest integer. static const struct Fanfare sFanfares[] = { [FANFARE_LEVEL_UP] = { MUS_LEVEL_UP, 80 }, [FANFARE_OBTAIN_ITEM] = { MUS_OBTAIN_ITEM, 160 }, diff --git a/src/sprite.c b/src/sprite.c index 1b89a50be1..2df5e2760a 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -28,6 +28,8 @@ #if T_SHOULD_RUN_MOVE_ANIM EWRAM_DATA bool32 gLoadFail = FALSE; +EWRAM_DATA bool32 gCountAllocs = FALSE; +EWRAM_DATA s32 gSpriteAllocs = 0; #endif // T_SHOULD_RUN_MOVE_ANIM struct SpriteCopyRequest @@ -1501,6 +1503,10 @@ void LoadSpriteSheets(const struct SpriteSheet *sheets) void FreeSpriteTilesByTag(u16 tag) { +#if T_SHOULD_RUN_MOVE_ANIM + if (gCountAllocs) + gSpriteAllocs--; +#endif u8 index = IndexOfSpriteTileTag(tag); if (index != 0xFF) { @@ -1566,6 +1572,10 @@ u16 GetSpriteTileTagByTileStart(u16 start) void AllocSpriteTileRange(u16 tag, u16 start, u16 count) { +#if T_SHOULD_RUN_MOVE_ANIM + if (gCountAllocs) + gSpriteAllocs++; +#endif u8 freeIndex = IndexOfSpriteTileTag(TAG_NONE); sSpriteTileRangeTags[freeIndex] = tag; SET_SPRITE_TILE_RANGE(freeIndex, start, count); diff --git a/src/test_runner_stub.c b/src/test_runner_stub.c index 9a9452ed21..20aabe3d9a 100644 --- a/src/test_runner_stub.c +++ b/src/test_runner_stub.c @@ -7,5 +7,7 @@ const bool8 gTestRunnerEnabled = FALSE; // The Makefile patches gTestRunnerHeadless as part of make test. // This allows us to open the ROM in an mgba with a UI and see the // animations and messages play, which helps when debugging a test. +#if TESTING const bool8 gTestRunnerHeadless = FALSE; +#endif const bool8 gTestRunnerSkipIsFail = FALSE; diff --git a/src/trainer_see.c b/src/trainer_see.c index 2ec23dfa4f..348ec14c2d 100644 --- a/src/trainer_see.c +++ b/src/trainer_see.c @@ -474,7 +474,7 @@ static u8 CheckTrainer(u8 objectEventId) if (GetTrainerFlagFromScriptPointer(trainerBattlePtr)) { //If there is a rematch, we want to trigger the approach sequence - if (GetRematchFromScriptPointer(trainerBattlePtr)) + if (I_VS_SEEKER_CHARGING && GetRematchFromScriptPointer(trainerBattlePtr)) { trainerBattlePtr = NULL; numTrainers = 0xFF; diff --git a/src/vs_seeker.c b/src/vs_seeker.c index 1fcf5fdfcc..d9e4497421 100644 --- a/src/vs_seeker.c +++ b/src/vs_seeker.c @@ -725,6 +725,7 @@ static u16 GetTrainerFlagFromScript(const u8 *script) trainerFlag |= script[1] << 8; break; case SCR_OP_CALLNATIVE: + { u32 callnativeFunc = (((((script[4] << 8) + script[3]) << 8) + script[2]) << 8) + script[1]; if (callnativeFunc == ((u32)NativeVsSeekerRematchId | 0xA000000)) // | 0xA000000 corresponds to the request_effects=1 version of the function { @@ -737,6 +738,7 @@ static u16 GetTrainerFlagFromScript(const u8 *script) trainerFlag = TRAINER_NONE; } break; + } default: trainerFlag = TRAINER_NONE; break; diff --git a/test/battle/ability/aura_break.c b/test/battle/ability/aura_break.c index 389ab327b1..10c248c87d 100644 --- a/test/battle/ability/aura_break.c +++ b/test/battle/ability/aura_break.c @@ -5,62 +5,62 @@ DOUBLE_BATTLE_TEST("Aura Break inverts Fairy Aura's effect") { s16 damage[3]; - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } - } WHEN { - TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); } - TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); SWITCH(playerRight, 2); } - TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); SWITCH(opponentRight, 2); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[0]); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); SWITCH(playerRight, 2); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft); SWITCH(opponentRight, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[2]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); - } THEN { - EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); - EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[2]); - } + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[2]); + } } DOUBLE_BATTLE_TEST("Aura Break inverts Dark Aura's effect") { s16 damage[3]; - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } - } WHEN { - TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); } - TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); SWITCH(playerRight, 2); } - TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); SWITCH(opponentRight, 2); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[0]); + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); } + TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); SWITCH(playerRight, 2); } + TURN { MOVE(playerLeft, MOVE_BITE, target:opponentLeft); SWITCH(opponentRight, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[2]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); - } THEN { - EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); - EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[2]); - } + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[2]); + } } DOUBLE_BATTLE_TEST("Aura Break ignores Mold Breaker abilities") @@ -73,43 +73,43 @@ DOUBLE_BATTLE_TEST("Aura Break ignores Mold Breaker abilities") PARAMETRIZE { species = SPECIES_ZEKROM, ability = ABILITY_TERAVOLT; } PARAMETRIZE { species = SPECIES_RESHIRAM, ability = ABILITY_TURBOBLAZE; } - GIVEN { - PLAYER(species) { Ability(ability); Level(50); } - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } - PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } - } WHEN { - TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); } - TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); } - TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); SWITCH(playerRight, 2); } - TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); SWITCH(playerRight, 3); } - TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); SWITCH(playerRight, 2); SWITCH(opponentRight, 2); } - TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); SWITCH(playerRight, 3); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[0]); + GIVEN { + PLAYER(species) { Ability(ability); Level(50); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ZYGARDE_50) { Ability(ABILITY_AURA_BREAK); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); SWITCH(playerRight, 2); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); SWITCH(playerRight, 3); } + TURN { MOVE(playerLeft, MOVE_BITE, target: opponentLeft); SWITCH(playerRight, 2); SWITCH(opponentRight, 2); } + TURN { MOVE(playerLeft, MOVE_PLAY_ROUGH, target: opponentLeft); SWITCH(playerRight, 3); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[1]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[2]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[2]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[3]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[3]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[4]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[4]); - ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); - HP_BAR(opponentLeft, captureDamage: &damage[5]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[5]); } THEN { - EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[2]); - EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[4]); - EXPECT_MUL_EQ(damage[1], UQ_4_12(1.33), damage[3]); - EXPECT_MUL_EQ(damage[1], UQ_4_12(0.75), damage[5]); - } + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[2]); + EXPECT_MUL_EQ(damage[0], UQ_4_12(0.75), damage[4]); + EXPECT_MUL_EQ(damage[1], UQ_4_12(1.33), damage[3]); + EXPECT_MUL_EQ(damage[1], UQ_4_12(0.75), damage[5]); + } } diff --git a/test/battle/ability/bad_dreams.c b/test/battle/ability/bad_dreams.c index 491d5a91a2..cb724e2411 100644 --- a/test/battle/ability/bad_dreams.c +++ b/test/battle/ability/bad_dreams.c @@ -35,7 +35,21 @@ SINGLE_BATTLE_TEST("Bad Dreams causes the sleeping enemy Pokemon to lose 1/8 of } } -TO_DO_BATTLE_TEST("Bad Dreams affects Pokémon with Comatose") +SINGLE_BATTLE_TEST("Bad Dreams causes Pokémon with Comatose to lose 1/8 of HP") +{ + GIVEN { + PLAYER(SPECIES_DARKRAI); + OPPONENT(SPECIES_KOMALA) { Ability(ABILITY_COMATOSE); } + } WHEN { + TURN {;} + } SCENE { + ABILITY_POPUP(player, ABILITY_BAD_DREAMS); + MESSAGE("The opposing Komala is tormented!"); + HP_BAR(opponent); + } THEN { + EXPECT_EQ(opponent->hp, opponent->maxHP - opponent->maxHP / 8); + } +} DOUBLE_BATTLE_TEST("Bad Dreams does not activate if only the partner Pokemon is sleeping") { diff --git a/test/battle/ability/bulletproof.c b/test/battle/ability/bulletproof.c index 733eb63a11..37d59b468e 100644 --- a/test/battle/ability/bulletproof.c +++ b/test/battle/ability/bulletproof.c @@ -1,4 +1,20 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Bulletproof makes ballistic moves fail against the ability user"); +SINGLE_BATTLE_TEST("Bulletproof makes ballistic moves fail against the ability user") +{ + GIVEN { + ASSUME(IsBallisticMove(MOVE_ELECTRO_BALL)); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_CHESPIN) { Ability(ABILITY_BULLETPROOF); } + } WHEN { + TURN { MOVE(player, MOVE_ELECTRO_BALL); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_BULLETPROOF); + MESSAGE("The opposing Chespin's Bulletproof blocks Electro Ball!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_BALL, player); + HP_BAR(opponent); + } + } +} diff --git a/test/battle/ability/dark_aura.c b/test/battle/ability/dark_aura.c index eb1bf05246..1371975a28 100644 --- a/test/battle/ability/dark_aura.c +++ b/test/battle/ability/dark_aura.c @@ -1,4 +1,108 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Dark Aura (Ability) test titles") +DOUBLE_BATTLE_TEST("Dark Aura increases the power of all Dark-type attacks by 33%") +{ + s16 damage[8]; + + GIVEN { + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + PLAYER(SPECIES_LINOONE); + PLAYER(SPECIES_LINOONE); + OPPONENT(SPECIES_LINOONE); + OPPONENT(SPECIES_LINOONE); + } WHEN { + TURN { MOVE(playerRight, MOVE_SKILL_SWAP, target: playerLeft); } + TURN { SWITCH(playerLeft, 2); } + TURN { + MOVE(playerLeft, MOVE_BITE, target:opponentLeft, secondaryEffect:FALSE); + MOVE(playerRight, MOVE_BITE, target:opponentRight, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_BITE, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_BITE, target:playerRight, secondaryEffect:FALSE); + } + TURN { MOVE(opponentLeft, MOVE_GASTRO_ACID, target:playerRight); } + TURN { + MOVE(playerLeft, MOVE_BITE, target:opponentLeft, secondaryEffect:FALSE); + MOVE(playerRight, MOVE_BITE, target:opponentRight, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_BITE, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_BITE, target:playerRight, secondaryEffect:FALSE); + } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[2]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentRight); + HP_BAR(playerRight, captureDamage: &damage[3]); + + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponentLeft); + + // Turn 3 + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[4]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[5]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[6]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentRight); + HP_BAR(playerRight, captureDamage: &damage[7]); + } THEN { + EXPECT_MUL_EQ(damage[4], UQ_4_12(1.33), damage[0]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(1.33), damage[1]); + EXPECT_MUL_EQ(damage[6], UQ_4_12(1.33), damage[2]); + EXPECT_MUL_EQ(damage[7], UQ_4_12(1.33), damage[3]); + } +} + +DOUBLE_BATTLE_TEST("Dark Aura's effect doesn't stack multiple times") +{ + s16 damage[6]; + + GIVEN { + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + PLAYER(SPECIES_WOBBUFFET) { HP(9999); MaxHP(9999); } + PLAYER(SPECIES_YVELTAL) { Ability(ABILITY_DARK_AURA); } + OPPONENT(SPECIES_WOBBUFFET) { HP(9999); MaxHP(9999); } + OPPONENT(SPECIES_WOBBUFFET) { HP(9999); MaxHP(9999); } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_BITE, target:opponentLeft, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_BITE, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_BITE, target:playerLeft, secondaryEffect:FALSE); + } + TURN { SWITCH(playerRight, 2); } + TURN { + MOVE(playerLeft, MOVE_BITE, target:opponentLeft, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_BITE, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_BITE, target:playerLeft, secondaryEffect:FALSE); + } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentRight); + HP_BAR(playerLeft, captureDamage: &damage[2]); + + // Turn 2 + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Yveltal"); + + // Turn 3 + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[3]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[4]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BITE, opponentRight); + HP_BAR(playerLeft, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[3], damage[0]); + EXPECT_EQ(damage[4], damage[1]); + EXPECT_EQ(damage[5], damage[2]); + } +} diff --git a/test/battle/ability/fairy_aura.c b/test/battle/ability/fairy_aura.c index 3b8d400b02..a51abf1be5 100644 --- a/test/battle/ability/fairy_aura.c +++ b/test/battle/ability/fairy_aura.c @@ -1,4 +1,108 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Fairy Aura (Ability) test titles") +DOUBLE_BATTLE_TEST("Fairy Aura increases the power of all Fairy-type attacks by 33%") +{ + s16 damage[8]; + + GIVEN { + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + PLAYER(SPECIES_LINOONE); + PLAYER(SPECIES_LINOONE); + OPPONENT(SPECIES_LINOONE); + OPPONENT(SPECIES_LINOONE); + } WHEN { + TURN { MOVE(playerRight, MOVE_SKILL_SWAP, target: playerLeft); } + TURN { SWITCH(playerLeft, 2); } + TURN { + MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft, secondaryEffect:FALSE); + MOVE(playerRight, MOVE_PLAY_ROUGH, target:opponentRight, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_PLAY_ROUGH, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_PLAY_ROUGH, target:playerRight, secondaryEffect:FALSE); + } + TURN { MOVE(opponentLeft, MOVE_GASTRO_ACID, target:playerRight); } + TURN { + MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft, secondaryEffect:FALSE); + MOVE(playerRight, MOVE_PLAY_ROUGH, target:opponentRight, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_PLAY_ROUGH, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_PLAY_ROUGH, target:playerRight, secondaryEffect:FALSE); + } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[2]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentRight); + HP_BAR(playerRight, captureDamage: &damage[3]); + + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_GASTRO_ACID, opponentLeft); + + // Turn 3 + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[4]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerRight); + HP_BAR(opponentRight, captureDamage: &damage[5]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[6]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentRight); + HP_BAR(playerRight, captureDamage: &damage[7]); + } THEN { + EXPECT_MUL_EQ(damage[4], UQ_4_12(1.33), damage[0]); + EXPECT_MUL_EQ(damage[5], UQ_4_12(1.33), damage[1]); + EXPECT_MUL_EQ(damage[6], UQ_4_12(1.33), damage[2]); + EXPECT_MUL_EQ(damage[7], UQ_4_12(1.33), damage[3]); + } +} + +DOUBLE_BATTLE_TEST("Fairy Aura's effect doesn't stack multiple times") +{ + s16 damage[6]; + + GIVEN { + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + PLAYER(SPECIES_WOBBUFFET) { HP(9999); MaxHP(9999); } + PLAYER(SPECIES_XERNEAS) { Ability(ABILITY_FAIRY_AURA); } + OPPONENT(SPECIES_WOBBUFFET) { HP(9999); MaxHP(9999); } + OPPONENT(SPECIES_WOBBUFFET) { HP(9999); MaxHP(9999); } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_PLAY_ROUGH, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_PLAY_ROUGH, target:playerLeft, secondaryEffect:FALSE); + } + TURN { SWITCH(playerRight, 2); } + TURN { + MOVE(playerLeft, MOVE_PLAY_ROUGH, target:opponentLeft, secondaryEffect:FALSE); + MOVE(opponentLeft, MOVE_PLAY_ROUGH, target:playerLeft, secondaryEffect:FALSE); + MOVE(opponentRight, MOVE_PLAY_ROUGH, target:playerLeft, secondaryEffect:FALSE); + } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[0]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[1]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentRight); + HP_BAR(playerLeft, captureDamage: &damage[2]); + + // Turn 2 + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Xerneas"); + + // Turn 3 + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, playerLeft); + HP_BAR(opponentLeft, captureDamage: &damage[3]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentLeft); + HP_BAR(playerLeft, captureDamage: &damage[4]); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PLAY_ROUGH, opponentRight); + HP_BAR(playerLeft, captureDamage: &damage[5]); + } THEN { + EXPECT_EQ(damage[3], damage[0]); + EXPECT_EQ(damage[4], damage[1]); + EXPECT_EQ(damage[5], damage[2]); + } +} diff --git a/test/battle/ability/filter.c b/test/battle/ability/filter.c index c9a742c48d..69c0e96278 100644 --- a/test/battle/ability/filter.c +++ b/test/battle/ability/filter.c @@ -9,7 +9,7 @@ SINGLE_BATTLE_TEST("Filter reduces damage to Super Effective moves by 0.75", s16 GIVEN { ASSUME(gSpeciesInfo[SPECIES_MR_MIME].types[0] == TYPE_PSYCHIC); ASSUME(gSpeciesInfo[SPECIES_MR_MIME].types[1] == TYPE_FAIRY); - ASSUME(gMovesInfo[MOVE_POISON_JAB].type == TYPE_POISON); + ASSUME(GetMoveType(MOVE_POISON_JAB) == TYPE_POISON); ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_FAIRY] > UQ_4_12(1.0)); ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_PSYCHIC] == UQ_4_12(1.0)); PLAYER(SPECIES_MR_MIME) { Ability(ability); } diff --git a/test/battle/ability/flare_boost.c b/test/battle/ability/flare_boost.c index a4ff14382a..54bd3b9d38 100644 --- a/test/battle/ability/flare_boost.c +++ b/test/battle/ability/flare_boost.c @@ -1,4 +1,21 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Flare Boost (Ability) test titles") +SINGLE_BATTLE_TEST("Flare Boost increases Sp. Attack by 50% when the Pokémon is burned", s16 damage) +{ + u32 status1; + PARAMETRIZE { status1 = STATUS1_NONE; } + PARAMETRIZE { status1 = STATUS1_BURN; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); + PLAYER(SPECIES_DRIFBLIM) { Ability(ABILITY_FLARE_BOOST); Status1(status1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SWIFT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWIFT, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} diff --git a/test/battle/ability/fur_coat.c b/test/battle/ability/fur_coat.c index 56fb197114..2ad6a3d5a2 100644 --- a/test/battle/ability/fur_coat.c +++ b/test/battle/ability/fur_coat.c @@ -1,4 +1,44 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Fur Coat (Ability) test titles") +ASSUMPTIONS +{ + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); +} + +SINGLE_BATTLE_TEST("Fur Coat doubles Defense", s16 damage) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_FUR_COAT; } + PARAMETRIZE { ability = ABILITY_RATTLED; } + + GIVEN { + PLAYER(SPECIES_PERSIAN_ALOLA) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Fur Coat has no effect on self-inflicted confusion damage", s16 damage) +{ + u32 ability; + PARAMETRIZE { ability = ABILITY_FUR_COAT; } + PARAMETRIZE { ability = ABILITY_RATTLED; } + + GIVEN { + PLAYER(SPECIES_PERSIAN_ALOLA) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_CONFUSE_RAY); MOVE(player, MOVE_POUND, WITH_RNG(RNG_CONFUSION, TRUE)); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CONFUSE_RAY, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} diff --git a/test/battle/ability/iron_fist.c b/test/battle/ability/iron_fist.c index ae26f9cdd0..360b3606be 100644 --- a/test/battle/ability/iron_fist.c +++ b/test/battle/ability/iron_fist.c @@ -1,4 +1,26 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Iron Fist (Ability) test titles") +SINGLE_BATTLE_TEST("Iron Fist increases the power of punching moves by 20%", s16 damage) +{ + u32 move, ability; + PARAMETRIZE { move = MOVE_BULLET_PUNCH; ability = ABILITY_IRON_FIST; } + PARAMETRIZE { move = MOVE_BULLET_PUNCH; ability = ABILITY_BLAZE; } + PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_IRON_FIST; } + PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_BLAZE; } + + GIVEN { + ASSUME(IsPunchingMove(MOVE_BULLET_PUNCH)); + ASSUME(!IsPunchingMove(MOVE_SCRATCH)); + ASSUME(GetMovePower(MOVE_BULLET_PUNCH) == GetMovePower(MOVE_SCRATCH)); + PLAYER(SPECIES_CHIMCHAR) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(1.2), results[0].damage); // Iron Fist affects punching moves + EXPECT_EQ(results[2].damage, results[3].damage); // Iron Fist does not affect non-punching moves + } +} diff --git a/test/battle/ability/leaf_guard.c b/test/battle/ability/leaf_guard.c index 94785bd29b..182f07787b 100644 --- a/test/battle/ability/leaf_guard.c +++ b/test/battle/ability/leaf_guard.c @@ -31,7 +31,41 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents non-volatile status conditions in sun") } } -TO_DO_BATTLE_TEST("Leaf Guard doesn't prevent non-volatile status conditions if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent non-volatile status conditions if Cloud Nine/Air Lock is on the field") +{ + u32 move, species, ability; + u16 status; + PARAMETRIZE { move = MOVE_WILL_O_WISP; status = STATUS1_BURN; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_HYPNOSIS; status = STATUS1_SLEEP; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; status = STATUS1_PARALYSIS; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { move = MOVE_WILL_O_WISP; status = STATUS1_BURN; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { move = MOVE_HYPNOSIS; status = STATUS1_SLEEP; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { move = MOVE_THUNDER_WAVE; status = STATUS1_PARALYSIS; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + // PARAMETRIZE { move = MOVE_POWDER_SNOW; status = STATUS1_FREEZE; } // Pointless since you can't freeze in sunlight anyway + GIVEN { + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_WILL_O_WISP) == MOVE_EFFECT_BURN); + ASSUME(GetMoveEffect(MOVE_HYPNOSIS) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_HYPNOSIS) == MOVE_EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_THUNDER_WAVE) == MOVE_EFFECT_PARALYSIS); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_TOXIC) == MOVE_EFFECT_TOXIC); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); MOVE(opponent, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + NONE_OF { + ABILITY_POPUP(player, ABILITY_LEAF_GUARD); + MESSAGE("It doesn't affect Leafeon…"); + } + STATUS_ICON(player, status); + } +} SINGLE_BATTLE_TEST("Leaf Guard prevents status conditions from Flame Orb and Toxic Orb") { @@ -50,29 +84,82 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents status conditions from Flame Orb and Tox NONE_OF { MESSAGE("Leafeon was burned!"); STATUS_ICON(player, burn: TRUE); } } else { - NONE_OF { MESSAGE("Leafeon was badly poisoned!"); STATUS_ICON(player, poison: TRUE); } + NONE_OF { MESSAGE("Leafeon was badly poisoned!"); STATUS_ICON(player, badPoison: TRUE); } } } } -TO_DO_BATTLE_TEST("Leaf Guard doesn't prevent status conditions from Flame Orb and Toxic Orb if Cloud Nine/Air Lock is on the field"); - -SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun") +SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent status conditions from Flame Orb and Toxic Orb if Cloud Nine/Air Lock is on the field") { + u32 item, species, ability; + PARAMETRIZE { item = ITEM_FLAME_ORB; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { item = ITEM_TOXIC_ORB; species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { item = ITEM_FLAME_ORB; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { item = ITEM_TOXIC_ORB; species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } GIVEN { - ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); + ASSUME(gItemsInfo[ITEM_FLAME_ORB].holdEffect == HOLD_EFFECT_FLAME_ORB); + ASSUME(gItemsInfo[ITEM_TOXIC_ORB].holdEffect == HOLD_EFFECT_TOXIC_ORB); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); Item(item); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_SUNNY_DAY); } + } SCENE { + if (item == ITEM_FLAME_ORB) { + MESSAGE("Leafeon was burned!"); + STATUS_ICON(player, burn: TRUE); + } + else { + MESSAGE("Leafeon was badly poisoned!"); + STATUS_ICON(player, badPoison: TRUE); + } + } +} + +SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun (Gen 5+)") +{ + u32 gen; + PARAMETRIZE { gen = GEN_4; } + PARAMETRIZE { gen = GEN_5; } + GIVEN { + WITH_CONFIG(GEN_CONFIG_LEAF_GUARD_PREVENTS_REST, gen); ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } } SCENE { - MESSAGE("But it failed!"); - NONE_OF { + if (gen >= GEN_5) { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + STATUS_ICON(player, sleep: TRUE); + HP_BAR(player); + } + } + else { STATUS_ICON(player, sleep: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); HP_BAR(player); } } } -TO_DO_BATTLE_TEST("Leaf Guard doesn't prevent Rest if Cloud Nine/Air Lock is on the field"); +SINGLE_BATTLE_TEST("Leaf Guard doesn't prevent Rest if Cloud Nine/Air Lock is on the field") +{ + u32 species, ability; + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_GOLDUCK; ability = ABILITY_CLOUD_NINE; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } + GIVEN { + WITH_CONFIG(GEN_CONFIG_LEAF_GUARD_PREVENTS_REST, GEN_5); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); + PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); } + OPPONENT(species) { Ability(ability); } + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } + } SCENE { + STATUS_ICON(player, sleep: TRUE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); + HP_BAR(player); + } +} diff --git a/test/battle/ability/libero.c b/test/battle/ability/libero.c index 8ea93df3c0..b2ebf5cd5b 100644 --- a/test/battle/ability/libero.c +++ b/test/battle/ability/libero.c @@ -1,4 +1,4 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Libero (Ability) test titles") +// Tests for Libero are handled in test/battle/ability/protean.c diff --git a/test/battle/ability/magic_bounce.c b/test/battle/ability/magic_bounce.c index 56c9a32332..9ef36de4af 100644 --- a/test/battle/ability/magic_bounce.c +++ b/test/battle/ability/magic_bounce.c @@ -42,6 +42,7 @@ SINGLE_BATTLE_TEST("Magic Bounce bounces back powder moves") SINGLE_BATTLE_TEST("Magic Bounce cannot bounce back powder moves against Grass Types") { GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); ASSUME(IsPowderMove(MOVE_STUN_SPORE)); ASSUME(GetSpeciesType(SPECIES_ODDISH, 0) == TYPE_GRASS); PLAYER(SPECIES_ODDISH); diff --git a/test/battle/ability/mold_breaker.c b/test/battle/ability/mold_breaker.c index 2c04deeeef..fb6f9d11ab 100644 --- a/test/battle/ability/mold_breaker.c +++ b/test/battle/ability/mold_breaker.c @@ -1,4 +1,22 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Mold Breaker (Ability) test titles") +SINGLE_BATTLE_TEST("Mold Breaker cancels damage reduction from Ice Scales", s16 damage) +{ + u16 ability; + PARAMETRIZE { ability = ABILITY_SHADOW_TAG; } + PARAMETRIZE { ability = ABILITY_MOLD_BREAKER; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_PSYCHIC) == DAMAGE_CATEGORY_SPECIAL); + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_FROSMOTH) { Ability(ABILITY_ICE_SCALES); } + } WHEN { + TURN { MOVE(player, MOVE_PSYCHIC); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, UQ_4_12(0.5), results[0].damage); + } +} + +TO_DO_BATTLE_TEST("TODO: Write more Mold Breaker (Ability) test titles") diff --git a/test/battle/ability/overcoat.c b/test/battle/ability/overcoat.c index 6d7b5f2a8d..5edda7c3d5 100644 --- a/test/battle/ability/overcoat.c +++ b/test/battle/ability/overcoat.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves (Gen6+)") PARAMETRIZE { gen = GEN_5; } PARAMETRIZE { gen = GEN_6; } GIVEN { - WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, gen); + WITH_CONFIG(GEN_CONFIG_POWDER_OVERCOAT, gen); ASSUME(IsPowderMove(MOVE_STUN_SPORE)); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PINECO) { Ability(ABILITY_OVERCOAT); } @@ -71,17 +71,29 @@ DOUBLE_BATTLE_TEST("Overcoat blocks damage from hail") } } -SINGLE_BATTLE_TEST("Overcoat blocks Effect Spore's effect") +SINGLE_BATTLE_TEST("Overcoat blocks Effect Spore's effect (Gen6+)") { + u32 config; + PARAMETRIZE { config = GEN_5; } + PARAMETRIZE { config = GEN_6; } GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_OVERCOAT, config); PLAYER(SPECIES_PINECO) {Ability(ABILITY_OVERCOAT);} OPPONENT(SPECIES_SHROOMISH) {Ability(ABILITY_EFFECT_SPORE);} } WHEN { TURN { MOVE(player, MOVE_TACKLE, WITH_RNG(RNG_EFFECT_SPORE, 1)); } } SCENE { MESSAGE("Pineco used Tackle!"); - NOT ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + if (config == GEN_6) { + NOT ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + } + else { + ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); + } } THEN { - EXPECT_EQ(player->status1, 0); + if (config == GEN_6) + EXPECT_EQ(player->status1, 0); + else + EXPECT_NE(player->status1, 0); } } diff --git a/test/battle/ability/parental_bond.c b/test/battle/ability/parental_bond.c index b82f16cc26..fc128dba64 100644 --- a/test/battle/ability/parental_bond.c +++ b/test/battle/ability/parental_bond.c @@ -352,6 +352,22 @@ SINGLE_BATTLE_TEST("Parental Bond does not trigger on two turn attacks") } } +SINGLE_BATTLE_TEST("Parental Bond does not trigger Scale Shot effect on Drain Punch") +{ + GIVEN { + PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DRAIN_PUNCH, gimmick: GIMMICK_MEGA); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAIN_PUNCH, player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + } +} + TO_DO_BATTLE_TEST("Parental Bond tests"); // Temporary TODO: Convert Bulbapedia description into tests. diff --git a/test/battle/ability/prism_armor.c b/test/battle/ability/prism_armor.c index 60c8e238cf..69bdde0a0f 100644 --- a/test/battle/ability/prism_armor.c +++ b/test/battle/ability/prism_armor.c @@ -9,7 +9,7 @@ SINGLE_BATTLE_TEST("Prism Armor reduces damage to Super Effective moves by 0.75" GIVEN { ASSUME(gSpeciesInfo[SPECIES_NECROZMA].types[0] == TYPE_PSYCHIC); ASSUME(gSpeciesInfo[SPECIES_NECROZMA].types[1] == TYPE_PSYCHIC); - ASSUME(gMovesInfo[MOVE_DARK_PULSE].type == TYPE_DARK); + ASSUME(GetMoveType(MOVE_DARK_PULSE) == TYPE_DARK); ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_FAIRY] > UQ_4_12(1.0)); ASSUME(gTypeEffectivenessTable[TYPE_POISON][TYPE_PSYCHIC] == UQ_4_12(1.0)); PLAYER(SPECIES_NECROZMA); diff --git a/test/battle/ability/protean.c b/test/battle/ability/protean.c index fe4ae25e60..c41fa58cca 100644 --- a/test/battle/ability/protean.c +++ b/test/battle/ability/protean.c @@ -1,12 +1,15 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Protean changes the type of the user to the move used every time (Gen6-8)") +SINGLE_BATTLE_TEST("Protean/Libero changes the type of the user to the move used every time (Gen6-8)") { + u32 ability, species; + PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_KECLEON; } + PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; } GIVEN { WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_6); PLAYER(SPECIES_REGIROCK); - OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_WATER_GUN); } @@ -15,24 +18,36 @@ SINGLE_BATTLE_TEST("Protean changes the type of the user to the move used every TURN { SWITCH(opponent, 0); } TURN { MOVE(opponent, MOVE_WATER_GUN); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_PROTEAN); - MESSAGE("The opposing Kecleon transformed into the Water type!"); + ABILITY_POPUP(opponent, ability); + if (species == SPECIES_KECLEON) + MESSAGE("The opposing Kecleon transformed into the Water type!"); + else + MESSAGE("The opposing Raboot transformed into the Water type!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); - ABILITY_POPUP(opponent, ABILITY_PROTEAN); - MESSAGE("The opposing Kecleon transformed into the Normal type!"); + ABILITY_POPUP(opponent, ability); + if (species == SPECIES_KECLEON) + MESSAGE("The opposing Kecleon transformed into the Normal type!"); + else + MESSAGE("The opposing Raboot transformed into the Normal type!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); - ABILITY_POPUP(opponent, ABILITY_PROTEAN); - MESSAGE("The opposing Kecleon transformed into the Water type!"); + ABILITY_POPUP(opponent, ability); + if (species == SPECIES_KECLEON) + MESSAGE("The opposing Kecleon transformed into the Water type!"); + else + MESSAGE("The opposing Raboot transformed into the Water type!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); } } -SINGLE_BATTLE_TEST("Protean changes the type of the user only once per switch in (Gen9+)") +SINGLE_BATTLE_TEST("Protean/Libero changes the type of the user only once per switch in (Gen9+)") { + u32 ability, species; + PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_KECLEON; } + PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; } GIVEN { WITH_CONFIG(GEN_PROTEAN_LIBERO, GEN_9); PLAYER(SPECIES_REGIROCK); - OPPONENT(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + OPPONENT(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(opponent, MOVE_WATER_GUN); } @@ -41,31 +56,42 @@ SINGLE_BATTLE_TEST("Protean changes the type of the user only once per switch in TURN { SWITCH(opponent, 0); } TURN { MOVE(opponent, MOVE_WATER_GUN); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_PROTEAN); - MESSAGE("The opposing Kecleon transformed into the Water type!"); + ABILITY_POPUP(opponent, ability); + if (species == SPECIES_KECLEON) + MESSAGE("The opposing Kecleon transformed into the Water type!"); + else + MESSAGE("The opposing Raboot transformed into the Water type!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); NONE_OF { - ABILITY_POPUP(opponent, ABILITY_PROTEAN); + ABILITY_POPUP(opponent, ability); MESSAGE("The opposing Kecleon transformed into the Normal type!"); + MESSAGE("The opposing Raboot transformed into the Normal type!"); } ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); - ABILITY_POPUP(opponent, ABILITY_PROTEAN); - MESSAGE("The opposing Kecleon transformed into the Water type!"); + ABILITY_POPUP(opponent, ability); + if (species == SPECIES_KECLEON) + MESSAGE("The opposing Kecleon transformed into the Water type!"); + else + MESSAGE("The opposing Raboot transformed into the Water type!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); } } -SINGLE_BATTLE_TEST("Protean does not change the user's type when using Struggle") +SINGLE_BATTLE_TEST("Protean/Libero does not change the user's type when using Struggle") { + u32 ability, species; + PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_GRENINJA; } + PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; } GIVEN { PLAYER(SPECIES_REGIROCK); - OPPONENT(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); } + OPPONENT(species) { Ability(ability); } } WHEN { TURN { MOVE(opponent, MOVE_STRUGGLE); } } SCENE { NONE_OF { - ABILITY_POPUP(opponent, ABILITY_PROTEAN); + ABILITY_POPUP(opponent, ability); MESSAGE("The opposing Greninja transformed into the Normal type!"); + MESSAGE("The opposing Raboot transformed into the Normal type!"); } ANIMATION(ANIM_TYPE_MOVE, MOVE_STRUGGLE, opponent); } diff --git a/test/battle/ability/sharpness.c b/test/battle/ability/sharpness.c index 38ed79f86f..9b89614c36 100644 --- a/test/battle/ability/sharpness.c +++ b/test/battle/ability/sharpness.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Sharpness increases the power of slicing moves", s16 damage) +SINGLE_BATTLE_TEST("Sharpness increases the power of slicing moves by 50%", s16 damage) { u32 move; u16 ability; diff --git a/test/battle/ability/solid_rock.c b/test/battle/ability/solid_rock.c index b3dea4ae5e..d15b87e236 100644 --- a/test/battle/ability/solid_rock.c +++ b/test/battle/ability/solid_rock.c @@ -9,7 +9,7 @@ SINGLE_BATTLE_TEST("Solid Rock reduces damage to Super Effective moves by 0.75", GIVEN { ASSUME(gSpeciesInfo[SPECIES_CARRACOSTA].types[0] == TYPE_WATER); ASSUME(gSpeciesInfo[SPECIES_CARRACOSTA].types[1] == TYPE_ROCK); - ASSUME(gMovesInfo[MOVE_CLOSE_COMBAT].type == TYPE_FIGHTING); + ASSUME(GetMoveType(MOVE_CLOSE_COMBAT) == TYPE_FIGHTING); ASSUME(gTypeEffectivenessTable[TYPE_FIGHTING][TYPE_ROCK] > UQ_4_12(1.0)); ASSUME(gTypeEffectivenessTable[TYPE_FIGHTING][TYPE_WATER] == UQ_4_12(1.0)); PLAYER(SPECIES_CARRACOSTA) { Ability(ability); } diff --git a/test/battle/ability/soundproof.c b/test/battle/ability/soundproof.c index a7135942d1..6af6231cc2 100644 --- a/test/battle/ability/soundproof.c +++ b/test/battle/ability/soundproof.c @@ -1,4 +1,20 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Soundproof (Ability) test titles") +SINGLE_BATTLE_TEST("Soundproof makes sound moves fail against the ability user") +{ + GIVEN { + ASSUME(IsSoundMove(MOVE_BOOMBURST)); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); } + } WHEN { + TURN { MOVE(player, MOVE_BOOMBURST); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_SOUNDPROOF); + MESSAGE("The opposing Exploud's Soundproof blocks Boomburst!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BOOMBURST, player); + HP_BAR(opponent); + } + } +} diff --git a/test/battle/ability/toxic_boost.c b/test/battle/ability/toxic_boost.c index 85960c5b02..35a233ec23 100644 --- a/test/battle/ability/toxic_boost.c +++ b/test/battle/ability/toxic_boost.c @@ -1,4 +1,23 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Toxic Boost (Ability) test titles") +SINGLE_BATTLE_TEST("Toxic Boost increases Attack by 50% when the Pokémon is poisoned", s16 damage) +{ + u32 status1; + PARAMETRIZE { status1 = STATUS1_NONE; } + PARAMETRIZE { status1 = STATUS1_POISON; } + PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_ZANGOOSE) { Ability(ABILITY_TOXIC_BOOST); Status1(status1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[2].damage); + } +} diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 4c86673473..3e8f45717e 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -690,7 +690,7 @@ AI_SINGLE_BATTLE_TEST("AI won't use thawing moves if target is frozen unless it ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_SCALD].thawsUser == TRUE); + ASSUME(MoveThawsUser(MOVE_SCALD) == TRUE); AI_FLAGS(aiFlags | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE); Status1(status); } OPPONENT(SPECIES_VULPIX) { Moves(MOVE_TACKLE, aiMove); } diff --git a/test/battle/ai/ai_double_ace.c b/test/battle/ai/ai_double_ace.c index 3fa9ce77e0..38b7d1dcd8 100644 --- a/test/battle/ai/ai_double_ace.c +++ b/test/battle/ai/ai_double_ace.c @@ -94,3 +94,35 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_DOUBLE_ACE_POKEMON: Ace mons won't be switched in TURN { EXPECT_SWITCH(opponentLeft, 2); } } } + +AI_DOUBLE_BATTLE_TEST("AI_FLAG_DOUBLE_ACE_POKEMON: sends out Ace mons when no other options remain mid-battle") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_SMART_SWITCHING | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_DOUBLE_ACE_POKEMON); + + PLAYER(SPECIES_WOBBUFFET) { Level(50); Speed(200); Moves(MOVE_THUNDERBOLT, MOVE_CELEBRATE); SpAttack(200); } + PLAYER(SPECIES_WOBBUFFET) { Level(50); Speed(150); Moves(MOVE_THUNDERBOLT, MOVE_CELEBRATE); SpAttack(200); } + + OPPONENT(SPECIES_ZIGZAGOON) { Level(5); HP(1); Speed(1); Moves(MOVE_SPLASH); } + OPPONENT(SPECIES_POOCHYENA) { Level(5); HP(1); Speed(1); Moves(MOVE_SPLASH); } + + // Aces + OPPONENT(SPECIES_MIGHTYENA) { Level(50); Speed(10); Moves(MOVE_CRUNCH); } + OPPONENT(SPECIES_GENGAR) { Level(50); Speed(10); Moves(MOVE_SPLASH); } + } WHEN { + TURN { + MOVE(playerLeft, MOVE_THUNDERBOLT, target: opponentLeft); + MOVE(playerRight, MOVE_CELEBRATE); + EXPECT_MOVE(opponentLeft, MOVE_SPLASH); + EXPECT_MOVE(opponentRight, MOVE_SPLASH); + EXPECT_SEND_OUT(opponentLeft, 3); + } + TURN { + MOVE(playerLeft, MOVE_CELEBRATE); + MOVE(playerRight, MOVE_THUNDERBOLT, target: opponentRight); + EXPECT_MOVE(opponentLeft, MOVE_SPLASH); + EXPECT_MOVE(opponentRight, MOVE_SPLASH); + EXPECT_SEND_OUT(opponentRight, 2); + } + } +} diff --git a/test/battle/ai/ai_trytofaint.c b/test/battle/ai/ai_trytofaint.c index a1a23efdec..50ab376503 100644 --- a/test/battle/ai/ai_trytofaint.c +++ b/test/battle/ai/ai_trytofaint.c @@ -59,3 +59,17 @@ AI_SINGLE_BATTLE_TEST("AI sees Loaded Dice damage increase from multi hit moves" MESSAGE("Wobbuffet fainted!"); } } + +AI_SINGLE_BATTLE_TEST("AI sees Parental Bond killing through sturdy") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY); + PLAYER(SPECIES_MAGNEZONE){Level(64); Ability(ABILITY_STURDY); Moves(MOVE_TACKLE, MOVE_LIGHT_SCREEN); } + OPPONENT(SPECIES_KANGASKHAN_MEGA){Level(64); Moves(MOVE_DRAIN_PUNCH, MOVE_TAUNT); } + } WHEN { + TURN{ MOVE(player, MOVE_TACKLE); + EXPECT_MOVE(opponent, MOVE_DRAIN_PUNCH); // AI should see drain punch as a kill due to multi hit, outscoring taunt + } + } +} + diff --git a/test/battle/ai/can_use_all_moves.c b/test/battle/ai/can_use_all_moves.c index fb6f7a343a..efae2b7544 100644 --- a/test/battle/ai/can_use_all_moves.c +++ b/test/battle/ai/can_use_all_moves.c @@ -9,7 +9,6 @@ AI_DOUBLE_BATTLE_TEST("AI uses Final Gambit") { - KNOWN_FAILING; GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); @@ -20,13 +19,12 @@ AI_DOUBLE_BATTLE_TEST("AI uses Final Gambit") OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { EXPECT_MOVE(opponentLeft, MOVE_FINAL_GAMBIT); } + TURN { EXPECT_MOVE(opponentLeft, MOVE_FINAL_GAMBIT); SEND_OUT(playerLeft, 2); } } } AI_DOUBLE_BATTLE_TEST("AI uses Guillotine") { - KNOWN_FAILING; GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); @@ -37,13 +35,12 @@ AI_DOUBLE_BATTLE_TEST("AI uses Guillotine") OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { EXPECT_MOVE(opponentLeft, MOVE_GUILLOTINE); } + TURN { EXPECT_MOVE(opponentLeft, MOVE_GUILLOTINE); SEND_OUT(playerLeft, 2); } } } AI_DOUBLE_BATTLE_TEST("AI uses Sheer Cold") { - KNOWN_FAILING; GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); @@ -54,7 +51,7 @@ AI_DOUBLE_BATTLE_TEST("AI uses Sheer Cold") OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { EXPECT_MOVE(opponentLeft, MOVE_SHEER_COLD); } + TURN { EXPECT_MOVE(opponentLeft, MOVE_SHEER_COLD); SEND_OUT(playerLeft, 2); } } } diff --git a/test/battle/end_turn_effects.c b/test/battle/end_turn_effects.c index 51aa1e79bf..01c844f9b5 100644 --- a/test/battle/end_turn_effects.c +++ b/test/battle/end_turn_effects.c @@ -29,3 +29,27 @@ DOUBLE_BATTLE_TEST("End Turn Effects: First Event Block is executed correctly") } } +DOUBLE_BATTLE_TEST("End Turn Effects: Effects are applied by Speed Order") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT) { MaxHP(200); HP(100); Speed(3); } + PLAYER(SPECIES_RILLABOOM) { MaxHP(200); HP(100); Speed(1); Ability(ABILITY_GRASSY_SURGE); } + OPPONENT(SPECIES_MEWTWO) { MaxHP(200); HP(100); Speed(2); } + OPPONENT(SPECIES_WOBBUFFET) { MaxHP(200); HP(100); Speed(4); } + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_FAKE_OUT, target: playerLeft); + MOVE(playerRight, MOVE_FAKE_OUT, target: opponentRight); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, opponentLeft); + HP_BAR(playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, playerRight); + HP_BAR(opponentRight); + + HP_BAR(opponentRight); + HP_BAR(playerLeft); + HP_BAR(opponentLeft); + HP_BAR(playerRight); + } +} diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index bb8814fa42..0329ee903c 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -1671,5 +1671,71 @@ SINGLE_BATTLE_TEST("Dynamax: Destiny Bond fails if a dynamaxed battler is presen } } +DOUBLE_BATTLE_TEST("Dynamax stat lowering moves don't make stat-changing abilities apply to partner") +{ + u32 move, stat, ability; + move = 0; stat = 0; ability = 0; + u32 abilityList[] = {ABILITY_COMPETITIVE, ABILITY_DEFIANT, ABILITY_CONTRARY, ABILITY_SIMPLE}; + for (u32 j = 0; j < 4; j++) + { + PARAMETRIZE { move = MOVE_SCRATCH; stat = STAT_SPEED; ability = abilityList[j]; } + PARAMETRIZE { move = MOVE_FURY_CUTTER; stat = STAT_SPATK; ability = abilityList[j]; } + PARAMETRIZE { move = MOVE_LICK; stat = STAT_DEF; ability = abilityList[j]; ;} + PARAMETRIZE { move = MOVE_DRAGON_CLAW; stat = STAT_ATK; ability = abilityList[j]; } + PARAMETRIZE { move = MOVE_CRUNCH; stat = STAT_SPDEF; ability = abilityList[j]; } + } + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_STRIKE, MOVE_EFFECT_LOWER_SPEED_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_FLUTTERBY, MOVE_EFFECT_LOWER_SP_ATK_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_PHANTASM, MOVE_EFFECT_LOWER_DEFENSE_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_WYRMWIND, MOVE_EFFECT_LOWER_ATTACK_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_DARKNESS, MOVE_EFFECT_LOWER_SP_DEF_SIDE)); + PLAYER(SPECIES_WOBBUFFET) { } + PLAYER(SPECIES_WOBBUFFET) { } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ability); } + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } + } WHEN { + TURN { MOVE(playerLeft, move, target: opponentLeft, gimmick: GIMMICK_DYNAMAX);} + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + } THEN { + EXPECT_EQ(opponentRight->statStages[stat], DEFAULT_STAT_STAGE - 1); + } +} + +DOUBLE_BATTLE_TEST("Dynamax stat raising moves don't make stat-changing abilities apply to partner") +{ + u32 move, stat, ability; + move = 0; stat = 0; ability = 0; + u32 abilityList[] = {ABILITY_CONTRARY, ABILITY_SIMPLE}; + for (u32 j = 0; j < 2; j++) + { + PARAMETRIZE { move = MOVE_PECK; stat = STAT_SPEED; ability = abilityList[j]; } + PARAMETRIZE { move = MOVE_POISON_JAB; stat = STAT_SPATK; ability = abilityList[j]; } + PARAMETRIZE { move = MOVE_BULLET_PUNCH; stat = STAT_DEF; ability = abilityList[j]; ;} + PARAMETRIZE { move = MOVE_DOUBLE_KICK; stat = STAT_ATK; ability = abilityList[j]; } + PARAMETRIZE { move = MOVE_MUD_SLAP; stat = STAT_SPDEF; ability = abilityList[j]; } + } + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_STRIKE, MOVE_EFFECT_LOWER_SPEED_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_FLUTTERBY, MOVE_EFFECT_LOWER_SP_ATK_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_PHANTASM, MOVE_EFFECT_LOWER_DEFENSE_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_WYRMWIND, MOVE_EFFECT_LOWER_ATTACK_SIDE)); + ASSUME(MoveHasAdditionalEffect(MOVE_MAX_DARKNESS, MOVE_EFFECT_LOWER_SP_DEF_SIDE)); + PLAYER(SPECIES_WOBBUFFET) { Ability(ability); } + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } + OPPONENT(SPECIES_WOBBUFFET) {} + OPPONENT(SPECIES_WOBBUFFET) {} + } WHEN { + TURN { MOVE(playerLeft, move, target: opponentLeft, gimmick: GIMMICK_DYNAMAX);} + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } THEN { + EXPECT_EQ(playerRight->statStages[stat], DEFAULT_STAT_STAGE + 1); + } +} + TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-lowering Max Moves, without showing a message") TO_DO_BATTLE_TEST("Dynamax: Contrary inverts stat-increasing Max Moves, without showing a message") diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c index 37a6d515b3..d238ea0d51 100644 --- a/test/battle/gimmick/terastal.c +++ b/test/battle/gimmick/terastal.c @@ -639,17 +639,21 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves } } -SINGLE_BATTLE_TEST("(TERA) Protean cannot change the type of a Terastallized Pokemon") +SINGLE_BATTLE_TEST("(TERA) Protean/Libero cannot change the type of a Terastallized Pokemon") { + u32 ability, species; + PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_GRENINJA; } + PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; } GIVEN { - PLAYER(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); TeraType(TYPE_GRASS); } + PLAYER(species) { Ability(ability); TeraType(TYPE_GRASS); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_BUBBLE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_EMBER); } } SCENE { - MESSAGE("Greninja used Bubble!"); - MESSAGE("The opposing Wobbuffet used Ember!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_TERA_ACTIVATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BUBBLE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, opponent); MESSAGE("It's super effective!"); } } diff --git a/test/battle/hold_effect/life_orb.c b/test/battle/hold_effect/life_orb.c index 81ddd614db..e983537b83 100644 --- a/test/battle/hold_effect/life_orb.c +++ b/test/battle/hold_effect/life_orb.c @@ -34,6 +34,7 @@ SINGLE_BATTLE_TEST("Life Orb activates if it hits a Substitute") SINGLE_BATTLE_TEST("Life Orb does not activate if using status move on a Substitute") { GIVEN { + ASSUME(MoveIgnoresSubstitute(MOVE_GROWL)); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/shed_shell.c b/test/battle/hold_effect/shed_shell.c new file mode 100644 index 0000000000..93c3fb0e53 --- /dev/null +++ b/test/battle/hold_effect/shed_shell.c @@ -0,0 +1,67 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gItemsInfo[ITEM_SHED_SHELL].holdEffect == HOLD_EFFECT_SHED_SHELL); +}; + +SINGLE_BATTLE_TEST("Shed Shell allows switching out even when trapped by Mean Look") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHED_SHELL); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_GASTLY); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_MEAN_LOOK); } + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEAN_LOOK, opponent); + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Wynaut"); + } +} + +SINGLE_BATTLE_TEST("Shed Shell allows switching out even when trapped by Shadow Tag") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHED_SHELL); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + SWITCH_OUT_MESSAGE("Wobbuffet"); + SEND_IN_MESSAGE("Wynaut"); + } +} + +SINGLE_BATTLE_TEST("Shed Shell allows switching out even when trapped by Arena Trap") +{ + GIVEN { + PLAYER(SPECIES_DIGLETT) { Item(ITEM_SHED_SHELL); } // Grounded + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_DIGLETT) { Ability(ABILITY_ARENA_TRAP); } + } WHEN { + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + SWITCH_OUT_MESSAGE("Diglett"); + SEND_IN_MESSAGE("Wynaut"); + } +} + +SINGLE_BATTLE_TEST("Shed Shell does not allow Teleport when trapped") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_TELEPORT) == EFFECT_TELEPORT); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHED_SHELL); Moves(MOVE_TELEPORT, MOVE_SPLASH, MOVE_CELEBRATE); } + OPPONENT(SPECIES_GASTLY); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_MEAN_LOOK); } + TURN { MOVE(player, MOVE_TELEPORT); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEAN_LOOK, opponent); + MESSAGE("Wobbuffet used Teleport!"); + MESSAGE("But it failed!"); + } +} diff --git a/test/battle/item_effect/poke_flute.c b/test/battle/item_effect/poke_flute.c new file mode 100644 index 0000000000..c9aebed5d3 --- /dev/null +++ b/test/battle/item_effect/poke_flute.c @@ -0,0 +1,43 @@ +#include "global.h" +#include "test/battle.h" +#include "constants/item_effects.h" + +DOUBLE_BATTLE_TEST("Poke Flute heals all battlers from being asleep") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_POKE_FLUTE].battleUsage == EFFECT_ITEM_USE_POKE_FLUTE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + } WHEN { + TURN { USE_ITEM(playerLeft, ITEM_POKE_FLUTE, partyIndex: 0); } + } SCENE { + MESSAGE("The Pokémon hearing the flute awoke!"); + } THEN { + EXPECT_EQ(playerLeft->status1, STATUS1_NONE); + EXPECT_EQ(playerRight->status1, STATUS1_NONE); + EXPECT_EQ(opponentLeft->status1, STATUS1_NONE); + EXPECT_EQ(opponentRight->status1, STATUS1_NONE); + } +} + +DOUBLE_BATTLE_TEST("Poke Flute does not heal battlers with Soundproof from being asleep") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_POKE_FLUTE].battleUsage == EFFECT_ITEM_USE_POKE_FLUTE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + PLAYER(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); } + OPPONENT(SPECIES_EXPLOUD) { Ability(ABILITY_SOUNDPROOF); Status1(STATUS1_SLEEP); } + } WHEN { + TURN { USE_ITEM(playerLeft, ITEM_POKE_FLUTE, partyIndex: 0); } + } SCENE { + MESSAGE("The Pokémon hearing the flute awoke!"); + } THEN { + EXPECT_EQ(playerLeft->status1, STATUS1_NONE); + EXPECT_NE(playerRight->status1, STATUS1_NONE); + EXPECT_EQ(opponentLeft->status1, STATUS1_NONE); + EXPECT_NE(opponentRight->status1, STATUS1_NONE); + } +} diff --git a/test/battle/move_animations/all_anims.c b/test/battle/move_animations/all_anims.c index c929921d3f..e69eb59750 100644 --- a/test/battle/move_animations/all_anims.c +++ b/test/battle/move_animations/all_anims.c @@ -11,42 +11,43 @@ static void ParametrizeMovesAndSpecies(u32 j, u32 *pMove, u32 *pSpecies) { - if (gMovesInfo[j].effect == EFFECT_DARK_VOID) // User needs to be Darkrai + enum BattleMoveEffects effect = GetMoveEffect(j); + if (effect == EFFECT_DARK_VOID) // User needs to be Darkrai { *pMove = j; *pSpecies = SPECIES_DARKRAI; } - else if (gMovesInfo[j].effect == EFFECT_HYPERSPACE_FURY) // User needs to be Hoopa Unbound + else if (effect == EFFECT_HYPERSPACE_FURY) // User needs to be Hoopa Unbound { *pMove = j; *pSpecies = SPECIES_HOOPA_UNBOUND; } - else if (gMovesInfo[j].effect == EFFECT_AURA_WHEEL) // User needs to be Morpeko + else if (effect == EFFECT_AURA_WHEEL) // User needs to be Morpeko { *pMove = j; *pSpecies = SPECIES_MORPEKO_FULL_BELLY; } - else if (gMovesInfo[j].effect == EFFECT_ROTOTILLER || gMovesInfo[j].effect == EFFECT_FLOWER_SHIELD) // User needs to be Grass-type + else if (effect == EFFECT_ROTOTILLER || effect == EFFECT_FLOWER_SHIELD) // User needs to be Grass-type { *pMove = j; *pSpecies = SPECIES_TANGELA; } - else if (gMovesInfo[j].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE && gMovesInfo[j].argument.type == TYPE_FIRE) // User needs to be Fire-type + else if (effect == EFFECT_FAIL_IF_NOT_ARG_TYPE && GetMoveArgType(j) == TYPE_FIRE) // User needs to be Fire-type { *pMove = j; *pSpecies = SPECIES_FLAREON; } - else if (gMovesInfo[j].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE && gMovesInfo[j].argument.type == TYPE_ELECTRIC) // User needs to be Electric-type + else if (effect == EFFECT_FAIL_IF_NOT_ARG_TYPE && GetMoveArgType(j) == TYPE_ELECTRIC) // User needs to be Electric-type { *pMove = j; *pSpecies = SPECIES_JOLTEON; } - else if (gMovesInfo[j].effect == EFFECT_MAGNETIC_FLUX || gMovesInfo[j].effect == EFFECT_GEAR_UP) // User needs to have Plus + else if (effect == EFFECT_MAGNETIC_FLUX || effect == EFFECT_GEAR_UP) // User needs to have Plus { *pMove = j; *pSpecies = SPECIES_KLINKLANG; } - else if (gMovesInfo[j].effect == EFFECT_PLACEHOLDER) // Ignore placeholder *pMoves + else if (effect == EFFECT_PLACEHOLDER) // Ignore placeholder *pMoves { *pMove = MOVE_POUND; *pSpecies = SPECIES_WOBBUFFET; @@ -60,100 +61,104 @@ static void ParametrizeMovesAndSpecies(u32 j, u32 *pMove, u32 *pSpecies) static bool32 TargetHasToMove(u32 move) // Opponent needs to hit the player first { - if (gMovesInfo[move].effect == EFFECT_COUNTER - || gMovesInfo[move].effect == EFFECT_MIRROR_MOVE - || gMovesInfo[move].effect == EFFECT_CONVERSION_2 - || gMovesInfo[move].effect == EFFECT_MIRROR_COAT - || gMovesInfo[move].effect == EFFECT_METAL_BURST - || gMovesInfo[move].effect == EFFECT_COPYCAT - || gMovesInfo[move].effect == EFFECT_SUCKER_PUNCH - || gMovesInfo[move].effect == EFFECT_INSTRUCT) + enum BattleMoveEffects effect = GetMoveEffect(move); + if (effect == EFFECT_COUNTER + || effect == EFFECT_MIRROR_MOVE + || effect == EFFECT_CONVERSION_2 + || effect == EFFECT_MIRROR_COAT + || effect == EFFECT_METAL_BURST + || effect == EFFECT_COPYCAT + || effect == EFFECT_SUCKER_PUNCH + || effect == EFFECT_INSTRUCT) return TRUE; return FALSE; } static bool32 AttackerHasToSwitch(u32 move) // User needs to send out a different team member { - if (gMovesInfo[move].effect == EFFECT_TELEPORT - || gMovesInfo[move].effect == EFFECT_EXPLOSION - || gMovesInfo[move].effect == EFFECT_MISTY_EXPLOSION - || gMovesInfo[move].effect == EFFECT_BATON_PASS - || gMovesInfo[move].effect == EFFECT_MEMENTO - || gMovesInfo[move].effect == EFFECT_HEALING_WISH - || gMovesInfo[move].effect == EFFECT_HIT_ESCAPE - || gMovesInfo[move].effect == EFFECT_FINAL_GAMBIT - || gMovesInfo[move].effect == EFFECT_PARTING_SHOT - || gMovesInfo[move].effect == EFFECT_SHED_TAIL - || gMovesInfo[move].effect == EFFECT_CHILLY_RECEPTION) + enum BattleMoveEffects effect = GetMoveEffect(move); + if (effect == EFFECT_TELEPORT + || effect == EFFECT_EXPLOSION + || effect == EFFECT_MISTY_EXPLOSION + || effect == EFFECT_BATON_PASS + || effect == EFFECT_MEMENTO + || effect == EFFECT_HEALING_WISH + || effect == EFFECT_HIT_ESCAPE + || effect == EFFECT_FINAL_GAMBIT + || effect == EFFECT_PARTING_SHOT + || effect == EFFECT_SHED_TAIL + || effect == EFFECT_CHILLY_RECEPTION) return TRUE; return FALSE; } static bool32 UserHasToGoFirst(u32 move) // Player needs to go first { - if (gMovesInfo[move].effect == EFFECT_PROTECT - || gMovesInfo[move].effect == EFFECT_ENDURE - || gMovesInfo[move].effect == EFFECT_FOLLOW_ME - || gMovesInfo[move].effect == EFFECT_MAGIC_COAT - || gMovesInfo[move].effect == EFFECT_ME_FIRST - || gMovesInfo[move].effect == EFFECT_QUASH - || gMovesInfo[move].effect == EFFECT_MAT_BLOCK - || gMovesInfo[move].effect == EFFECT_ELECTRIFY - || gMovesInfo[move].effect == EFFECT_SHELL_TRAP) + enum BattleMoveEffects effect = GetMoveEffect(move); + if (effect == EFFECT_PROTECT + || effect == EFFECT_ENDURE + || effect == EFFECT_FOLLOW_ME + || effect == EFFECT_MAGIC_COAT + || effect == EFFECT_ME_FIRST + || effect == EFFECT_QUASH + || effect == EFFECT_MAT_BLOCK + || effect == EFFECT_ELECTRIFY + || effect == EFFECT_SHELL_TRAP) return TRUE; return FALSE; } static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattlePokemon *defender) { + enum BattleMoveEffects effect = GetMoveEffect(move); // Setup turn - if (gMovesInfo[move].effect == EFFECT_SNORE - || gMovesInfo[move].effect == EFFECT_SLEEP_TALK) + if (effect == EFFECT_SNORE + || effect == EFFECT_SLEEP_TALK) { // attacker needs to be asleep TURN { MOVE(attacker, MOVE_REST); } } - else if (gMovesInfo[move].effect == EFFECT_SPIT_UP - || gMovesInfo[move].effect == EFFECT_SWALLOW) + else if (effect == EFFECT_SPIT_UP + || effect == EFFECT_SWALLOW) { // attacker needs to have used Stockpile TURN { MOVE(attacker, MOVE_STOCKPILE); } } - else if ((gMovesInfo[move].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS && gMovesInfo[move].argument.status == STATUS1_PARALYSIS)) + else if ((effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS && GetMoveEffectArg_Status(move) == STATUS1_PARALYSIS)) { // defender needs to be paralyzed TURN { MOVE(attacker, MOVE_THUNDER_WAVE); } } - else if (gMovesInfo[move].effect == EFFECT_RECYCLE - || gMovesInfo[move].effect == EFFECT_BELCH) + else if (effect == EFFECT_RECYCLE + || effect == EFFECT_BELCH) { // attacker needs to have eaten its Berry TURN { MOVE(attacker, MOVE_STUFF_CHEEKS); } } - else if (gMovesInfo[move].effect == EFFECT_REFRESH - || gMovesInfo[move].effect == EFFECT_PSYCHO_SHIFT) + else if (effect == EFFECT_REFRESH + || effect == EFFECT_PSYCHO_SHIFT) { // attacker needs to be paralyzed TURN { MOVE(defender, MOVE_THUNDER_WAVE); } } - else if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) + else if (effect == EFFECT_LAST_RESORT) { // attacker needs to have used all other moves TURN { MOVE(attacker, MOVE_POUND); } } - else if (gMovesInfo[move].effect == EFFECT_DREAM_EATER - || gMovesInfo[move].effect == EFFECT_NIGHTMARE) + else if (effect == EFFECT_DREAM_EATER + || effect == EFFECT_NIGHTMARE) { // defender needs to be asleep TURN { MOVE(defender, MOVE_REST); } } - else if (gMovesInfo[move].effect == EFFECT_VENOM_DRENCH - || gMovesInfo[move].effect == EFFECT_PURIFY) + else if (effect == EFFECT_VENOM_DRENCH + || effect == EFFECT_PURIFY) { // defender needs to be poisoned TURN { MOVE(attacker, MOVE_POISON_POWDER); } } - else if (gMovesInfo[move].effect == EFFECT_TOPSY_TURVY) + else if (effect == EFFECT_TOPSY_TURVY) { // defender needs to have its stats buffed TURN { MOVE(defender, MOVE_SWORDS_DANCE); } } - else if (gMovesInfo[move].effect == EFFECT_AURORA_VEIL) + else if (effect == EFFECT_AURORA_VEIL) { // Has to be hailing TURN { MOVE(attacker, MOVE_HAIL); } } - else if (gMovesInfo[move].effect == EFFECT_STEEL_ROLLER) + else if (effect == EFFECT_STEEL_ROLLER) { // Needs a terrain TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } } @@ -161,15 +166,15 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP TURN { if (TargetHasToMove(move)) { - MOVE(defender, gMovesInfo[move].effect == EFFECT_MIRROR_COAT ? MOVE_SWIFT : MOVE_POUND); + MOVE(defender, effect == EFFECT_MIRROR_COAT ? MOVE_SWIFT : MOVE_POUND); MOVE(attacker, move); } - else if (gMovesInfo[move].effect == EFFECT_SNATCH) + else if (effect == EFFECT_SNATCH) { // defender needs to steal the defender's buffing move MOVE(attacker, move); MOVE(defender, MOVE_SWORDS_DANCE); } - else if (gMovesInfo[move].effect == EFFECT_OHKO || gMovesInfo[move].effect == EFFECT_SHEER_COLD) + else if (effect == EFFECT_OHKO || effect == EFFECT_SHEER_COLD) { // defender needs to send out a different team member MOVE(attacker, move); SEND_OUT(defender, 1); @@ -184,17 +189,17 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP MOVE(attacker, move); MOVE(defender, MOVE_POUND); } - else if (gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING) + else if (effect == EFFECT_REVIVAL_BLESSING) { // attacker selects party member MOVE(attacker, move, partyIndex: 1); MOVE(defender, MOVE_HELPING_HAND); } - else if (gMovesInfo[move].effect == EFFECT_UPPER_HAND) + else if (effect == EFFECT_UPPER_HAND) { // defender needs to choose priority move MOVE(attacker, move); MOVE(defender, MOVE_QUICK_ATTACK); } - else if (gMovesInfo[move].effect == EFFECT_ACUPRESSURE) + else if (effect == EFFECT_ACUPRESSURE) { MOVE(attacker, move, target: attacker); } @@ -208,22 +213,23 @@ static void WhenSingles(u32 move, struct BattlePokemon *attacker, struct BattleP static void SceneSingles(u32 move, struct BattlePokemon *mon) { - if (gMovesInfo[move].effect == EFFECT_FOLLOW_ME - || gMovesInfo[move].effect == EFFECT_HELPING_HAND - || gMovesInfo[move].effect == EFFECT_AFTER_YOU - || gMovesInfo[move].effect == EFFECT_ALLY_SWITCH - || gMovesInfo[move].effect == EFFECT_AROMATIC_MIST + enum BattleMoveEffects effect = GetMoveEffect(move); + if (effect == EFFECT_FOLLOW_ME + || effect == EFFECT_HELPING_HAND + || effect == EFFECT_AFTER_YOU + || effect == EFFECT_ALLY_SWITCH + || effect == EFFECT_AROMATIC_MIST || move == MOVE_HOLD_HANDS // Hack here because it shares its effect with Splash and Celebrate - || gMovesInfo[move].effect == EFFECT_COACHING - || gMovesInfo[move].effect == EFFECT_DRAGON_CHEER) + || effect == EFFECT_COACHING + || effect == EFFECT_DRAGON_CHEER) { // Moves that fail in Single Battles } - else if (gMovesInfo[move].effect == EFFECT_MIRROR_MOVE) // Copy the opponent's move + else if (effect == EFFECT_MIRROR_MOVE) // Copy the opponent's move { ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, mon); } - else if (gMovesInfo[move].effect == EFFECT_NATURE_POWER) // Recorded battles always use BATTLE_ENVIRONMENT_BUILDING + else if (effect == EFFECT_NATURE_POWER) // Recorded battles always use BATTLE_ENVIRONMENT_BUILDING { ANIMATION(ANIM_TYPE_MOVE, B_NATURE_POWER_MOVES >= GEN_4 ? MOVE_TRI_ATTACK : MOVE_SWIFT, mon); } @@ -235,54 +241,55 @@ static void SceneSingles(u32 move, struct BattlePokemon *mon) static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattlePokemon *target, struct BattlePokemon *ignore1, struct BattlePokemon *ignore2) { + enum BattleMoveEffects effect = GetMoveEffect(move); // Setup turn - if (gMovesInfo[move].effect == EFFECT_SNORE - || gMovesInfo[move].effect == EFFECT_SLEEP_TALK) + if (effect == EFFECT_SNORE + || effect == EFFECT_SLEEP_TALK) { // Player needs to be asleep TURN { MOVE(attacker, MOVE_REST); } } - else if (gMovesInfo[move].effect == EFFECT_SPIT_UP - || gMovesInfo[move].effect == EFFECT_SWALLOW) + else if (effect == EFFECT_SPIT_UP + || effect == EFFECT_SWALLOW) { // Player needs to have used Stockpile TURN { MOVE(attacker, MOVE_STOCKPILE); } } - else if ((gMovesInfo[move].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS && gMovesInfo[move].argument.status == STATUS1_PARALYSIS)) + else if ((effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS && GetMoveEffectArg_Status(move) == STATUS1_PARALYSIS)) { // Opponent needs to be paralyzed TURN { MOVE(attacker, MOVE_THUNDER_WAVE, target: target); } } - else if (gMovesInfo[move].effect == EFFECT_RECYCLE - || gMovesInfo[move].effect == EFFECT_BELCH) + else if (effect == EFFECT_RECYCLE + || effect == EFFECT_BELCH) { // Player needs to have eaten its Berry TURN { MOVE(attacker, MOVE_STUFF_CHEEKS); } } - else if (gMovesInfo[move].effect == EFFECT_REFRESH - || gMovesInfo[move].effect == EFFECT_PSYCHO_SHIFT) + else if (effect == EFFECT_REFRESH + || effect == EFFECT_PSYCHO_SHIFT) { // Player needs to be paralyzed TURN { MOVE(target, MOVE_THUNDER_WAVE, target: attacker); } } - else if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) + else if (effect == EFFECT_LAST_RESORT) { // Player needs to have used all other moves TURN { MOVE(attacker, MOVE_POUND, target: target); } } - else if (gMovesInfo[move].effect == EFFECT_DREAM_EATER - || gMovesInfo[move].effect == EFFECT_NIGHTMARE) + else if (effect == EFFECT_DREAM_EATER + || effect == EFFECT_NIGHTMARE) { // Opponent needs to be asleep TURN { MOVE(target, MOVE_REST); } } - else if (gMovesInfo[move].effect == EFFECT_VENOM_DRENCH - || gMovesInfo[move].effect == EFFECT_PURIFY) + else if (effect == EFFECT_VENOM_DRENCH + || effect == EFFECT_PURIFY) { // Opponent needs to be poisoned TURN { MOVE(attacker, MOVE_POISON_POWDER, target: target); } } - else if (gMovesInfo[move].effect == EFFECT_TOPSY_TURVY) + else if (effect == EFFECT_TOPSY_TURVY) { // Opponent needs to have its stats buffed TURN { MOVE(target, MOVE_SWORDS_DANCE); } } - else if (gMovesInfo[move].effect == EFFECT_AURORA_VEIL) + else if (effect == EFFECT_AURORA_VEIL) { // Has to be hailing TURN { MOVE(attacker, MOVE_HAIL); } } - else if (gMovesInfo[move].effect == EFFECT_STEEL_ROLLER) + else if (effect == EFFECT_STEEL_ROLLER) { // Needs a terrain TURN { MOVE(attacker, MOVE_ELECTRIC_TERRAIN); } } @@ -290,15 +297,15 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP TURN { if (TargetHasToMove(move)) { // Opponent needs to hit the player first - MOVE(target, gMovesInfo[move].effect == EFFECT_MIRROR_COAT ? MOVE_SWIFT : MOVE_POUND, target: attacker); + MOVE(target, effect == EFFECT_MIRROR_COAT ? MOVE_SWIFT : MOVE_POUND, target: attacker); MOVE(attacker, move, target: target); } - else if (gMovesInfo[move].effect == EFFECT_SNATCH) + else if (effect == EFFECT_SNATCH) { // Opponent needs to steal the opponent's buffing move MOVE(attacker, move, target: target); MOVE(target, MOVE_SWORDS_DANCE); } - else if (gMovesInfo[move].effect == EFFECT_OHKO || gMovesInfo[move].effect == EFFECT_SHEER_COLD) + else if (effect == EFFECT_OHKO || effect == EFFECT_SHEER_COLD) { // Opponent needs to send out a different team member MOVE(attacker, move, target: target); SEND_OUT(target, 2); @@ -313,19 +320,19 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP MOVE(attacker, move, target: target); MOVE(target, MOVE_POUND, target: attacker); } - else if (gMovesInfo[move].effect == EFFECT_AFTER_YOU) + else if (effect == EFFECT_AFTER_YOU) { // Player goes first, opponent third MOVE(attacker, move, target: target); MOVE(ignore1, MOVE_CELEBRATE); MOVE(target, MOVE_POUND, target: attacker); MOVE(ignore2, MOVE_CELEBRATE); } - else if (gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING) + else if (effect == EFFECT_REVIVAL_BLESSING) { // Player selects party member MOVE(attacker, move, partyIndex: 2); MOVE(target, MOVE_LAST_RESORT, target: attacker); // Last Resort, so there's no anim on the opponent's side. } - else if (gMovesInfo[move].effect == EFFECT_UPPER_HAND) + else if (effect == EFFECT_UPPER_HAND) { // Opponent needs to choose priority move MOVE(attacker, move, target: target); MOVE(target, MOVE_QUICK_ATTACK, target: attacker); @@ -335,7 +342,7 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP MOVE(target, MOVE_LAST_RESORT, target: attacker); // Last Resort, so there's no anim on the opponent's side. MOVE(attacker, move, target: target); } - if (gMovesInfo[move].effect != EFFECT_AFTER_YOU) + if (effect != EFFECT_AFTER_YOU) { // Actions for the remaining battlers MOVE(ignore1, MOVE_CELEBRATE); @@ -346,15 +353,16 @@ static void DoublesWhen(u32 move, struct BattlePokemon *attacker, struct BattleP static void DoublesScene(u32 move, struct BattlePokemon *attacker) { - if (gMovesInfo[move].effect == EFFECT_MAGNETIC_FLUX || gMovesInfo[move].effect == EFFECT_GEAR_UP) // For some reason, Magnetic Flux and Gear Up are failing in Double Battles here + enum BattleMoveEffects effect = GetMoveEffect(move); + if (effect == EFFECT_MAGNETIC_FLUX || effect == EFFECT_GEAR_UP) // For some reason, Magnetic Flux and Gear Up are failing in Double Battles here { // Moves that fail in Double Battles } - else if (gMovesInfo[move].effect == EFFECT_MIRROR_MOVE) + else if (effect == EFFECT_MIRROR_MOVE) { // Copy the opponent's move ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, attacker); } - else if (gMovesInfo[move].effect == EFFECT_NATURE_POWER) + else if (effect == EFFECT_NATURE_POWER) { // Recorded battles always use BATTLE_ENVIRONMENT_BUILDING ANIMATION(ANIM_TYPE_MOVE, B_NATURE_POWER_MOVES >= GEN_4 ? MOVE_TRI_ATTACK : MOVE_SWIFT, attacker); } @@ -382,16 +390,16 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (player to op PLAYER(species) { HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) + if (GetMoveEffect(move) != EFFECT_BESTOW) Item(ITEM_ORAN_BERRY); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } @@ -401,9 +409,10 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (player to op SceneSingles(move, player); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -420,16 +429,16 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (opponent to OPPONENT(species) { HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) + if (GetMoveEffect(move) != EFFECT_BESTOW) Item(ITEM_ORAN_BERRY); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } @@ -439,9 +448,10 @@ SINGLE_BATTLE_TEST("Move Animations don't leak when used - Singles (opponent to SceneSingles(move, opponent); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -463,7 +473,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -472,22 +482,22 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) + if (GetMoveEffect(move) != EFFECT_BESTOW) Item(ITEM_ORAN_BERRY); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) + if (GetMoveEffect(move) != EFFECT_BESTOW) Item(ITEM_ORAN_BERRY); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } @@ -497,9 +507,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -521,7 +532,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -529,23 +540,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -556,9 +567,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -580,7 +592,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -588,23 +600,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -615,9 +627,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -639,7 +652,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -647,23 +660,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -674,9 +687,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -698,7 +712,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -706,23 +720,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -733,9 +747,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -757,7 +772,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -765,23 +780,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -792,9 +807,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentLeft DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -816,7 +832,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -824,23 +840,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == playerRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -851,9 +867,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -875,7 +892,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -883,23 +900,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -910,9 +927,10 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh DoublesScene(move, attacker); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -935,7 +953,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -943,23 +961,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -971,7 +989,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerLeft t } THEN { FORCE_MOVE_ANIM(FALSE); if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); } } @@ -994,7 +1012,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -1002,23 +1020,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -1030,7 +1048,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (playerRight } THEN { FORCE_MOVE_ANIM(FALSE); if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); } } @@ -1053,7 +1071,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentleft HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -1061,23 +1079,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentleft HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -1089,7 +1107,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentleft } THEN { FORCE_MOVE_ANIM(FALSE); if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); } } @@ -1112,7 +1130,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentLeft) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } @@ -1120,23 +1138,23 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (attacker == opponentRight) { if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND, MOVE_CELEBRATE); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) { + if (GetMoveEffect(move) != EFFECT_BESTOW) { Item(ITEM_ORAN_BERRY); } } @@ -1148,7 +1166,7 @@ DOUBLE_BATTLE_TEST("Move Animations don't leak when used - Doubles (opponentRigh } THEN { FORCE_MOVE_ANIM(FALSE); if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); } } @@ -1167,27 +1185,27 @@ SINGLE_BATTLE_TEST("Move Animations occur before their stat change animations - PLAYER(species) { HP(9997); MaxHP(9999); Item(ITEM_ORAN_BERRY); if (species == SPECIES_WOBBUFFET) Gender(MON_FEMALE); - if (gMovesInfo[move].effect == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); + if (GetMoveEffect(move) == EFFECT_LAST_RESORT) Moves(move, MOVE_POUND); if (species == SPECIES_KLINKLANG) Ability(ABILITY_PLUS); } PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); MaxHP(9999); Moves(MOVE_POUND); - HP(gMovesInfo[move].effect == EFFECT_REVIVAL_BLESSING ? 0 : 9998); + HP(GetMoveEffect(move) == EFFECT_REVIVAL_BLESSING ? 0 : 9998); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_MALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); Ability(ABILITY_TELEPATHY); - if (gMovesInfo[move].effect != EFFECT_BESTOW) + if (GetMoveEffect(move) != EFFECT_BESTOW) Item(ITEM_ORAN_BERRY); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); HP(9998); MaxHP(9999); SpDefense(9999); Defense(9999); } } WHEN { WhenSingles(move, player, opponent); } SCENE { - if (!(gMovesInfo[move].effect == EFFECT_RECYCLE - || gMovesInfo[move].effect == EFFECT_BELCH - || gMovesInfo[move].effect == EFFECT_SPIT_UP - || gMovesInfo[move].effect == EFFECT_SWALLOW - || gMovesInfo[move].effect == EFFECT_TOPSY_TURVY)) // require a move that boosts stats before using this move + if (!(GetMoveEffect(move) == EFFECT_RECYCLE + || GetMoveEffect(move) == EFFECT_BELCH + || GetMoveEffect(move) == EFFECT_SPIT_UP + || GetMoveEffect(move) == EFFECT_SWALLOW + || GetMoveEffect(move) == EFFECT_TOPSY_TURVY)) // require a move that boosts stats before using this move { NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); @@ -1197,9 +1215,10 @@ SINGLE_BATTLE_TEST("Move Animations occur before their stat change animations - SceneSingles(move, player); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1265,9 +1284,10 @@ SINGLE_BATTLE_TEST("Z-Moves don't leak when used - Singles (player to opponent)" ANIMATION(ANIM_TYPE_MOVE, zmove, player); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1294,9 +1314,10 @@ SINGLE_BATTLE_TEST("Z-Moves don't leak when used - Singles (opponent to player)" ANIMATION(ANIM_TYPE_MOVE, zmove, opponent); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1325,9 +1346,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (playerLeft to oppone ANIMATION(ANIM_TYPE_MOVE, zmove, playerLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1356,9 +1378,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (playerLeft to oppone ANIMATION(ANIM_TYPE_MOVE, zmove, playerLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1387,9 +1410,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (playerRight to oppon ANIMATION(ANIM_TYPE_MOVE, zmove, playerRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1418,9 +1442,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (playerRight to oppon ANIMATION(ANIM_TYPE_MOVE, zmove, playerRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1449,9 +1474,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (opponentLeft to play ANIMATION(ANIM_TYPE_MOVE, zmove, opponentLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1480,9 +1506,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (opponentLeft to play ANIMATION(ANIM_TYPE_MOVE, zmove, opponentLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1511,9 +1538,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (opponentRight to pla ANIMATION(ANIM_TYPE_MOVE, zmove, opponentRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1542,9 +1570,10 @@ DOUBLE_BATTLE_TEST("Z-Moves don't leak when used - Doubles (opponentRight to pla ANIMATION(ANIM_TYPE_MOVE, zmove, opponentRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1587,9 +1616,10 @@ SINGLE_BATTLE_TEST("Tera Blast doesn't leak when used - Singles (player to oppon ANIMATION(ANIM_TYPE_MOVE, move, player); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1609,9 +1639,10 @@ SINGLE_BATTLE_TEST("Tera Blast doesn't leak when used - Singles (opponent to pla ANIMATION(ANIM_TYPE_MOVE, move, opponent); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1633,9 +1664,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (playerLeft to o ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1657,9 +1689,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (playerLeft to o ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1681,9 +1714,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (playerRight to ANIMATION(ANIM_TYPE_MOVE, move, playerRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1705,9 +1739,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (playerRight to ANIMATION(ANIM_TYPE_MOVE, move, playerRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1729,9 +1764,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (opponentLeft to ANIMATION(ANIM_TYPE_MOVE, move, opponentLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1753,9 +1789,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (opponentLeft to ANIMATION(ANIM_TYPE_MOVE, move, opponentLeft); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1777,9 +1814,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (opponentRight t ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } @@ -1801,9 +1839,10 @@ DOUBLE_BATTLE_TEST("Tera Blast doesn't leak when used - Doubles (opponentRight t ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); } THEN { FORCE_MOVE_ANIM(FALSE); - if (gLoadFail) - DebugPrintf("Move failed: %S (%u)", gMovesInfo[move].name, move); + if (gLoadFail || gSpriteAllocs != 0) + DebugPrintf("Move failed: %S (%u)", GetMoveName(move), move); EXPECT_EQ(gLoadFail, FALSE); + EXPECT_EQ(gSpriteAllocs, 0); } } diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index e3f99cb73b..8300c7b9c8 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -170,7 +170,7 @@ DOUBLE_BATTLE_TEST("Ally Switch - move fails if the target was ally which change DOUBLE_BATTLE_TEST("Ally Switch doesn't make self-targeting status moves fail") { GIVEN { - ASSUME(gMovesInfo[MOVE_HARDEN].target == MOVE_TARGET_USER); + ASSUME(GetMoveTarget(MOVE_HARDEN) == MOVE_TARGET_USER); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -366,7 +366,7 @@ DOUBLE_BATTLE_TEST("Ally Switch does not update leech seed battler") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_LEECH_SEED_DRAIN, playerLeft); HP_BAR(playerLeft); HP_BAR(opponentLeft); - + MESSAGE("The opposing Ralts used Ally Switch!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_ALLY_SWITCH, opponentRight); MESSAGE("The opposing Ralts and the opposing Bulbasaur switched places!"); diff --git a/test/battle/move_effect/brine.c b/test/battle/move_effect/brine.c index 9165257859..5f1504437d 100644 --- a/test/battle/move_effect/brine.c +++ b/test/battle/move_effect/brine.c @@ -1,4 +1,25 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Brine's power doubles if the target is at 50% or below max HP"); +SINGLE_BATTLE_TEST("Brine's power doubles if the target is at 50% or below max HP", s16 damage) +{ + bool32 halfHP; + PARAMETRIZE { halfHP = FALSE; } + PARAMETRIZE { halfHP = TRUE; } + GIVEN { + ASSUME(GetMoveEffect(MOVE_BRINE) == EFFECT_BRINE); + PLAYER(SPECIES_SQUIRTLE); + OPPONENT(SPECIES_BLISSEY){ + if (halfHP) { + HP((GetMonData(&OPPONENT_PARTY[0], MON_DATA_MAX_HP) / 2) - 1); + } + } + } WHEN { + TURN { MOVE(player, MOVE_BRINE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BRINE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} diff --git a/test/battle/move_effect/curse.c b/test/battle/move_effect/curse.c index bb1de42fba..355972e74e 100644 --- a/test/battle/move_effect/curse.c +++ b/test/battle/move_effect/curse.c @@ -37,16 +37,19 @@ SINGLE_BATTLE_TEST("Curse cuts the user's HP in half when used by Ghost-types") } } -SINGLE_BATTLE_TEST("Curse applies to the user if used with Protean") +SINGLE_BATTLE_TEST("Curse applies to the user if used with Protean/Libero") { + u32 ability, species; + PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_KECLEON; } + PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; } GIVEN { - PLAYER(SPECIES_KECLEON) { Ability(ABILITY_PROTEAN); } + PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, MOVE_CURSE, target: player); } } SCENE { s32 playerMaxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP); - ABILITY_POPUP(player, ABILITY_PROTEAN); + ABILITY_POPUP(player, ability); ANIMATION(ANIM_TYPE_MOVE, MOVE_CURSE, player); HP_BAR(player, damage: playerMaxHP / 2); HP_BAR(player, damage: playerMaxHP / 4); diff --git a/test/battle/move_effect/heal_bell.c b/test/battle/move_effect/heal_bell.c index 67bdfda1b8..b3f6af0c45 100644 --- a/test/battle/move_effect/heal_bell.c +++ b/test/battle/move_effect/heal_bell.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); - ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_HEAL_BELL) == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL); ASSUME(MoveHasAdditionalEffect(MOVE_SPARKLY_SWIRL, MOVE_EFFECT_AROMATHERAPY)); } diff --git a/test/battle/move_effect/magic_coat.c b/test/battle/move_effect/magic_coat.c index 50ed79e194..ca7b78883e 100644 --- a/test/battle/move_effect/magic_coat.c +++ b/test/battle/move_effect/magic_coat.c @@ -32,3 +32,32 @@ SINGLE_BATTLE_TEST("Magic Coat prints the correct message when bouncing back a m STATUS_ICON(opponent, sleep: TRUE); } } + +DOUBLE_BATTLE_TEST("Magic Coat reflects hazards regardless of the user's position") +{ + struct BattlePokemon *coatUser = NULL; + PARAMETRIZE { coatUser = playerLeft; } + PARAMETRIZE { coatUser = playerRight; } + ASSUME(GetMoveEffect(MOVE_SPIKES) == EFFECT_SPIKES); + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(coatUser, MOVE_MAGIC_COAT); MOVE(opponentRight, MOVE_STEALTH_ROCK); MOVE(opponentLeft, MOVE_SPIKES); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAGIC_COAT, coatUser); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponentLeft); + } + } THEN { + EXPECT(!IsHazardOnSide(B_SIDE_PLAYER, HAZARDS_STEALTH_ROCK)); + EXPECT(!IsHazardOnSide(B_SIDE_PLAYER, HAZARDS_SPIKES)); + EXPECT(IsHazardOnSide(B_SIDE_OPPONENT, HAZARDS_STEALTH_ROCK)); + EXPECT(IsHazardOnSide(B_SIDE_OPPONENT, HAZARDS_SPIKES)); + } +} diff --git a/test/battle/move_effect/metronome.c b/test/battle/move_effect/metronome.c index 2419ecb1e4..91865b05cf 100644 --- a/test/battle/move_effect/metronome.c +++ b/test/battle/move_effect/metronome.c @@ -25,6 +25,7 @@ SINGLE_BATTLE_TEST("Metronome picks a random move") SINGLE_BATTLE_TEST("Metronome's called powder move fails against Grass Types") { GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); ASSUME(IsPowderMove(MOVE_POISON_POWDER)); ASSUME(GetSpeciesType(SPECIES_TANGELA, 0) == TYPE_GRASS); ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_NON_VOLATILE_STATUS); diff --git a/test/battle/move_effect/mirror_move.c b/test/battle/move_effect/mirror_move.c index 642998cbcf..2f3c65b827 100644 --- a/test/battle/move_effect/mirror_move.c +++ b/test/battle/move_effect/mirror_move.c @@ -41,6 +41,7 @@ SINGLE_BATTLE_TEST("Mirror Move fails if no move was used before") SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types") { GIVEN { + WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); ASSUME(IsPowderMove(MOVE_STUN_SPORE)); ASSUME(GetSpeciesType(SPECIES_ODDISH, 0) == TYPE_GRASS); ASSUME(GetMoveEffect(MOVE_STUN_SPORE) == EFFECT_NON_VOLATILE_STATUS); diff --git a/test/battle/move_effect/powder.c b/test/battle/move_effect/powder.c index da8eba4caf..0cfeeb0a8d 100644 --- a/test/battle/move_effect/powder.c +++ b/test/battle/move_effect/powder.c @@ -168,7 +168,7 @@ SINGLE_BATTLE_TEST("Powder fails if the target is Grass type (Gen6+)") SINGLE_BATTLE_TEST("Powder fails if the target has Overcoat (Gen6+)") { GIVEN { - WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6); + WITH_CONFIG(GEN_CONFIG_POWDER_OVERCOAT, GEN_6); PLAYER(SPECIES_FORRETRESS) { Ability(ABILITY_OVERCOAT); } OPPONENT(SPECIES_VIVILLON); } WHEN { @@ -223,17 +223,20 @@ DOUBLE_BATTLE_TEST("Powder still blocks the target's Fire type moves even if it } } -SINGLE_BATTLE_TEST("Powder prevents Protean from changing its user to Fire type") +SINGLE_BATTLE_TEST("Powder prevents Protean/Libero from changing its user to Fire type") { + u32 ability, species; + PARAMETRIZE { ability = ABILITY_PROTEAN; species = SPECIES_GRENINJA; } + PARAMETRIZE { ability = ABILITY_LIBERO; species = SPECIES_RABOOT; } GIVEN { - PLAYER(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); } + PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_VIVILLON); } WHEN { TURN { MOVE(opponent, MOVE_POWDER); MOVE(player, MOVE_EMBER); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_POWDER, opponent); NONE_OF { - ABILITY_POPUP(player, ABILITY_PROTEAN); + ABILITY_POPUP(player, ability); ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent); } diff --git a/test/battle/move_effect/psychic_terrain.c b/test/battle/move_effect/psychic_terrain.c index 2c5089c704..51fdb236ef 100644 --- a/test/battle/move_effect/psychic_terrain.c +++ b/test/battle/move_effect/psychic_terrain.c @@ -120,6 +120,8 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves against semi-in PARAMETRIZE { move = MOVE_SOLAR_BEAM; shouldWork = FALSE;} PARAMETRIZE { move = MOVE_FLY; shouldWork = TRUE;} GIVEN { + WITH_CONFIG(GEN_CONFIG_TOXIC_NEVER_MISS, GEN_6); + ASSUME(IsSpeciesOfType(SPECIES_SHROODLE, TYPE_POISON)); PLAYER(SPECIES_SHROODLE) { Ability(ABILITY_PRANKSTER); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/rest.c b/test/battle/move_effect/rest.c index fcf2b15567..af1fb19c8c 100644 --- a/test/battle/move_effect/rest.c +++ b/test/battle/move_effect/rest.c @@ -35,22 +35,6 @@ SINGLE_BATTLE_TEST("Rest fails if the user is at full HP") } } -SINGLE_BATTLE_TEST("Rest fails if the user is protected by Leaf Guard") -{ - GIVEN { - ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); - ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); - PLAYER(SPECIES_CHIKORITA) { Ability(ABILITY_LEAF_GUARD); HP(1); } - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, MOVE_REST); } - } SCENE { - NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_REST, player); - } THEN { - EXPECT(!(player->status1 & STATUS1_SLEEP)); - } -} - SINGLE_BATTLE_TEST("Rest fails if the user is protected by Shields Down") { GIVEN { diff --git a/test/battle/move_effect/return.c b/test/battle/move_effect/return.c index 2a2614200d..2727b1b46e 100644 --- a/test/battle/move_effect/return.c +++ b/test/battle/move_effect/return.c @@ -1,6 +1,46 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Return's power increases the higher friendship of the user is") +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_RETURN) == EFFECT_RETURN); +} + +SINGLE_BATTLE_TEST("Return's power increases the higher friendship of the user is", s16 damage) +{ + u32 friendship; + PARAMETRIZE { friendship = 0; } + PARAMETRIZE { friendship = 100; } + PARAMETRIZE { friendship = 200; } + PARAMETRIZE { friendship = 255; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Friendship(friendship); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RETURN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RETURN, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } THEN { + if (i > 0) + EXPECT_GT(results[i].damage, results[i-1].damage); + } +} + TO_DO_BATTLE_TEST("Return does 0 damage at min Friendship (Gen2)") -TO_DO_BATTLE_TEST("Return does 1 damage at min Friendship (Gen3+)") + +SINGLE_BATTLE_TEST("Return does 1 damage at min Friendship (Gen3+)") +{ + s16 damage; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Friendship(0); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RETURN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RETURN, player); + HP_BAR(opponent, captureDamage: &damage); + } THEN { + EXPECT_EQ(damage, 1); + } +} diff --git a/test/battle/move_effect/shell_trap.c b/test/battle/move_effect/shell_trap.c index 435c79a652..f3f0068d6f 100644 --- a/test/battle/move_effect/shell_trap.c +++ b/test/battle/move_effect/shell_trap.c @@ -198,3 +198,84 @@ DOUBLE_BATTLE_TEST("Shell Trap targets correctly if one of the opponents has fai ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerLeft); } } + +SINGLE_BATTLE_TEST("Shell Trap activates if user is hit with a physical move but does no damage") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_FALSE_SWIPE) == EFFECT_FALSE_SWIPE); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SHELL_TRAP); MOVE(opponent, MOVE_FALSE_SWIPE); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SHELL_TRAP_SETUP, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FALSE_SWIPE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Encore fails if target has active Shell Trap waiting") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_SHELL_TRAP); MOVE(opponent, MOVE_ENCORE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + MESSAGE("Wobbuffet set a shell trap!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, player); + } + } +} + +SINGLE_BATTLE_TEST("Shell Trap fails if an other -3 or lower priority Move is used") +{ + GIVEN { + ASSUME(GetMovePriority(MOVE_DRAGON_TAIL) <= -3); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { + MOVE(player, MOVE_SHELL_TRAP); + MOVE(opponent, MOVE_DRAGON_TAIL); + } + } SCENE { + MESSAGE("Wobbuffet set a shell trap!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, player); + } +} + +DOUBLE_BATTLE_TEST("Shell Trap does not trigger when hit into Substitute") +{ + GIVEN { + ASSUME(GetMoveCategory(MOVE_DOUBLE_EDGE) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SNORLAX); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_SUBSTITUTE); } + TURN { + MOVE(playerLeft, MOVE_SHELL_TRAP); + MOVE(opponentLeft, MOVE_DOUBLE_EDGE, target: playerLeft); + MOVE(opponentRight, MOVE_SCRATCH, target: playerLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, playerLeft); + MESSAGE("Wynaut set a shell trap!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_EDGE, opponentLeft); + MESSAGE("Wynaut's substitute faded!"); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SHELL_TRAP, playerLeft); + } +} diff --git a/test/battle/move_effect/two_typed_move.c b/test/battle/move_effect/two_typed_move.c index 43c3515739..7372222e83 100644 --- a/test/battle/move_effect/two_typed_move.c +++ b/test/battle/move_effect/two_typed_move.c @@ -1,4 +1,12 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("TODO: Write Flying Press (Move Effect) test titles") +TO_DO_BATTLE_TEST("Flying Press does both Fighting and Flying-type for type effectiveness") +TO_DO_BATTLE_TEST("Flying-type Pokémon don't receive STAB on Flying Press") +TO_DO_BATTLE_TEST("Sky Plate doesn't boost Flying Press' power") // Check Fist Plate for comparison +TO_DO_BATTLE_TEST("Sharp Beak doesn't boost Flying Press' power") // Check Black Belt for comparison +TO_DO_BATTLE_TEST("Flying Gem doesn't trigger when using Flying Press") // Check Fighting Gem for comparison +TO_DO_BATTLE_TEST("Coba Berry doesn't trigger when the user is attacked by Flying Press") +TO_DO_BATTLE_TEST("Flying Press triggers Chople Berry, even when it wouldn't be super effective with regular Fighting-type moves") +TO_DO_BATTLE_TEST("Flying Press under Electrify does both Electric and Flying-type for type effectiveness") // Check Electric 1/4 effectiveness +TO_DO_BATTLE_TEST("Flying Press under Normalize does both Normal and Flying-type for type effectiveness") // Check Rock/Steel 1/4 effectiveness diff --git a/test/battle/move_effect_secondary/remove_status.c b/test/battle/move_effect_secondary/remove_status.c index 0a07ef6368..4e62ca55e9 100644 --- a/test/battle/move_effect_secondary/remove_status.c +++ b/test/battle/move_effect_secondary/remove_status.c @@ -118,6 +118,7 @@ TO_DO_BATTLE_TEST("Wake-Up Slap gets increased power against Pokémon with Comat DOUBLE_BATTLE_TEST("Sparkling Aria cures burns from all Pokemon on the field and behind substitutes") { GIVEN { + ASSUME(MoveIgnoresSubstitute(MOVE_SPARKLING_ARIA)); ASSUME(MoveHasAdditionalEffect(MOVE_SPARKLING_ARIA, MOVE_EFFECT_REMOVE_STATUS) == TRUE); ASSUME(GetMoveEffectArg_Status(MOVE_SPARKLING_ARIA) == STATUS1_BURN); PLAYER(SPECIES_PRIMARINA); diff --git a/tools/preproc/asm_file.cpp b/tools/preproc/asm_file.cpp index 10330f1774..6cfc4cbdb3 100644 --- a/tools/preproc/asm_file.cpp +++ b/tools/preproc/asm_file.cpp @@ -633,7 +633,11 @@ bool AsmFile::ParseEnum() RaiseError("%s:%ld: empty enum is invalid", headerFilename.c_str(), currentHeaderLine); } - if (m_buffer[m_pos] != ',') + if (m_buffer[m_pos] == '#') + { + currentHeaderLine = ParseLineSkipInEnum(); + } + else if (m_buffer[m_pos] != ',') { currentHeaderLine += SkipWhitespaceAndEol(); if (m_buffer[m_pos++] == '}' && m_buffer[m_pos++] == ';') @@ -737,6 +741,50 @@ int AsmFile::SkipWhitespaceAndEol() return newlines; } +int AsmFile::ParseLineSkipInEnum(void) +{ + m_pos++; + while (m_buffer[m_pos] == ' ' || m_buffer[m_pos] == '\t') + m_pos++; + + if (!IsAsciiDigit(m_buffer[m_pos])) + RaiseError("malformatted line indicator found inside `enum`, expected line number"); + + unsigned n = 0; + int digit = 0; + while ((digit = ConvertDigit(m_buffer[m_pos++], 10)) != -1) + n = 10 * n + digit; + + while (m_buffer[m_pos] == ' ' || m_buffer[m_pos] == '\t') + m_pos++; + + if (m_buffer[m_pos++] != '"') + RaiseError("malformatted line indicator found before `enum`, expected filename"); + + while (m_buffer[m_pos] != '"') + { + unsigned char c = m_buffer[m_pos++]; + + if (c == 0) + { + if (m_pos >= m_size) + RaiseError("unexpected EOF in line indicator"); + else + RaiseError("unexpected null character in line indicator"); + } + + if (!IsAsciiPrintable(c)) + RaiseError("unexpected character '\\x%02X' in line indicator", c); + + if (c == '\\') + { + c = m_buffer[m_pos]; + RaiseError("unexpected escape '\\%c' in line indicator", c); + } + } + return n - 1; +} + // returns the last line indicator and its corresponding file name without modifying the token index int AsmFile::FindLastLineNumber(std::string& filename) { diff --git a/tools/preproc/asm_file.h b/tools/preproc/asm_file.h index 33e6ce5c49..9cab32a97f 100644 --- a/tools/preproc/asm_file.h +++ b/tools/preproc/asm_file.h @@ -73,6 +73,7 @@ private: void VerifyStringLength(int length); int SkipWhitespaceAndEol(); int FindLastLineNumber(std::string& filename); + int ParseLineSkipInEnum(void); std::string ReadIdentifier(); long ReadInteger(std::string filename, long line); };