Merge branch 'master' of https://github.com/rh-hideout/pokeemerald-expansion into rh-hideout-master
@ -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,
|
||||
|
||||
1
.gitignore
vendored
@ -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
|
||||
|
||||
@ -76,6 +76,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://hashtagmarky.github.io"><img src="https://avatars.githubusercontent.com/u/143505183?v=4?s=100" width="100px;" alt="Marky"/><br /><sub><b>Marky</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=HashtagMarky" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MandL27"><img src="https://avatars.githubusercontent.com/u/10366615?v=4?s=100" width="100px;" alt="MandL27"/><br /><sub><b>MandL27</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=MandL27" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/cawtds"><img src="https://avatars.githubusercontent.com/u/38510667?v=4?s=100" width="100px;" alt="cawtds"/><br /><sub><b>cawtds</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=cawtds" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fdeblasio"><img src="https://avatars.githubusercontent.com/u/35279583?v=4?s=100" width="100px;" alt="Frank DeBlasio"/><br /><sub><b>Frank DeBlasio</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=fdeblasio" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://vriska.dev"><img src="https://avatars.githubusercontent.com/u/8355305?v=4?s=100" width="100px;" alt="leo60228"/><br /><sub><b>leo60228</b></sub></a><br /><a href="https://github.com/rh-hideout/pokeemerald-expansion/commits?author=leo60228" title="Documentation">📖</a> <a href="#data-leo60228" title="Data">🔣</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
|
||||
@ -1841,7 +1841,6 @@
|
||||
|
||||
.macro setmoveeffect effect:req
|
||||
sethword sMOVE_EFFECT, \effect
|
||||
sethword sSAVED_MOVE_EFFECT, \effect
|
||||
.endm
|
||||
|
||||
.macro sethword dst:req, value:req
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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::
|
||||
|
||||
@ -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::
|
||||
|
||||
@ -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::
|
||||
|
||||
@ -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
|
||||
|
Before Width: | Height: | Size: 20 KiB |
BIN
graphics/battle_anims/backgrounds/rainbow_opponent_tile.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
graphics/battle_anims/backgrounds/rainbow_player_tile.bin
Normal file
BIN
graphics/battle_anims/backgrounds/rainbow_player_tile.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1004 B |
|
Before Width: | Height: | Size: 501 B After Width: | Height: | Size: 505 B |
|
Before Width: | Height: | Size: 895 B After Width: | Height: | Size: 833 B |
|
Before Width: | Height: | Size: 672 B After Width: | Height: | Size: 703 B |
|
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 523 B |
|
Before Width: | Height: | Size: 925 B After Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 422 B |
|
Before Width: | Height: | Size: 1002 B After Width: | Height: | Size: 956 B |
|
Before Width: | Height: | Size: 596 B After Width: | Height: | Size: 584 B |
|
Before Width: | Height: | Size: 538 B After Width: | Height: | Size: 569 B |
|
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 506 B |
|
Before Width: | Height: | Size: 512 B After Width: | Height: | Size: 548 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 735 B After Width: | Height: | Size: 733 B |
9
include/battle.h
Normal file → Executable file
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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
|
||||
|
||||
1225
sound/song_table.inc
@ -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)];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,7 +4524,11 @@ 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++)
|
||||
{
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(moves[i], j);
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_SPD_MINUS_1:
|
||||
case MOVE_EFFECT_SPD_MINUS_2:
|
||||
@ -4547,6 +4541,7 @@ static bool32 HasMoveThatChangesKOThreshold(u32 battlerId, u32 noOfHitsToFaint,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
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,8 +2250,13 @@ 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;
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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},
|
||||
};
|
||||
|
||||
@ -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,10 +121,7 @@ static void GetHexStringFromU32(u8 *str, u32 value)
|
||||
}
|
||||
}
|
||||
|
||||
void DecompressionError_CB2(void)
|
||||
{
|
||||
static const struct WindowTemplate textWin[] =
|
||||
{
|
||||
static const struct WindowTemplate sTextWin =
|
||||
{
|
||||
.bg = 0,
|
||||
.tilemapLeft = 3,
|
||||
@ -133,9 +130,11 @@ void DecompressionError_CB2(void)
|
||||
.height = 16,
|
||||
.paletteNum = 15,
|
||||
.baseBlock = 1,
|
||||
}
|
||||
};
|
||||
|
||||
void DecompressionError_CB2(void)
|
||||
{
|
||||
|
||||
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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
//************************************
|
||||
//* *
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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 },
|
||||
|
||||
10
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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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")
|
||||
{
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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); }
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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!");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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!");
|
||||
if (config == GEN_6) {
|
||||
NOT ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE);
|
||||
}
|
||||
else {
|
||||
ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE);
|
||||
}
|
||||
} THEN {
|
||||
if (config == GEN_6)
|
||||
EXPECT_EQ(player->status1, 0);
|
||||
else
|
||||
EXPECT_NE(player->status1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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); }
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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); }
|
||||
|
||||