Merge branch 'upcoming' into gen9-species-nomigration

This commit is contained in:
Eduardo Quezada D'Ottone 2023-11-06 13:49:02 -03:00 committed by GitHub
commit 4aa14355d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 720 additions and 212 deletions

View File

@ -28,7 +28,9 @@ jobs:
repository: pret/agbcc
- name: Install binutils
run: sudo apt install -y build-essential libpng-dev libelf-dev
run: |
sudo apt update
sudo apt install -y build-essential libpng-dev libelf-dev
# build-essential, git, and libpng-dev are already installed
# gcc-arm-none-eabi is only needed for the modern build
# as an alternative to dkP

View File

@ -4061,58 +4061,57 @@ Move_BUG_BITE:
end
Move_CHARGE_BEAM:
loadspritegfx ANIM_TAG_BLACK_BALL_2
loadspritegfx ANIM_TAG_ELECTRIC_ORBS
loadspritegfx ANIM_TAG_CIRCLE_OF_LIGHT
loadspritegfx ANIM_TAG_ELECTRICITY
loadspritegfx ANIM_TAG_SPARK_2
delay 0
createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_ATTACKER), -31, 1, 5, 5, RGB(31, 31, 22)
playsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER
createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, 0, 1, 0
delay 0
createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 80, 24, 22, 12, 0, 1, 0
createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 156, 24, 121, 13, 0, 1, 1
delay 0
createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_ATTACKER), -31, 1, 0, 0, RGB(31, 31, 22)
delay 10
createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_ATTACKER), -31, 1, 5, 5, RGB(31, 31, 22)
playsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER
createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 100, 24, 60, 10, 0, 1, 0
createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 170, 24, 42, 11, 0, 1, 1
delay 0
createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 238, 24, 165, 10, 0, 1, 1
delay 0
createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_ATTACKER), -31, 1, 0, 0, RGB(31, 31, 22)
setalpha 12, 8
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, F_PAL_BG, 2, 0, 4, RGB_BLACK
waitforvisualfinish
createvisualtask AnimTask_ElectricChargingParticles, 2, ANIM_ATTACKER, 20, 0, 2
playsewithpan SE_M_CHARGE, SOUND_PAN_ATTACKER
delay 12
createsprite gGrowingShockWaveOrbSpriteTemplate, ANIM_ATTACKER, 2
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_ATTACKER, 2, 0, 11, RGB(31, 31, 22)
delay 50
createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 1, 16, 0, 5
createvisualtask AnimTask_ShakeMon, 2, ANIM_ATTACKER, 0, 4, 50, 1
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 4, 0, 50, 1
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_ATTACKER, 2, 11, 0, RGB(31, 31, 22)
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 2, 0, 11, RGB(31, 31, 22)
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
call SparkBeam
delay 20
createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_ATTACKER), -31, 1, 7, 7, RGB(31, 31, 22)
playsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 32, 12, 0, 20, 0, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 32, 12, 64, 20, 1, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 32, 12, 128, 20, 0, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 32, 12, 192, 20, 2, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 16, 12, 32, 20, 0, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 16, 12, 96, 20, 1, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 16, 12, 160, 20, 0, 0
createsprite gSparkElectricityFlashingSpriteTemplate, ANIM_ATTACKER, 4, 0, 0, 16, 12, 224, 20, 2, 0
delay 4
waitforvisualfinish
createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_ATTACKER), -31, 1, 0, 0, RGB(31, 31, 22)
playsewithpan SE_M_THUNDER_WAVE, SOUND_PAN_ATTACKER
createsprite gZapCannonBallSpriteTemplate, ANIM_TARGET, 3, 10, 0, 0, 0, 30, 0
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 16, 30, 0, 40, 0
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 16, 30, 64, 40, 1
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 16, 30, 128, 40, 0
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 16, 30, 192, 40, 2
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 8, 30, 32, 40, 0
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 8, 30, 96, 40, 1
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 8, 30, 160, 40, 0
createsprite gZapCannonSparkSpriteTemplate, ANIM_TARGET, 4, 10, 0, 8, 30, 224, 40, 2
waitforvisualfinish
createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 4, 0, 5, 1
delay 15
waitplaysewithpan SE_M_THUNDERBOLT2, SOUND_PAN_TARGET, 19
call ElectricityEffect
createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 2, 11, 0, RGB(31, 31, 22)
waitforvisualfinish
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, F_PAL_BG, 4, 4, 0, RGB_BLACK
blendoff
end
SparkBeam:
createsprite gSparkBeamSpriteTemplate, ANIM_ATTACKER, 3, 0, 0, 0, 0
delay 1
createsprite gSparkBeamSpriteTemplate, ANIM_ATTACKER, 3, 0, 0, 0, 0
delay 1
return
Move_WOOD_HAMMER:
loadspritegfx ANIM_TAG_WOOD_HAMMER
loadspritegfx ANIM_TAG_WOOD_HAMMER_HAMMER
@ -4297,22 +4296,22 @@ Move_HEAL_ORDER:
Move_HEAD_SMASH:
loadspritegfx ANIM_TAG_IMPACT
call SetImpactBackground
createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 2, 0
loadspritegfx ANIM_TAG_ROCKS
createvisualtask AnimTask_SkullBashPosition, 2, 0
playsewithpan SE_M_TAKE_DOWN, SOUND_PAN_ATTACKER
waitforvisualfinish
delay 2
createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 2, 1
playse SE_BANG
call SetImpactBackground
createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_ATTACKER, 2, 0, 40, 1
createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 10, 0, 40, 1
createsprite gFlashingHitSplatSpriteTemplate, ANIM_TARGET, 4, 0, 0, ANIM_TARGET, 0
playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET
createsprite gRockScatterSpriteTemplate, ANIM_TARGET, 2, -12, 32, 3, 4
createsprite gRockScatterSpriteTemplate, ANIM_TARGET, 2, 8, 31, 2, 2
createsprite gRockScatterSpriteTemplate, ANIM_TARGET, 2, -4, 28, 2, 3
createsprite gRockScatterSpriteTemplate, ANIM_TARGET, 2, 12, 30, 4, 3
waitforvisualfinish
createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_ATTACKER, 2, 0, 4, 1
createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 5, 0, 6, 1
createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 2, 2
createsprite gFlashingHitSplatSpriteTemplate, ANIM_TARGET, 3, 0, 0, 1, 1
loopsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET, 8, 3
waitforvisualfinish
clearmonbg ANIM_TARGET
blendoff
delay 2
createvisualtask AnimTask_SkullBashPosition, 2, 1
restorebg
waitbgfadein
end
@ -4861,19 +4860,82 @@ Move_WONDER_ROOM::
end
Move_PSYSHOCK:
loadspritegfx ANIM_TAG_RED_ORB_2
loadspritegfx ANIM_TAG_POISON_JAB
loadspritegfx ANIM_TAG_GRAY_SMOKE
loadspritegfx ANIM_TAG_WISP_FIRE
monbg ANIM_TARGET
setalpha 8, 8
playsewithpan SE_M_SUPERSONIC, SOUND_PAN_ATTACKER
createvisualtask AnimTask_ShakeMon2, 2, ANIM_ATTACKER, 1, 0, 10, 1
createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_ATTACKER, 0, 2, 0, 8, RGB(31, 23, 0)
createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_ATTACKER, 0, 2, 0, 8, RGB_WHITE
waitforvisualfinish
loopsewithpan SE_M_SUPERSONIC, SOUND_PAN_TARGET, 10, 3
createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 5, 0, 15, 1
createvisualtask AnimTask_ScaleMonAndRestore, 5, -6, -6, 15, ANIM_TARGET, 1
delay 10
call PsyshockConverge
waitforvisualfinish
clearmonbg ANIM_TARGET
blendoff
end
PsyshockConverge:
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 40, 40, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, -40, -40, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 0, 40, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 0, -40, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 40, -20, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 40, 20, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, -40, -20, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, -40, 20, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, -20, 30, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 20, -30, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, -20, -30, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 20, 30, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, -40, 0, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockOrbSpriteTemplate, ANIM_TARGET, 2, 40, 0, 16
playsewithpan SE_M_SWIFT, SOUND_PAN_TARGET
delay 6
createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 5, 0, 15, 1
createvisualtask AnimTask_BlendMonInAndOut, 5, ANIM_TARGET, RGB_WHITE, 12, 0, 1
createsprite gPsyshockSmokeSpriteTemplate, ANIM_TARGET, 2, 8, 8, 1, 0
playsewithpan SE_M_SWAGGER, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockSmokeSpriteTemplate, ANIM_TARGET, 2, -8, -8, 1, 0
playsewithpan SE_M_SWAGGER, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockSmokeSpriteTemplate, ANIM_TARGET, 2, 8, -8, 1, 0
playsewithpan SE_M_SWAGGER, SOUND_PAN_TARGET
delay 2
createsprite gPsyshockSmokeSpriteTemplate, ANIM_TARGET, 2, -8, 8, 1, 0
playsewithpan SE_M_SWAGGER, SOUND_PAN_TARGET
delay 2
return
Move_VENOSHOCK:
loadspritegfx ANIM_TAG_POISON_BUBBLE
loadspritegfx ANIM_TAG_TOXIC_BUBBLE
@ -5802,23 +5864,79 @@ Move_QUASH:
Move_ACROBATICS:
loadspritegfx ANIM_TAG_ROUND_SHADOW
loadspritegfx ANIM_TAG_WHITE_STREAK
loadspritegfx ANIM_TAG_IMPACT
monbg ANIM_TARGET
setalpha 12, 8
playsewithpan SE_M_FLY, SOUND_PAN_ATTACKER
createsprite gFlyBallUpSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 13, 336
waitforvisualfinish
playsewithpan SE_M_SWAGGER, SOUND_PAN_TARGET
createsprite gBounceBallLandSpriteTemplate, ANIM_TARGET, 3
delay 7
playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET
createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 0
createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 5, 11, 1
call SetSkyBg
call AcrobaticsSlashes
waitforvisualfinish
clearmonbg ANIM_TARGET
blendoff
visible ANIM_ATTACKER
call UnsetSkyBg
end
AcrobaticsSlashes:
createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 4, 0, 40, 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -10, 3
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 24, -19
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -28, -15
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -6, -30
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -20, 6
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 28, 2
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -14, -25
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 9, -2
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -1, 0
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 21, 4
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 28, 20
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -7, 24
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -11, 1
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 12, -18
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -21, -14
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -29, 7
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, 15, 28
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 1
createsprite gAcrobaticsSlashesSpriteTemplate, ANIM_TARGET, 2, -21, -16
playsewithpan SE_M_CUT, SOUND_PAN_TARGET
delay 2
return
Move_REFLECT_TYPE:
loadspritegfx ANIM_TAG_GUARD_RING @ring around user
loadspritegfx ANIM_TAG_ICE_CHUNK @blue green color
@ -8313,17 +8431,99 @@ Move_FELL_STINGER:
end
Move_PHANTOM_FORCE:
choosetwoturnanim PhantomForceSetUp, PhantomForceUnleash
PhantomForceEnd:
loadspritegfx ANIM_TAG_ROUND_SHADOW
loadspritegfx ANIM_TAG_IMPACT
choosetwoturnanim PhantomForcePrep PhantomForceAttack
PhantomForceWaitEnd:
waitforvisualfinish
restorebg
waitbgfadein
end
PhantomForceSetUp:
PhantomForcePrep:
monbg ANIM_ATTACKER
fadetobg BG_GHOST
waitbgfadein
delay 0
playsewithpan SE_M_FAINT_ATTACK, SOUND_PAN_ATTACKER
createvisualtask AnimTask_TranslateMonEllipticalRespectSide, 2, ANIM_ATTACKER, 18, 6, 1, 3
createvisualtask AnimTask_AttackerFadeToInvisible, 2, 1
waitforvisualfinish
clearmonbg ANIM_ATTACKER
invisible ANIM_ATTACKER
goto PhantomForceEnd
PhantomForceUnleash:
visible ANIM_ATTACKER
goto PhantomForceEnd
delay 1
goto PhantomForceWaitEnd
PhantomForceAttack:
loadspritegfx ANIM_TAG_PURPLE_FLAME
loadspritegfx ANIM_TAG_WHITE_SHADOW @Destiny Bond
monbg ANIM_ATTACKER
splitbgprio ANIM_ATTACKER
fadetobg BG_GHOST
waitbgfadein
delay 1
createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT, 0, 12, 12, RGB(0, 0, 23)
setalpha 12, 8
waitforvisualfinish
delay 10
playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER
createvisualtask AnimTask_PurpleFlamesOnTarget, 0x3
createvisualtask AnimTask_DestinyBondWhiteShadow, 0x5, 0x0, 0x30
delay 30
createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT, 0, 12, 12, RGB(0, 0, 23)
waitforvisualfinish
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_TARGET, 2
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_TARGET, 2
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_TARGET, 2
createvisualtask SoundTask_PlaySE1WithPanning, 5, 215, SOUND_PAN_TARGET
delay 3
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_TARGET, 2
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_DEF_PARTNER, 2
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_ATK_PARTNER, 2
createvisualtask SoundTask_PlaySE1WithPanning, 5, 215, SOUND_PAN_TARGET
delay 3
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_TARGET, 2
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_DEF_PARTNER, 2
createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 3, ANIM_ATK_PARTNER, 2
createvisualtask SoundTask_PlaySE1WithPanning, 5, 215, SOUND_PAN_TARGET
delay 3
createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 2, 0, 12, 1
createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_TARGET, 0, 2, 0, 13, RGB_PURPLE
waitforvisualfinish
delay 1
playsewithpan SOUND_PAN_ATTACKER, 192
createvisualtask AnimTask_NightShadeClone, 5, 10
waitforvisualfinish
clearmonbg ANIM_ATTACKER
delay 1
goto PhantomForceWaitEnd
PhantomForceBg:
fadetobg BG_DARK
waitbgfadeout
createvisualtask AnimTask_FadeScreenToWhite, 5
waitbgfadein
return
Move_TRICK_OR_TREAT:
loadspritegfx ANIM_TAG_EYE_SPARKLE
loadspritegfx ANIM_TAG_GHOSTLY_SPIRIT
fadetobg BG_NIGHTMARE
waitbgfadein
delay 10
playsewithpan SE_M_PSYBEAM, SOUND_PAN_ATTACKER
createvisualtask AnimTask_ShakeMon2, 2, ANIM_ATTACKER, 1, 0, 10, 1
createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_ATTACKER, 0, 2, 0, 8, RGB(10, 2, 19)
waitforvisualfinish
playsewithpan SE_M_LEER, SOUND_PAN_ATTACKER
createvisualtask AnimTask_ScaryFace, 5
delay 13
waitforvisualfinish
createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_TARGET, 2, 2, 0, 12, RGB(10, 2, 19) @;Deep purple
playsewithpan SE_M_NIGHTMARE, SOUND_PAN_TARGET
createsprite gCurseGhostSpriteTemplate, ANIM_TARGET, 2
createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 2, 0, 14, 1
waitforvisualfinish
clearmonbg ANIM_TARGET
restorebg
waitbgfadein
end
Move_NOBLE_ROAR:

View File

@ -0,0 +1,19 @@
JASC-PAL
0100
16
180 180 180
11 15 16
33 19 27
59 38 38
102 90 92
200 124 124
182 116 141
255 124 189
227 140 140
253 155 155
222 173 189
255 175 175
195 191 192
252 161 206
225 221 223
245 245 245

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

View File

@ -672,7 +672,7 @@ struct BattleStruct
u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum
u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct
u16 tracedAbility[MAX_BATTLERS_COUNT];
u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk
u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell.
bool8 spriteIgnore0Hp;
struct Illusion illusion[MAX_BATTLERS_COUNT];
s32 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier

View File

@ -91,7 +91,6 @@ bool32 AI_IsDamagedByRecoil(u32 battler);
u32 GetNoOfHitsToKO(u32 dmg, s32 hp);
u32 GetNoOfHitsToKOBattlerDmg(u32 dmg, u32 battlerDef);
u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex);
bool32 IsInIgnoredPowerfulMoveEffects(u32 effect);
void SetMovesDamageResults(u32 battlerAtk, u16 *moves);
u32 GetMoveDamageResult(u32 battlerAtk, u32 battlerDef, u32 moveIndex);
u32 GetCurrDamageHpPercent(u32 battlerAtk, u32 battlerDef);
@ -113,6 +112,7 @@ bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility);
bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move);
bool32 IsHazardMoveEffect(u32 moveEffect);
bool32 IsEncoreEncouragedEffect(u32 moveEffect);
bool32 IsChargingMove(u32 battlerAtk, u32 effect);
void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score);
bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect);
bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect);

View File

@ -25,10 +25,10 @@
// Species-specific settings
#define P_SHEDINJA_BALL GEN_LATEST // Since Gen 4, Shedinja requires a Poké Ball for its evolution. In Gen 3, Shedinja inherits Nincada's Ball.
#define P_KADABRA_EVERSTONE GEN_LATEST // Since Gen 4, Kadabra can evolve even when holding an Everstone.
#define P_HIPPO_GENDER_DIFF_ICONS TRUE // If TRUE, will give Hippopotas and Hippowdon custom icons for their female forms.
#define P_SHUCKLE_BERRY_JUICE TRUE // In Gen 2, Shuckle had a 1/16 chance of converting Berry that it's holding into Berry Juice. Setting this to TRUE will allow to do this with an Oran Berry, which is the spiritual succesor of the Berry item.
// Other settings
#define P_CUSTOM_GENDER_DIFF_ICONS TRUE // If TRUE, will give more Pokémon custom icons for their female forms, i.e. Hippopotas and Hippowdon
#define P_LEGENDARY_PERFECT_IVS GEN_LATEST // Since Gen 6, Legendaries, Mythicals and Ultra Beasts found in the wild or given through gifts have at least 3 perfect IVs.
#define P_EV_CAP GEN_LATEST // Since Gen 6, the max EVs per stat is 252 instead of 255.

View File

@ -301,16 +301,16 @@
#define MOVEEND_ATTACKER_VISIBLE 10
#define MOVEEND_TARGET_VISIBLE 11
#define MOVEEND_ITEM_EFFECTS_TARGET 12
#define MOVEEND_ITEM_EFFECTS_ALL 13
#define MOVEEND_KINGSROCK 14 // These item effects will occur each strike of a multi-hit move
#define MOVEEND_SUBSTITUTE 15
#define MOVEEND_SKY_DROP_CONFUSE 16
#define MOVEEND_UPDATE_LAST_MOVES 17
#define MOVEEND_MIRROR_MOVE 18
#define MOVEEND_NEXT_TARGET 19 // Everything up until here is handled for each strike of a multi-hit move
#define MOVEEND_MULTIHIT_MOVE 20
#define MOVEEND_DEFROST 21
#define MOVEEND_MOVE_EFFECTS2 22
#define MOVEEND_MOVE_EFFECTS2 13
#define MOVEEND_ITEM_EFFECTS_ALL 14
#define MOVEEND_KINGSROCK 15 // These item effects will occur each strike of a multi-hit move
#define MOVEEND_SUBSTITUTE 16
#define MOVEEND_SKY_DROP_CONFUSE 17
#define MOVEEND_UPDATE_LAST_MOVES 18
#define MOVEEND_MIRROR_MOVE 19
#define MOVEEND_NEXT_TARGET 20 // Everything up until here is handled for each strike of a multi-hit move
#define MOVEEND_MULTIHIT_MOVE 21
#define MOVEEND_DEFROST 22
#define MOVEEND_RECOIL 23
#define MOVEEND_MAGICIAN 24 // Occurs after final multi-hit strike, and after other items/abilities would activate
#define MOVEEND_EJECT_BUTTON 25

View File

@ -5227,6 +5227,9 @@ extern const u8 gMonIcon_Fearow[];
extern const u8 gMonIcon_Ekans[];
extern const u8 gMonIcon_Arbok[];
extern const u8 gMonIcon_Pikachu[];
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
extern const u8 gMonIcon_PikachuF[];
#endif
extern const u8 gMonIcon_Raichu[];
extern const u8 gMonIcon_Sandshrew[];
extern const u8 gMonIcon_Sandslash[];
@ -5404,6 +5407,9 @@ extern const u8 gMonIcon_Slowking[];
extern const u8 gMonIcon_Misdreavus[];
extern const u8 gMonIcon_Unown[];
extern const u8 gMonIcon_Wobbuffet[];
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
extern const u8 gMonIcon_WobbuffetF[];
#endif
extern const u8 gMonIcon_Girafarig[];
extern const u8 gMonIcon_Pineco[];
extern const u8 gMonIcon_Forretress[];
@ -5653,7 +5659,7 @@ extern const u8 gMonIcon_Riolu[];
extern const u8 gMonIcon_Lucario[];
extern const u8 gMonIcon_Hippopotas[];
extern const u8 gMonIcon_Hippowdon[];
#if P_HIPPO_GENDER_DIFF_ICONS == TRUE
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
extern const u8 gMonIcon_HippopotasF[];
extern const u8 gMonIcon_HippowdonF[];
#endif
@ -10058,6 +10064,9 @@ extern const u32 gItemIconPalette_LustrousGlobe[];
extern const u32 gItemIcon_BerserkGene[];
extern const u32 gItemIconPalette_BerserkGene[];
extern const u32 gItemIcon_FairyFeather[];
extern const u32 gItemIconPalette_FairyFeather[];
extern const u32 gItemIcon_ReturnToFieldArrow[];
extern const u32 gItemIconPalette_ReturnToFieldArrow[];

View File

@ -760,6 +760,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move
if (IsChargingMove(battlerAtk, moveEffect) && CanTargetFaintAi(battlerDef, battlerAtk))
RETURN_SCORE_MINUS(10);
// check if negates type
switch (effectiveness)
{
@ -1356,22 +1359,13 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
}
break;
//case EFFECT_BIDE:
//case EFFECT_SUPER_FANG:
//case EFFECT_RECHARGE:
case EFFECT_LEVEL_DAMAGE:
case EFFECT_PSYWAVE:
//case EFFECT_COUNTER:
//case EFFECT_FLAIL:
case EFFECT_RETURN:
case EFFECT_PRESENT:
case EFFECT_FRUSTRATION:
case EFFECT_SONICBOOM:
//case EFFECT_MIRROR_COAT:
case EFFECT_SKULL_BASH:
case EFFECT_FOCUS_PUNCH:
case EFFECT_SUPERPOWER:
//case EFFECT_ENDEAVOR:
case EFFECT_LOW_KICK:
// AI_CBM_HighRiskForDamage
if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2)
ADJUST_SCORE(-10);
@ -1906,17 +1900,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|| (gBattleMons[battlerDef].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))) //Leave out Illusion b/c AI is supposed to be fooled
ADJUST_SCORE(-10);
break;
case EFFECT_TWO_TURNS_ATTACK:
if (aiData->holdEffects[battlerAtk] != HOLD_EFFECT_POWER_HERB && CanTargetFaintAi(battlerDef, battlerAtk))
ADJUST_SCORE(-6);
break;
case EFFECT_RECHARGE:
if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2)
ADJUST_SCORE(-10);
else if (aiData->abilities[battlerAtk] != ABILITY_TRUANT
&& !CanIndexMoveFaintTarget(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex, 0))
ADJUST_SCORE(-2);
break;
case EFFECT_SPITE:
case EFFECT_MIMIC:
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker should go first
@ -2109,13 +2092,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case EFFECT_SPECTRAL_THIEF:
break;
case EFFECT_SOLAR_BEAM:
if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB
|| ((AI_GetWeather(aiData) & B_WEATHER_SUN) && aiData->holdEffects[battlerAtk] != HOLD_EFFECT_UTILITY_UMBRELLA))
break;
if (CanTargetFaintAi(battlerDef, battlerAtk)) //Attacker can be knocked out
ADJUST_SCORE(-4);
break;
case EFFECT_SEMI_INVULNERABLE:
if (predictedMove != MOVE_NONE
&& AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER
@ -2674,6 +2650,10 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
&& !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF))
ADJUST_SCORE(-10);
break;
case EFFECT_LOW_KICK:
if (IsDynamaxed(battlerDef))
ADJUST_SCORE(-10);
break;
case EFFECT_PLACEHOLDER:
return 0; // cannot even select
} // move effect checks
@ -3151,7 +3131,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
s32 score = 0;
s32 leastHits = 1000;
u16 *moves = GetMovesArray(battlerAtk);
bool8 isPowerfulIgnoredEffect[MAX_MON_MOVES];
bool8 isChargingMoveEffect[MAX_MON_MOVES];
for (i = 0; i < MAX_MON_MOVES; i++)
{
@ -3163,13 +3143,13 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
leastHits = noOfHits[i];
}
viableMoveScores[i] = AI_SCORE_DEFAULT;
isPowerfulIgnoredEffect[i] = IsInIgnoredPowerfulMoveEffects(gBattleMoves[moves[i]].effect);
isChargingMoveEffect[i] = IsChargingMove(battlerAtk, gBattleMoves[moves[i]].effect);
}
else
{
noOfHits[i] = -1;
viableMoveScores[i] = 0;
isPowerfulIgnoredEffect[i] = FALSE;
isChargingMoveEffect[i] = FALSE;
}
/*
MgbaPrintf_("%S: required hits: %d Dmg: %d", gMoveNames[moves[i]], noOfHits[i], AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]);
@ -3178,7 +3158,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
// Priority list:
// 1. Less no of hits to ko
// 2. Not in the powerful but ignored move effects table
// 2. Not charging
// 3. More accuracy
// 4. Better effect
@ -3193,9 +3173,9 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
{
multipleBestMoves = TRUE;
// We need to make sure it's the current move which is objectively better.
if (isPowerfulIgnoredEffect[i] && !isPowerfulIgnoredEffect[currId])
if (isChargingMoveEffect[i] && !isChargingMoveEffect[currId])
viableMoveScores[i] -= 3;
else if (!isPowerfulIgnoredEffect[i] && isPowerfulIgnoredEffect[currId])
else if (!isChargingMoveEffect[i] && isChargingMoveEffect[currId])
viableMoveScores[currId] -= 3;
switch (CompareMoveAccuracies(battlerAtk, battlerDef, currId, i))
@ -4847,15 +4827,6 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
IncreasePoisonScore(battlerAtk, battlerDef, move, &score);
IncreaseStatUpScore(battlerAtk, battlerDef, STAT_SPEED, &score);
break;
case EFFECT_SOLAR_BEAM:
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, movesetIndex) >= 2
&& HasMoveEffect(battlerAtk, EFFECT_SUNNY_DAY) && (AI_GetWeather(aiData) & B_WEATHER_SUN)) // Use Sunny Day to boost damage.
ADJUST_SCORE(-3);
case EFFECT_TWO_TURNS_ATTACK:
case EFFECT_SKULL_BASH:
if (aiData->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB)
ADJUST_SCORE(2);
break;
case EFFECT_COUNTER:
if (!IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) && predictedMove != MOVE_NONE)
{
@ -5246,9 +5217,6 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
case EFFECT_BELLY_DRUM:
case EFFECT_PSYCH_UP:
case EFFECT_MIRROR_COAT:
case EFFECT_SOLAR_BEAM:
case EFFECT_TWO_TURNS_ATTACK:
case EFFECT_ERUPTION:
case EFFECT_TICKLE:
case EFFECT_SUNNY_DAY:
case EFFECT_SANDSTORM:

View File

@ -363,25 +363,6 @@ static const u16 sEncouragedEncoreEffects[] =
EFFECT_CAMOUFLAGE,
};
// For the purposes of determining the most powerful move in a moveset, these
// moves are treated the same as having a power of 0 or 1
#define IGNORED_MOVES_END 0xFFFF
static const u16 sIgnoredPowerfulMoveEffects[] =
{
EFFECT_EXPLOSION,
EFFECT_DREAM_EATER,
EFFECT_RECHARGE,
EFFECT_SKULL_BASH,
EFFECT_SOLAR_BEAM,
EFFECT_FOCUS_PUNCH,
EFFECT_SUPERPOWER,
EFFECT_ERUPTION,
EFFECT_OVERHEAT,
EFFECT_MIND_BLOWN,
EFFECT_MAKE_IT_RAIN,
IGNORED_MOVES_END
};
// Functions
u32 GetAIChosenMove(u32 battlerId)
{
@ -980,6 +961,11 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
switch (gBattleMoves[move].effect)
{
case EFFECT_RECHARGE:
case EFFECT_SUPERPOWER:
case EFFECT_OVERHEAT:
case EFFECT_MAKE_IT_RAIN:
case EFFECT_MIND_BLOWN:
case EFFECT_STEEL_BEAM:
return TRUE;
case EFFECT_RECOIL_25:
case EFFECT_RECOIL_IF_MISS:
@ -1054,22 +1040,6 @@ u32 GetNoOfHitsToKOBattler(u32 battlerAtk, u32 battlerDef, u32 moveIndex)
return GetNoOfHitsToKOBattlerDmg(AI_DATA->simulatedDmg[battlerAtk][battlerDef][moveIndex], battlerDef);
}
bool32 IsInIgnoredPowerfulMoveEffects(u32 effect)
{
u32 i;
for (i = 0; sIgnoredPowerfulMoveEffects[i] != IGNORED_MOVES_END; i++)
{
if (effect == sIgnoredPowerfulMoveEffects[i])
{
// Don't ingore Solar Beam if doesn't have a charging turn.
if (effect == EFFECT_SOLAR_BEAM && (AI_GetWeather(AI_DATA) & B_WEATHER_SUN))
break;
return TRUE;
}
}
return FALSE;
}
void SetMovesDamageResults(u32 battlerAtk, u16 *moves)
{
s32 i, j, battlerDef, bestId, currId, hp, result;
@ -1079,7 +1049,7 @@ void SetMovesDamageResults(u32 battlerAtk, u16 *moves)
for (i = 0; i < MAX_MON_MOVES; i++)
{
u32 move = moves[i];
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || gBattleMoves[move].power == 0 || IsInIgnoredPowerfulMoveEffects(gBattleMoves[move].effect))
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || gBattleMoves[move].power == 0)
isNotConsidered[i] = TRUE;
else
isNotConsidered[i] = FALSE;
@ -1094,11 +1064,10 @@ void SetMovesDamageResults(u32 battlerAtk, u16 *moves)
if (isNotConsidered[i])
{
result = MOVE_POWER_OTHER; // Move has a power of 0/1, or is in the group sIgnoredPowerfulMoveEffects
result = MOVE_POWER_OTHER; // Move has a power of 0/1
}
else
{
// Considered move has power and is not in sIgnoredPowerfulMoveEffects
// Check all other moves and calculate their power
for (j = 0; j < MAX_MON_MOVES; j++)
{
@ -2394,6 +2363,24 @@ bool32 IsEncoreEncouragedEffect(u32 moveEffect)
return FALSE;
}
bool32 IsChargingMove(u32 battlerAtk, u32 effect)
{
switch (effect)
{
case EFFECT_SOLAR_BEAM:
if (AI_GetWeather(AI_DATA) & B_WEATHER_SUN)
return FALSE;
case EFFECT_SKULL_BASH:
case EFFECT_METEOR_BEAM:
case EFFECT_TWO_TURNS_ATTACK:
if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB)
return FALSE;
return TRUE;
default:
return FALSE;
}
}
static u32 GetLeechSeedDamage(u32 battlerId)
{
u32 damage = 0;

View File

@ -158,6 +158,7 @@ static void AnimRockPolishSparkle(struct Sprite *);
static void AnimPoisonJabProjectile(struct Sprite *);
static void AnimNightSlash(struct Sprite *);
static void AnimPluck(struct Sprite *);
static void AnimAcrobaticsSlashes(struct Sprite *);
const union AnimCmd gPowderParticlesAnimCmds[] =
{
@ -3006,6 +3007,61 @@ const struct SpriteTemplate gSeedFlareGreenCirclesTemplate =
.callback = AnimPowerAbsorptionOrb
};
const struct SpriteTemplate gSteelBeamBigOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_STEEL_BEAM,
.paletteTag = ANIM_TAG_STEEL_BEAM,
.oam = &gOamData_AffineOff_ObjNormal_8x8,
.anims = gSolarBeamBigOrbAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimSolarBeamBigOrb,
};
const struct SpriteTemplate gSteelBeamSmallOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_STEEL_BEAM,
.paletteTag = ANIM_TAG_STEEL_BEAM,
.oam = &gOamData_AffineOff_ObjNormal_8x8,
.anims = gSolarBeamSmallOrbAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimSolarBeamSmallOrb,
};
const struct SpriteTemplate gAcrobaticsSlashesSpriteTemplate =
{
.tileTag = ANIM_TAG_WHITE_STREAK,
.paletteTag = ANIM_TAG_WHITE_STREAK,
.oam = &gOamData_AffineDouble_ObjBlend_32x8,
.anims = gRockPolishStreak_AnimCmds,
.images = NULL,
.affineAnims = gRockPolishStreak_AffineAnimCmds,
.callback = AnimAcrobaticsSlashes,
};
const struct SpriteTemplate gPsyshockOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_RED_ORB_2,
.paletteTag = ANIM_TAG_POISON_JAB,
.oam = &gOamData_AffineOff_ObjNormal_8x8,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimPoisonJabProjectile,
};
const struct SpriteTemplate gPsyshockSmokeSpriteTemplate =
{
.tileTag = ANIM_TAG_GRAY_SMOKE,
.paletteTag = ANIM_TAG_WISP_FIRE,
.oam = &gOamData_AffineOff_ObjNormal_32x32,
.anims = gOctazookaAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimSpriteOnMonPos,
};
// functions
static void AnimGrassKnot(struct Sprite *sprite)
{
@ -6971,28 +7027,6 @@ void AnimTask_CompressTargetHorizontally(u8 taskId)
task->func = AnimTask_CompressTargetStep;
}
const struct SpriteTemplate gSteelBeamBigOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_STEEL_BEAM,
.paletteTag = ANIM_TAG_STEEL_BEAM,
.oam = &gOamData_AffineOff_ObjNormal_8x8,
.anims = gSolarBeamBigOrbAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimSolarBeamBigOrb,
};
const struct SpriteTemplate gSteelBeamSmallOrbSpriteTemplate =
{
.tileTag = ANIM_TAG_STEEL_BEAM,
.paletteTag = ANIM_TAG_STEEL_BEAM,
.oam = &gOamData_AffineOff_ObjNormal_8x8,
.anims = gSolarBeamSmallOrbAnimTable,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimSolarBeamSmallOrb,
};
void AnimTask_CreateSmallSteelBeamOrbs(u8 taskId)
{
if (--gTasks[taskId].data[0] == -1)
@ -7009,3 +7043,12 @@ void AnimTask_CreateSmallSteelBeamOrbs(u8 taskId)
if (gTasks[taskId].data[1] == 15)
DestroyAnimVisualTask(taskId);
}
static void AnimAcrobaticsSlashes(struct Sprite *sprite)
{
int affineAnimNum = Random2() % ARRAY_COUNT(gRockPolishStreak_AffineAnimCmds);
InitSpritePosToAnimTarget(sprite, TRUE);
StartSpriteAffineAnim(sprite, affineAnimNum);
StoreSpriteCallbackInData6(sprite, DestroySpriteAndMatrix);
sprite->callback = RunStoredCallbackWhenAnimEnds;
}

View File

@ -584,6 +584,28 @@ const struct SpriteTemplate gAquaTailHitSpriteTemplate =
.callback = AnimAquaTail,
};
static const union AnimCmd sAnimCmdAnimatedSpark2[] = {
ANIMCMD_FRAME((8 * 8) / (16 * 16) * 0, 8),
ANIMCMD_FRAME((8 * 8) / (16 * 16) * 1, 8),
ANIMCMD_FRAME((8 * 8) / (16 * 16) * 2, 8),
ANIMCMD_JUMP(0)
};
static const union AnimCmd *const sAnimCmdTable_AnimatedSpark2[] = {
sAnimCmdAnimatedSpark2,
};
const struct SpriteTemplate gSparkBeamSpriteTemplate =
{
.tileTag = ANIM_TAG_SPARK_2,
.paletteTag = ANIM_TAG_SPARK_2,
.oam = &gOamData_AffineOff_ObjNormal_16x16,
.anims = sAnimCmdTable_AnimatedSpark2,
.images = NULL,
.affineAnims = gDummySpriteAffineAnimTable,
.callback = AnimToTargetInSinWave,
};
static void AnimAquaTail(struct Sprite *sprite)
{
StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);

View File

@ -233,7 +233,7 @@ static u16 GetNextBall(u16 ballId)
{
if (ballId == gBagPockets[BALLS_POCKET].itemSlots[i].itemId)
{
ballNext = gBagPockets[BALLS_POCKET].itemSlots[i].itemId;
ballNext = gBagPockets[BALLS_POCKET].itemSlots[i+1].itemId;
break;
}
}

View File

@ -1057,6 +1057,7 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl)
objVram = ConvertIntToDecimalStringN(text + 2, lvl, STR_CONV_MODE_LEFT_ALIGN, 3);
xPos = 5 * (3 - (objVram - (text + 2)));
MegaIndicator_SetVisibilities(healthboxSpriteId, TRUE);
}
windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(text, xPos, 3, 2, &windowId);

View File

@ -3760,6 +3760,8 @@ u8 AtkCanceller_UnableToUseMove2(void)
if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN
&& IsBattlerGrounded(gBattlerTarget)
&& GetChosenMovePriority(gBattlerAttacker) > 0
&& gBattleMoves[gCurrentMove].target != MOVE_TARGET_ALL_BATTLERS
&& gBattleMoves[gCurrentMove].target != MOVE_TARGET_OPPONENTS_FIELD
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
{
CancelMultiTurnMoves(gBattlerAttacker);
@ -4095,6 +4097,13 @@ static uq4_12_t GetSupremeOverlordModifier(u32 battler)
return modifier;
}
static bool32 HadMoreThanHalfHpNowHasLess(u32 battler)
{
// Had more than half of hp before, now has less
return (gBattleStruct->hpBefore[battler] >= gBattleMons[battler].maxHP / 2
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2);
}
u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg)
{
u32 effect = 0;
@ -5043,6 +5052,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
}
}
if (effect)
gMultiHitCounter = 0; // Prevent multi-hit moves from hitting more than once after move has been absorbed.
}
break;
case ABILITYEFFECT_MOVE_END: // Think contact abilities.
@ -5107,9 +5119,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler)
// Had more than half of hp before, now has less
&& gBattleStruct->hpBefore[battler] >= gBattleMons[battler].maxHP / 2
&& gBattleMons[battler].hp < gBattleMons[battler].maxHP / 2
&& HadMoreThanHalfHpNowHasLess(battler)
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove))
&& CompareStat(battler, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN))
@ -5586,8 +5596,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& (gMultiHitCounter == 0 || gMultiHitCounter == 1) // Activates after all hits from a multi-hit move.
&& IsBattlerAlive(gBattlerTarget)
&& (gBattleMons[gBattlerTarget].hp <= gBattleMons[gBattlerTarget].maxHP / 2)
&& HadMoreThanHalfHpNowHasLess(gBattlerTarget)
&& !(TestSheerForceFlag(gBattlerAttacker, gCurrentMove)))
{
gBattlerAttacker = gBattlerTarget;

View File

@ -2023,3 +2023,6 @@ const u32 gItemIconPalette_LustrousGlobe[] = INCBIN_U32("graphics/items/icon_pal
const u32 gItemIcon_BerserkGene[] = INCBIN_U32("graphics/items/icons/berserk_gene.4bpp.lz");
const u32 gItemIconPalette_BerserkGene[] = INCBIN_U32("graphics/items/icon_palettes/berserk_gene.gbapal.lz");
const u32 gItemIcon_FairyFeather[] = INCBIN_U32("graphics/items/icons/fairy_feather.4bpp.lz");
const u32 gItemIconPalette_FairyFeather[] = INCBIN_U32("graphics/items/icon_palettes/fairy_feather.gbapal.lz");

View File

@ -5199,6 +5199,9 @@ const u8 gMonIcon_Fearow[] = INCBIN_U8("graphics/pokemon/fearow/icon.4bpp");
const u8 gMonIcon_Ekans[] = INCBIN_U8("graphics/pokemon/ekans/icon.4bpp");
const u8 gMonIcon_Arbok[] = INCBIN_U8("graphics/pokemon/arbok/icon.4bpp");
const u8 gMonIcon_Pikachu[] = INCBIN_U8("graphics/pokemon/pikachu/icon.4bpp");
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
const u8 gMonIcon_PikachuF[] = INCBIN_U8("graphics/pokemon/pikachu/iconf.4bpp");
#endif
const u8 gMonIcon_Raichu[] = INCBIN_U8("graphics/pokemon/raichu/icon.4bpp");
const u8 gMonIcon_Sandshrew[] = INCBIN_U8("graphics/pokemon/sandshrew/icon.4bpp");
const u8 gMonIcon_Sandslash[] = INCBIN_U8("graphics/pokemon/sandslash/icon.4bpp");
@ -5376,6 +5379,9 @@ const u8 gMonIcon_Slowking[] = INCBIN_U8("graphics/pokemon/slowking/icon.4bpp");
const u8 gMonIcon_Misdreavus[] = INCBIN_U8("graphics/pokemon/misdreavus/icon.4bpp");
const u8 gMonIcon_Unown[] = INCBIN_U8("graphics/pokemon/unown/icon.4bpp");
const u8 gMonIcon_Wobbuffet[] = INCBIN_U8("graphics/pokemon/wobbuffet/icon.4bpp");
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
const u8 gMonIcon_WobbuffetF[] = INCBIN_U8("graphics/pokemon/wobbuffet/iconf.4bpp");
#endif
const u8 gMonIcon_Girafarig[] = INCBIN_U8("graphics/pokemon/girafarig/icon.4bpp");
const u8 gMonIcon_Pineco[] = INCBIN_U8("graphics/pokemon/pineco/icon.4bpp");
const u8 gMonIcon_Forretress[] = INCBIN_U8("graphics/pokemon/forretress/icon.4bpp");
@ -5625,7 +5631,7 @@ const u8 gMonIcon_Riolu[] = INCBIN_U8("graphics/pokemon/riolu/icon.4bpp");
const u8 gMonIcon_Lucario[] = INCBIN_U8("graphics/pokemon/lucario/icon.4bpp");
const u8 gMonIcon_Hippopotas[] = INCBIN_U8("graphics/pokemon/hippopotas/icon.4bpp");
const u8 gMonIcon_Hippowdon[] = INCBIN_U8("graphics/pokemon/hippowdon/icon.4bpp");
#if P_HIPPO_GENDER_DIFF_ICONS == TRUE
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
const u8 gMonIcon_HippopotasF[] = INCBIN_U8("graphics/pokemon/hippopotas/iconf.4bpp");
const u8 gMonIcon_HippowdonF[] = INCBIN_U8("graphics/pokemon/hippowdon/iconf.4bpp");
#endif

View File

@ -844,7 +844,7 @@ const u32 *const gItemIconTable[ITEMS_COUNT + 1][2] =
[ITEM_LINKING_CORD] = {gItemIcon_LinkingCord, gItemIconPalette_LinkingCord},
[ITEM_PEAT_BLOCK] = {gItemIcon_PeatBlock, gItemIconPalette_PeatBlock},
[ITEM_BERSERK_GENE] = {gItemIcon_BerserkGene, gItemIconPalette_BerserkGene},
[ITEM_FAIRY_FEATHER] = {gItemIcon_QuestionMark, gItemIconPalette_QuestionMark}, // {gItemIcon_FairyFeather, gItemIconPalette_FairyFeather},
[ITEM_FAIRY_FEATHER] = {gItemIcon_FairyFeather, gItemIconPalette_FairyFeather},
[ITEM_SYRUPY_APPLE] = {gItemIcon_QuestionMark, gItemIconPalette_QuestionMark}, // {gItemIcon_SyrupyApple, gItemIconPalette_SyrupyApple},
[ITEM_UNREMARKABLE_TEACUP] = {gItemIcon_QuestionMark, gItemIconPalette_QuestionMark}, // {gItemIcon_UnremarkableTeacup, gItemIconPalette_UnremarkableTeacup},
[ITEM_MASTERPIECE_TEACUP] = {gItemIcon_QuestionMark, gItemIconPalette_QuestionMark}, // {gItemIcon_MasterpieceTeacup, gItemIconPalette_MasterpieceTeacup},

View File

@ -1528,7 +1528,11 @@ const u8 *const gMonIconTable[NUM_SPECIES + 1] =
// Female icon palette indexes still need to be defined in gMonIconPaletteIndicesFemale, even if they are the same as males.
const u8 *const gMonIconTableFemale[NUM_SPECIES + 1] =
{
#if P_GEN_4_POKEMON == TRUE && P_HIPPO_GENDER_DIFF_ICONS == TRUE
#if P_CUSTOM_GENDER_DIFF_ICONS == TRUE
[SPECIES_PIKACHU] = gMonIcon_PikachuF,
[SPECIES_WOBBUFFET] = gMonIcon_WobbuffetF,
#endif
#if P_GEN_4_POKEMON == TRUE && P_CUSTOM_GENDER_DIFF_ICONS == TRUE
[SPECIES_HIPPOPOTAS] = gMonIcon_HippopotasF,
[SPECIES_HIPPOWDON] = gMonIcon_HippowdonF,
#endif
@ -2984,6 +2988,8 @@ const u8 gMonIconPaletteIndices[] =
const u8 gMonIconPaletteIndicesFemale[] =
{
[SPECIES_PIKACHU] = 2,
[SPECIES_WOBBUFFET] = 0,
#if P_GEN_4_POKEMON == TRUE
[SPECIES_HIPPOPOTAS] = 1,
[SPECIES_HIPPOWDON] = 1,

View File

@ -0,0 +1,95 @@
#include "global.h"
#include "test/battle.h"
SINGLE_BATTLE_TEST("Anger Shell activates only if the target had more than 50% of its hp")
{
bool32 activates = FALSE;
u16 maxHp = 500, hp = 0;
PARAMETRIZE { hp = 249; activates = FALSE; }
PARAMETRIZE { hp = 100; activates = FALSE; }
PARAMETRIZE { hp = 50; activates = FALSE; }
PARAMETRIZE { hp = 251; activates = TRUE; }
PARAMETRIZE { hp = 255; activates = TRUE; }
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].power != 0);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(hp); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
if (activates) {
ABILITY_POPUP(player, ABILITY_ANGER_SHELL);
} else {
NOT ABILITY_POPUP(player, ABILITY_ANGER_SHELL);
}
} THEN {
if (activates) {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
}
}
}
SINGLE_BATTLE_TEST("Anger Shell lowers Def/Sp.Def by 1 and raises Atk/Sp.Atk/Spd by 1")
{
u16 maxHp = 500;
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].power != 0);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
ABILITY_POPUP(player, ABILITY_ANGER_SHELL);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Defense fell!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Sp. Def fell!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Attack rose!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Sp. Atk rose!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Wobbuffet's Speed rose!");
} THEN {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
}
}
SINGLE_BATTLE_TEST("Anger Shell activates after all hits from a multi-hit move")
{
u32 j;
u16 maxHp = 500;
GIVEN {
ASSUME(gBattleMoves[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT);
PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); }
OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times.
} WHEN {
TURN { MOVE(opponent, MOVE_DOUBLE_SLAP); }
} SCENE {
for (j = 0; j < 4; j++)
{
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent);
NOT ABILITY_POPUP(player, ABILITY_ANGER_SHELL);
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SLAP, opponent);
ABILITY_POPUP(player, ABILITY_ANGER_SHELL);
} THEN {
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE - 1);
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1);
EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1);
EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1);
}
}

View File

@ -115,3 +115,26 @@ DOUBLE_BATTLE_TEST("Defiant sharply raises opponent's Attack after Intimidate")
EXPECT_EQ(opponentRight->statStages[STAT_ATK], (abilityRight == ABILITY_DEFIANT) ? DEFAULT_STAT_STAGE + 2 : DEFAULT_STAT_STAGE - 2);
}
}
SINGLE_BATTLE_TEST("Defiant activates after Sticky Web lowers Speed")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_MANKEY) { Ability(ABILITY_DEFIANT); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_STICKY_WEB); }
TURN { SWITCH(player, 1); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponent);
// Switch-in - Sticky Web activates
MESSAGE("Go! Mankey!");
MESSAGE("Mankey was caught in a Sticky Web!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Mankey's Speed fell!");
// Defiant activates
ABILITY_POPUP(player, ABILITY_DEFIANT);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Mankey's Attack sharply rose!");
}
}

View File

@ -57,3 +57,24 @@ SINGLE_BATTLE_TEST("Sap Sipper does not increase Attack if already maxed")
}
}
}
SINGLE_BATTLE_TEST("Sap Sipper blocks multi-hit grass type moves")
{
GIVEN {
ASSUME(gBattleMoves[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT);
PLAYER(SPECIES_MARILL) { Ability(ABILITY_SAP_SIPPER); }
OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); }
} WHEN {
TURN { MOVE(opponent, MOVE_BULLET_SEED); }
} SCENE {
MESSAGE("Foe Shellder used Bullet Seed!");
ABILITY_POPUP(player, ABILITY_SAP_SIPPER);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Marill's Attack rose!");
NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, opponent);
HP_BAR(player);
MESSAGE("Hit 5 time(s)!");
}
}
}

View File

@ -260,8 +260,8 @@ AI_SINGLE_BATTLE_TEST("AI can choose a status move that boosts the attack by two
AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking into account accuracy and move effect")
{
u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE;
u16 expectedMove, abilityAtk = ABILITY_NONE;
u16 expectedMove2 = MOVE_NONE;
u16 expectedMove, expectedMove2 = MOVE_NONE;
u16 abilityAtk = ABILITY_NONE, holdItemAtk = ITEM_NONE;
// Psychic is not very effective, but always hits. Solarbeam requires a charging turn, Double Edge has recoil and Focus Blast can miss;
PARAMETRIZE { abilityAtk = ABILITY_STURDY; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SOLAR_BEAM; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE; expectedMove = MOVE_PSYCHIC; }
@ -272,12 +272,24 @@ AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking
// This time it's Solarbeam + Psychic, because the weather is sunny.
PARAMETRIZE { abilityAtk = ABILITY_DROUGHT; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SOLAR_BEAM; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE;
expectedMove = MOVE_PSYCHIC; expectedMove2 = MOVE_SOLAR_BEAM; }
// Psychic and Solar Beam are chosen because user is holding Power Herb
PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SOLAR_BEAM; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE;
expectedMove = MOVE_PSYCHIC; expectedMove2 = MOVE_SOLAR_BEAM; }
// Psychic and Skull Bash are chosen because user is holding Power Herb
PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE;
expectedMove = MOVE_PSYCHIC; expectedMove2 = MOVE_SKULL_BASH; }
// Skull Bash is chosen because it's the most accurate and is holding Power Herb
PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_SLAM; move4 = MOVE_DOUBLE_EDGE;
expectedMove = MOVE_SKULL_BASH; }
// Crabhammer is chosen even if Skull Bash is more accurate, the user has no Power Herb
PARAMETRIZE { abilityAtk = ABILITY_STURDY; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_SLAM; move4 = MOVE_CRABHAMMER;
expectedMove = MOVE_CRABHAMMER; }
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET) { HP(5); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_GEODUDE) { Moves(move1, move2, move3, move4); Ability(abilityAtk); }
OPPONENT(SPECIES_GEODUDE) { Moves(move1, move2, move3, move4); Ability(abilityAtk); Item(holdItemAtk); }
} WHEN {
TURN { if (expectedMove2 == MOVE_NONE) { EXPECT_MOVE(opponent, expectedMove); SEND_OUT(player, 1); }
else {EXPECT_MOVES(opponent, expectedMove, expectedMove2); SCORE_EQ(opponent, expectedMove, expectedMove2); SEND_OUT(player, 1);}
@ -288,6 +300,36 @@ AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking
}
}
AI_SINGLE_BATTLE_TEST("AI won't use Solar Beam if there is no Sun up or the user is not holding Power Herb")
{
u16 abilityAtk = ABILITY_NONE;
u16 holdItemAtk = ITEM_NONE;
PARAMETRIZE { abilityAtk = ABILITY_DROUGHT; }
PARAMETRIZE { holdItemAtk = ITEM_POWER_HERB; }
PARAMETRIZE { }
GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT);
PLAYER(SPECIES_WOBBUFFET) { HP(211); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_TYPHLOSION) { Moves(MOVE_SOLAR_BEAM, MOVE_GRASS_PLEDGE); Ability(abilityAtk); Item(holdItemAtk); }
} WHEN {
if (abilityAtk == ABILITY_DROUGHT) {
TURN { EXPECT_MOVES(opponent, MOVE_SOLAR_BEAM, MOVE_GRASS_PLEDGE); }
TURN { EXPECT_MOVES(opponent, MOVE_SOLAR_BEAM, MOVE_GRASS_PLEDGE); SEND_OUT(player, 1); }
} else if (holdItemAtk == ITEM_POWER_HERB) {
TURN { EXPECT_MOVES(opponent, MOVE_SOLAR_BEAM, MOVE_GRASS_PLEDGE); MOVE(player, MOVE_KNOCK_OFF); }
TURN { EXPECT_MOVE(opponent, MOVE_GRASS_PLEDGE); SEND_OUT(player, 1); }
} else {
TURN { EXPECT_MOVE(opponent, MOVE_GRASS_PLEDGE); }
TURN { EXPECT_MOVE(opponent, MOVE_GRASS_PLEDGE); SEND_OUT(player, 1); }
}
} SCENE {
MESSAGE("Wobbuffet fainted!");
}
}
AI_SINGLE_BATTLE_TEST("AI won't use ground type attacks against flying type Pokemon unless Gravity is in effect")
{
GIVEN {

View File

@ -0,0 +1,53 @@
#include "global.h"
#include "test/battle.h"
ASSUMPTIONS
{
ASSUME(gBattleMoves[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF);
}
SINGLE_BATTLE_TEST("Knock Off knocks a healing berry before it has the chance to activate")
{
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); MaxHP(500); HP(255); }
} WHEN {
TURN { MOVE(player, MOVE_KNOCK_OFF); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
MESSAGE("Foe Wobbuffet's Sitrus Berry restored health!");
}
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF);
MESSAGE("Wobbuffet knocked off Foe Wobbuffet's Sitrus Berry!");
}
}
SINGLE_BATTLE_TEST("Knock Off activates after Rocky Helmet and Weakness Policy")
{
u16 item = 0;
PARAMETRIZE { item = ITEM_WEAKNESS_POLICY; }
PARAMETRIZE { item = ITEM_ROCKY_HELMET; }
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(item); }
} WHEN {
TURN { MOVE(player, MOVE_KNOCK_OFF); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
if (item == ITEM_WEAKNESS_POLICY) {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE);
MESSAGE("Using WeaknssPolicy, the Attack of Foe Wobbuffet sharply rose!");
MESSAGE("Using WeaknssPolicy, the Sp. Atk of Foe Wobbuffet sharply rose!");
} else if (item == ITEM_ROCKY_HELMET) {
HP_BAR(player);
MESSAGE("Wobbuffet was hurt by Foe Wobbuffet's Rocky Helmet!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF);
MESSAGE("Wobbuffet knocked off Foe Wobbuffet's Rocky Helmet!");
}
}
}

View File

@ -78,7 +78,6 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all battlers")
{
KNOWN_FAILING;
GIVEN {
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); }
OPPONENT(SPECIES_WOBBUFFET);
@ -93,7 +92,6 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all opponents")
{
KNOWN_FAILING;
GIVEN {
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); }
OPPONENT(SPECIES_WOBBUFFET);
@ -124,7 +122,6 @@ DOUBLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all
SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority field moves")
{
KNOWN_FAILING;
GIVEN {
PLAYER(SPECIES_SABLEYE) { Ability(ABILITY_PRANKSTER); }
OPPONENT(SPECIES_WOBBUFFET);