Merge branch 'battle_engine' of https://github.com/rh-hideout/pokeemerald-expansion into teleport

This commit is contained in:
LOuroboros 2022-07-03 13:49:18 -03:00
commit 8f728dcd79
93 changed files with 1273 additions and 1569 deletions

View File

@ -451,13 +451,6 @@ Replace `<output of nproc>` with the number that the `nproc` command returned.
`nproc` is not available on macOS. The alternative is `sysctl -n hw.ncpu` ([relevant Stack Overflow thread](https://stackoverflow.com/questions/1715580)).
## Debug info
To build **pokeemerald.elf** with enhanced debug info:
```bash
make DINFO=1
```
## devkitARM's C compiler
This project supports the `arm-none-eabi-gcc` compiler included with devkitARM. If devkitARM (a.k.a. gba-dev) has already been installed as part of the platform-specific instructions, simply run:
@ -534,7 +527,7 @@ devkitARM is now installed.
devkitARM is now installed.
## Installing devkitARM on Arch Linux
### Installing devkitARM on Arch Linux
1. Follow [devkitPro's instructions](https://devkitpro.org/wiki/devkitPro_pacman#Customising_Existing_Pacman_Install) to configure `pacman` to download devkitPro packages.
2. Install `gba-dev`: run the following command as root.
@ -552,7 +545,7 @@ devkitARM is now installed.
devkitARM is now installed.
## Other toolchains
### Other toolchains
To build using a toolchain other than devkitARM, override the `TOOLCHAIN` environment variable with the path to your toolchain, which must contain the subdirectory `bin`.
```bash
@ -564,6 +557,14 @@ make TOOLCHAIN="/usr/local/arm-none-eabi"
```
To compile the `modern` target with this toolchain, the subdirectories `lib`, `include`, and `arm-none-eabi` must also be present.
### Building with debug info under a modern toolchain
To build **pokeemerald.elf** with debug symbols under a modern toolchain:
```bash
make modern DINFO=1
```
Note that this is not necessary for a non-modern build since those are built with debug symbols by default.
# Useful additional tools
* [porymap](https://github.com/huderlem/porymap) for viewing and editing maps

View File

@ -107,7 +107,7 @@ LIBPATH := -L ../../tools/agbcc/lib
LIB := $(LIBPATH) -lgcc -lc -L../../libagbsyscall -lagbsyscall
else
CC1 = $(shell $(PATH_MODERNCC) --print-prog-name=cc1) -quiet
override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast -g
override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast
ROM := $(MODERN_ROM_NAME)
OBJ_DIR := $(MODERN_OBJ_DIR_NAME)
LIBPATH := -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libgcc.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libnosys.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libc.a))"

View File

@ -100,9 +100,9 @@
special CallTrainerHillFunction
.endm
@ Set the challenge mode to HILL_TAG_* (Normal, Variety, Unique, or Expert)
.macro trainerhill_settag tag:req
setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_TAG
copyvar VAR_0x8005, \tag
@ Set the challenge mode to HILL_MODE_* (Normal, Variety, Unique, or Expert)
.macro trainerhill_setmode mode:req
setvar VAR_0x8004, TRAINER_HILL_FUNC_SET_MODE
copyvar VAR_0x8005, \mode
special CallTrainerHillFunction
.endm

View File

@ -14193,7 +14193,42 @@ Move_LASH_OUT::
end @to do:
Move_POLTERGEIST::
end @to do:
loadspritegfx ANIM_TAG_EYE_SPARKLE
loadspritegfx ANIM_TAG_WHITE_SHADOW @Destiny Bond
loadspritegfx ANIM_TAG_QUICK_GUARD_HAND @Black Colour
loadspritegfx ANIM_TAG_IMPACT
loadspritegfx ANIM_TAG_POLTERGEIST
fadetobg BG_NIGHTMARE
waitbgfadein
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 2, 0, 0, 16, RGB_BLACK
waitforvisualfinish
createsprite gEyeSparkleSpriteTemplate, ANIM_ATTACKER, 0, -16, -8
createsprite gEyeSparkleSpriteTemplate, ANIM_ATTACKER, 0, 16, -8
playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER
waitforvisualfinish
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 2, 0, 16, 0, RGB_BLACK
playsewithpan SE_M_FAINT_ATTACK, SOUND_PAN_ATTACKER
delay 0x1
launchtask AnimTask_DestinyBondWhiteShadow 0x5 0x2 0x0 0x24
delay 0x30
playsewithpan SE_M_SAND_ATTACK, SOUND_PAN_TARGET
createvisualtask AnimTask_PoltergeistItem, 2
waitforvisualfinish
setalpha 12, 8
launchtemplate gBasicHitSplatSpriteTemplate 0x2 0x4 0x0 0x0 0x1 0x1
launchtask AnimTask_ShakeMon 0x5 0x5 0x1 0x0 0x5 0x5 0x1
launchtemplate gComplexPaletteBlendSpriteTemplate 0x2 0x7 0x7 0x5 0x1 0x0 0xa 0x0 0x0
playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET
waitforvisualfinish
launchtask AnimTask_NightmareClone 0x2 0x0
launchtask AnimTask_ShakeMon 0x2 0x5 0x1 0x3 0x0 0x28 0x1
playsewithpan SE_M_NIGHTMARE, SOUND_PAN_TARGET
waitforvisualfinish
restorebg
waitbgfadein
clearmonbg 0x3
blendoff
end
Move_CORROSIVE_GAS::
end @to do:

View File

@ -410,6 +410,51 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectHit @ EFFECT_RISING_VOLTAGE
.4byte BattleScript_EffectHit @ EFFECT_BEAK_BLAST
.4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE
.4byte BattleScript_EffectSteelBeam @ EFFECT_STEEL_BEAM
BattleScript_EffectSteelBeam::
attackcanceler
attackstring
ppreduce
accuracycheck BattleScript_SteelBeamMiss, ACC_CURR_MOVE
critcalc
damagecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
seteffectwithchance
jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_SteelBeamAfterSelfDamage
call BattleScript_SteelBeamSelfDamage
BattleScript_SteelBeamAfterSelfDamage::
waitstate
tryfaintmon BS_ATTACKER
tryfaintmon BS_TARGET
goto BattleScript_MoveEnd
BattleScript_SteelBeamMiss::
pause B_WAIT_TIME_SHORT
effectivenesssound
resultmessage
waitmessage B_WAIT_TIME_LONG
jumpifability BS_ATTACKER, ABILITY_MAGIC_GUARD, BattleScript_MoveEnd
bichalfword gMoveResultFlags, MOVE_RESULT_MISSED
call BattleScript_SteelBeamSelfDamage
orhalfword gMoveResultFlags, MOVE_RESULT_MISSED
goto BattleScript_SteelBeamAfterSelfDamage
BattleScript_SteelBeamSelfDamage::
dmg_1_2_attackerhp
healthbarupdate BS_ATTACKER
datahpupdate BS_ATTACKER
return
BattleScript_EffectCourtChange::
attackcanceler
@ -1272,6 +1317,7 @@ BattleScript_StrengthSapTryHp:
attackanimation
waitanimation
BattleScript_StrengthSapHp:
jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_MoveEnd
jumpiffullhp BS_ATTACKER, BattleScript_MoveEnd
manipulatedamage DMG_BIG_ROOT
healthbarupdate BS_ATTACKER
@ -2106,7 +2152,9 @@ BattleScript_GrowthDoMoveAnim::
waitanimation
setbyte sSTAT_ANIM_PLAYED, FALSE
playstatchangeanimation BS_ATTACKER, BIT_ATK | BIT_SPATK, 0
.if B_GROWTH_UNDER_SUN >= GEN_5
jumpifweatheraffected BS_ATTACKER, B_WEATHER_SUN, BattleScript_GrowthAtk2
.endif
setstatchanger STAT_ATK, 1, FALSE
goto BattleScript_GrowthAtk
BattleScript_GrowthAtk2:
@ -2117,7 +2165,9 @@ BattleScript_GrowthAtk:
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_GrowthTrySpAtk::
.if B_GROWTH_UNDER_SUN >= GEN_5
jumpifweatheraffected BS_ATTACKER, B_WEATHER_SUN, BattleScript_GrowthSpAtk2
.endif
setstatchanger STAT_SPATK, 1, FALSE
goto BattleScript_GrowthSpAtk
BattleScript_GrowthSpAtk2:
@ -2340,7 +2390,7 @@ BattleScript_EffectPsychicTerrain:
waitanimation
printfromtable gTerrainStringIds
waitmessage B_WAIT_TIME_LONG
playanimation BS_SCRIPTING, B_ANIM_RESTORE_BG
playanimation BS_ATTACKER, B_ANIM_RESTORE_BG
call BattleScript_TerrainSeedLoop
jumpifabilitypresent ABILITY_MIMICRY, BattleScript_ApplyMimicry
goto BattleScript_MoveEnd
@ -2409,6 +2459,8 @@ BattleScript_EffectHealPulse:
attackcanceler
attackstring
ppreduce
jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_MoveUsedHealBlockPrevents @ stops pollen puff
jumpifstatus3 BS_TARGET, STATUS3_HEAL_BLOCK, BattleScript_MoveUsedHealBlockPrevents
accuracycheck BattleScript_ButItFailed, NO_ACC_CALC_CHECK_LOCK_ON
jumpifsubstituteblocks BattleScript_ButItFailed
tryhealpulse BS_TARGET, BattleScript_AlreadyAtFullHp
@ -3103,6 +3155,7 @@ BattleScript_EffectAbsorb::
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_AbsorbHealBlock
setdrainedhp
manipulatedamage DMG_BIG_ROOT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE
@ -3122,6 +3175,7 @@ BattleScript_AbsorbUpdateHp::
waitmessage B_WAIT_TIME_LONG
BattleScript_AbsorbTryFainting::
tryfaintmon BS_ATTACKER
BattleScript_AbsorbHealBlock::
tryfaintmon BS_TARGET
goto BattleScript_MoveEnd
@ -3228,6 +3282,7 @@ BattleScript_DreamEaterWorked:
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
jumpifstatus3 BS_ATTACKER, STATUS3_HEAL_BLOCK, BattleScript_DreamEaterTryFaintEnd
setdrainedhp
manipulatedamage DMG_BIG_ROOT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
@ -4533,7 +4588,11 @@ BattleScript_NightmareWorked::
BattleScript_EffectMinimize::
attackcanceler
setminimize
.if B_MINIMIZE_EVASION >= GEN_5
setstatchanger STAT_EVASION, 2, FALSE
.else
setstatchanger STAT_EVASION, 1, FALSE
.endif
goto BattleScript_EffectStatUpAfterAtkCanceler
BattleScript_EffectCurse::
@ -6235,12 +6294,30 @@ BattleScript_LocalBattleLost::
jumpifbattletype BATTLE_TYPE_EREADER_TRAINER, BattleScript_LocalBattleLostEnd
jumpifhalfword CMP_EQUAL, gTrainerBattleOpponent_A, TRAINER_SECRET_BASE, BattleScript_LocalBattleLostEnd
BattleScript_LocalBattleLostPrintWhiteOut::
.if B_WHITEOUT_MONEY >= GEN_4
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_LocalBattleLostEnd
printstring STRINGID_PLAYERWHITEOUT
waitmessage B_WAIT_TIME_LONG
getmoneyreward
printstring STRINGID_PLAYERWHITEOUT2
waitmessage B_WAIT_TIME_LONG
end2
BattleScript_LocalBattleLostEnd::
printstring STRINGID_PLAYERLOSTTOENEMYTRAINER
waitmessage B_WAIT_TIME_LONG
getmoneyreward
printstring STRINGID_PLAYERPAIDPRIZEMONEY
waitmessage B_WAIT_TIME_LONG
end2
.else
printstring STRINGID_PLAYERWHITEOUT
waitmessage B_WAIT_TIME_LONG
printstring STRINGID_PLAYERWHITEOUT2
waitmessage B_WAIT_TIME_LONG
BattleScript_LocalBattleLostEnd::
end2
.endif
BattleScript_CheckDomeDrew::
jumpifbyte CMP_EQUAL, gBattleOutcome, B_OUTCOME_DREW, BattleScript_LocalBattleLostEnd_
BattleScript_LocalBattleLostPrintTrainersWinText::
@ -6482,9 +6559,11 @@ BattleScript_LearnMoveReturn::
BattleScript_RainContinuesOrEnds::
printfromtable gRainContinuesStringIds
waitmessage B_WAIT_TIME_LONG
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_RAIN_STOPPED, BattleScript_RainContinuesOrEndsEnd
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_RAIN_STOPPED, BattleScript_RainEnds
playanimation BS_ATTACKER, B_ANIM_RAIN_CONTINUES
BattleScript_RainContinuesOrEndsEnd::
end2
BattleScript_RainEnds::
call BattleScript_WeatherFormChanges
end2
BattleScript_DamagingWeatherContinues::
@ -6523,6 +6602,7 @@ BattleScript_DamagingWeatherContinuesEnd::
BattleScript_SandStormHailEnds::
printfromtable gSandStormHailEndStringIds
waitmessage B_WAIT_TIME_LONG
call BattleScript_WeatherFormChanges
end2
BattleScript_SunlightContinues::
@ -6534,6 +6614,7 @@ BattleScript_SunlightContinues::
BattleScript_SunlightFaded::
printstring STRINGID_SUNLIGHTFADED
waitmessage B_WAIT_TIME_LONG
call BattleScript_WeatherFormChanges
end2
BattleScript_OverworldWeatherStarts::
@ -7955,7 +8036,7 @@ BattleScript_DrizzleActivates::
call BattleScript_WeatherFormChanges
end3
BattleScript_DefiantActivates::
BattleScript_AbilityRaisesDefenderStat::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
statbuffchange 0, NULL
@ -8235,8 +8316,10 @@ BattleScript_DesolateLandEvaporatesWaterTypeMoves::
attackstring
pause B_WAIT_TIME_SHORT
ppreduce
jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd
printstring STRINGID_MOVEEVAPORATEDINTHEHARSHSUNLIGHT
waitmessage B_WAIT_TIME_LONG
orword gHitMarker, HITMARKER_STRING_PRINTED
goto BattleScript_MoveEnd
BattleScript_PrimordialSeaActivates::
@ -8253,8 +8336,10 @@ BattleScript_PrimordialSeaFizzlesOutFireTypeMoves::
attackstring
pause B_WAIT_TIME_SHORT
ppreduce
jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_STRING_PRINTED, BattleScript_MoveEnd
printstring STRINGID_MOVEFIZZLEDOUTINTHEHEAVYRAIN
waitmessage B_WAIT_TIME_LONG
orword gHitMarker, HITMARKER_STRING_PRINTED
goto BattleScript_MoveEnd
BattleScript_DeltaStreamActivates::
@ -8465,6 +8550,13 @@ BattleScript_ObliviousPreventsAttraction::
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_FlinchPrevention::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
printstring STRINGID_PKMNSXPREVENTSFLINCHING
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_OwnTempoPrevents::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp

View File

@ -157,7 +157,7 @@ TrainerHill_Entrance_EventScript_ChooseChallenge::
switch VAR_RESULT
case 4, TrainerHill_Entrance_EventScript_CancelEntry
case MULTI_B_PRESSED, TrainerHill_Entrance_EventScript_CancelEntry
trainerhill_settag VAR_RESULT
trainerhill_setmode VAR_RESULT
setvar VAR_TRAINER_HILL_IS_ACTIVE, 1
setvar VAR_TEMP_5, 0
special HealPlayerParty

View File

@ -0,0 +1,19 @@
JASC-PAL
0100
16
0 0 0
246 246 246
246 246 246
213 197 230
213 197 230
180 148 213
180 148 213
180 148 213
148 98 197
115 65 164
82 32 131
82 32 131
82 32 131
0 0 0
0 0 0
0 0 0

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;1;;;;;,99:;;;;;1;;;;isMMMMŃMMMMis@;UUUUŃUUUU1AiAĹŮŮŮšŮŮŮĆAsi;ÔŰsssŰĚ1si;ÍssDssŐ1si;ÔŰsssŰĚ1siAŃŰŰŰ›ŰŰŰŰAs@;ÇÇŰŰŰÇÇ1Ai;MMggŰŰŰggMM1si;UU××ŃŰŰ××UU1si;9999:;;9999:sissssssssssssss

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;FFFFFFFFFFFFFxF|}|{zF}FFFFFFFFFFFFF~}~›ł›››FFFFFFFFFFFFFF}|{z|FFFFFFFFFFFFFF|}~}~FFFFFFFFFFFFFł‘Ö–››–ÖŰÖ–››–Ö›Ö–››–ÖŰŰŰÖ–››–Ö–››–ÖŰŰŰŰŰÖ–››–Ö–››–ÖŰŰŰÖ–››–Ö‘Ö–››–ÖŰÖ–››–Ö›

View File

@ -0,0 +1 @@
<EFBFBD>áñù>ù>}~=x½=x}~y>ù>ñá

View File

@ -0,0 +1 @@
ムロロロルル<15>圀屁ムロロロユユテ<EFBE95>歯屁屁ムロロユヒヒヒ絜給副屁ムロユヒヒヒヒ絜給虚屁ムロヒヒヒヒヒ絜給給屁ムユヒヒヒヒヒ綷給給副ムヒヒヒヒフフ驎結給魚ムフフフフ顥顥絜給魚ムユユユユ隯隯絜給魚ムヒヒヒヒ<EFBE8B><EFBFBD>給魚ムフヒヒヒヒヒ驎給給憲ムロヒヒヒヒヒ顥給給屁ムロフヒヒヒヒ絜給旧屁ムロロフヒヒヒ絜給憲屁ムロロロフフヒ綷血屁屁ムロロロロロフ蕙屁屁屁

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9999:;;;<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD>FF<46>FF<46><46><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD>F66<36>66F<36><46><EFBFBD><EFBFBD><08><><EFBFBD>F<EFBFBD>FF<46>FF<46>F<EFBFBD><46><EFBFBD><08><>F6F<36><46><EFBFBD>ۛF6F<36><46><08><>F6<46><36><EFBFBD><EFBFBD><EFBFBD>ۛ6F<36><46><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֖<EFBFBD><D696>ۛ<EFBFBD><DB9B><EFBFBD><08><>F6<46><36><EFBFBD><EFBFBD><EFBFBD>ۛ6F<36><46><08><>F6F<36><46><EFBFBD>ۛF6F<36><46><08><><EFBFBD>F<EFBFBD>FF<46>FF<46>F<EFBFBD><46><EFBFBD><08><><EFBFBD><EFBFBD>F66<36>66F<36><46><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD>FF<46>FF<46><46><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F<EFBFBD><46><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

View File

@ -0,0 +1 @@
<EFBFBD>ÁoAcA`ADAUAUÁÿÿÿÿÿÿÿÿÿÿÿÿÿÿ

View File

@ -0,0 +1 @@
155;&&%9:;;;1++;44++43????;1++;;;44;3???;;1++55555;3???;?1+444+44;,???;;1+;5;+;5;5;???;1+;+;+;+;+;???;14;+;4;+5+;;?;;1;;4;;;444?;;;?

Binary file not shown.

View File

@ -0,0 +1 @@
1;5;9&%9:;5;1;+;;+++++;;;+;1;+;;+++++>>;+;1;+;;+++++;;;+;?;+;;+++++;>>+;1;+;;++,++;;;+;1?+;;,,;,,>>;+;1;+5555;55555+;?;,,,,,;,,,,,,;1;??;55;55555551???;++5+++++++1??;;++++++++++1;;;?,,,,,,,,,,

View File

@ -0,0 +1 @@
<EFBFBD>ĺ?í˝%„˝ß!~A } ÷Aůy˙˙

View File

@ -0,0 +1 @@
1;55&&%&:;5;1;,,,+$$$$,;;,;-;;;;+;;;;5;55;3;2!0+;2!0+;,+;35;;;,5;;;+;;+;4,;2!0+20;+20,;15;;5;,;;5,;;551,20+205;+2!0,,15;;+;;+;,;5;;;1,20+20+;20+20;1555+;;+;;5+;551+,,,20+20,,;,,1+;;5;;+;;5;;;;1,20+;;,20,20;51;;;,;;;;;;;;;,

View File

@ -0,0 +1 @@
<EFBFBD><03>s @ @<40>Q<EFBFBD>S<EFBFBD>Q<EFBFBD>Q<EFBFBD>Q<EFBFBD>Q<EFBFBD>QPP<10><>

View File

@ -0,0 +1 @@
ムユユユルルナニホユロユムヒトトロロトトトフフフヒロヒムヒロロロロロロロヒロヒムヒロユユユユユ゚ヒロヒムヒロヒヒヒトトロヒロヒムヒロヒロロトヒピユユヒロヒムヒロヒロロロヒヒロトトヒロヒムヒロヒロロロヒヒユユ゚ヒロヒムヒロヒロロロヒヒトトロヒロヒムヒロヒロロロヒピユユヒロヒムヒロヒロロロトトロトトトロヒムヒロヒ屁屁屁ロユユユヒムトロヒロロロロロ巒ヒヒヒヒムロロヒロロロロロ巒ヒヒヒヒムロロトロロロロロ巒トトトト

Binary file not shown.

View File

@ -0,0 +1 @@
1555&&8&.55;icddddqqqrdddcsicssssssssssscsicssssssssssscsicCA@ABAAJBAAcsicsssssssdssscsicACKCCABB@A@csicssdsssssssscsicA@BBAABJBABcsicsssssssdssscsicABACKAAA@CAcsicssssdsssssscsicA@CABBAJBABcsidsssssssdsssdsiCCABBACAA@BABsiBsssssssssssBs

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9&%9:;;;+$$$+;;;;;3+;;;+55;553+;;;+,,;,,3+;;;+4,+;;;,,;;;;;;;3+;;;54+;;;+,;;++;;;+,,+;;;+;;3+;;;+;+;3+555+;,;4,,,,,

Binary file not shown.

View File

@ -0,0 +1 @@
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><15><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۛ<EFBFBD><DB9B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9&%9:;;;-;;;5,#$#,5;;;;<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;iFFFFFFFFFFFF|FiFzsssysss}sssFiFsFFFFFFFFFFFFiFss{s|s{szsssFiFFFFFFFFFFFFzFiFsssss}|s|s{sFiFFFFFF|FFFFFFF詮屁妲;;;F屁屁F詮屁妲;;;F屁屁F詮屁妲;;;F屁屁F<08>FFFFFxFFFFFFF<08>驎驎驎z驎驎礰<08>FFFFFFFFFFFF<46>|硺硤硎﨤礼神礼

Binary file not shown.

View File

@ -0,0 +1 @@
ّ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>منَ<D986><D98E><EFBFBD>ٍ<><D98D><EFBFBD><EFBFBD><EFBFBD>ًٌٌٌٌٌٌ<D98C><D98C><08>ٌٌٌ<D98C><D98C><EFBFBD><EFBFBD><EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD>ّ<><D991><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD>ًًٌٌٌٌٌّ<D98C>ٌ<EFBFBD>ًٌٌٌٌّ<D991><D98B><EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ًّ<D991><D98B><EFBFBD>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD>ًّ<D991>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD>ًٌٌٌ<D98C><D98C>ًّ<D991>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD>ًّ<D991>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD>ًٌٌٌٌّ<D991>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD>ًّ<D991>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD>ٌّ<D991>ً<EFBFBD>ٌ<EFBFBD>ً<EFBFBD>ٌٌٌٌٌ<D98C>ّ<><D991>ً<EFBFBD><D98B><EFBFBD>ً<EFBFBD><D98B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ّ<><D991>ٌ<EFBFBD><D98C><EFBFBD>ٌ<EFBFBD><D98C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;@AAAAABCCCCC@AA@ûCAAAB@CABBBûA@AûAAAB@CACCû@A@AAûCAB@CCCûA@A@AAABBB@CCCAA@A@AAAþþþûþþþAA@A@AAAþþþûþþþAA@A@ABAþûûûûûþAA@A@AAAþþþûþþþAA@A@AAAþþþûþþþAA@A@BACCCA@BBBBA@A@@AûAAAAAAAûA@A@@ûCCAAABBBBû@A@ûCCAACCCCCCCûA@BBBBBBBBBBBBBB

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;<08><><EFBFBD><EFBFBD>@@<40><><EFBFBD>@@<40><><EFBFBD><EFBFBD><08><><EFBFBD>@<40><>@<40>@<40><>B<EFBFBD><42><EFBFBD><08><>@<40><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><08>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><08>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><08>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><08>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><08>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><08><>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><08><><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><08><><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><08><><EFBFBD><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD>֖<><D696><EFBFBD><EFBFBD>A<EFBFBD>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><08>֖<EFBFBD><D696><EFBFBD><EFBFBD>@<40><><EFBFBD><EFBFBD><EFBFBD>֜

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;<08><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><17><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><17><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><17><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><17><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><17><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><><17><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><17><>

Binary file not shown.

View File

@ -0,0 +1 @@
1;;;9989:;;;i@mAsA^AqBEEEEECsdsCsdsAsEEEEEe@sBmBsBmBEEEEElsAsds@sds@sBsAi@mAs@mCsCmBsBm@sdsCsdsAsdsAsdeBsBmAs@mBsAmBslsAsdsBsdsBsdsBi@mAsAmBsCmAsCm@sdsCsdsCsdsBsdeBsBmCsBmBsAm@sls@sdsAsdsBsdsBi@mBsBmCs@mAs@m@sds@sds@sdsCsd

View File

@ -469,7 +469,6 @@ struct MegaEvolutionData
bool8 playerSelect;
u8 triggerSpriteId;
bool8 isWishMegaEvo;
bool8 isPrimalReversion;
};
struct Illusion
@ -634,7 +633,7 @@ struct BattleStruct
#define TARGET_TURN_DAMAGED ((gSpecialStatuses[gBattlerTarget].physicalDmg != 0 || gSpecialStatuses[gBattlerTarget].specialDmg != 0))
#define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0))
#define IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || gBattleMons[battlerId].type3 == type))
#define IS_BATTLER_OF_TYPE(battlerId, type)((gBattleMons[battlerId].type1 == type || gBattleMons[battlerId].type2 == type || (gBattleMons[battlerId].type3 != TYPE_MYSTERY && gBattleMons[battlerId].type3 == type)))
#define SET_BATTLER_TYPE(battlerId, type) \
{ \
gBattleMons[battlerId].type1 = type; \
@ -932,5 +931,6 @@ extern bool8 gHasFetchedBall;
extern u8 gLastUsedBall;
extern u16 gLastThrownBall;
extern bool8 gSwapDamageCategory; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
extern u8 gPartyCriticalHits[PARTY_SIZE];
#endif // GUARD_BATTLE_H

View File

@ -85,7 +85,7 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef);
u8 GetMoveDamageResult(u16 move);
u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef);
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
u16 *GetMovesArray(u32 battler);
bool32 IsConfusionMoveEffect(u16 moveEffect);
bool32 HasMove(u32 battlerId, u32 move);

View File

@ -9,7 +9,6 @@ void SpriteCB_TrainerSlideIn(struct Sprite *sprite);
void InitAndLaunchChosenStatusAnimation(bool8 isStatus2, u32 status);
bool8 TryHandleLaunchBattleTableAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId, u16 argument);
void InitAndLaunchSpecialAnimation(u8 activeBattlerId, u8 attacker, u8 target, u8 tableId);
bool8 IsMoveWithoutAnimation(u16 moveId, u8 animationTurn);
bool8 IsBattleSEPlaying(u8 battlerId);
void BattleLoadOpponentMonSpriteGfx(struct Pokemon *mon, u8 battlerId);
void BattleLoadPlayerMonSpriteGfx(struct Pokemon *mon, u8 battlerId);

View File

@ -169,6 +169,7 @@ extern const u8 BattleScript_BRNPrevention[];
extern const u8 BattleScript_PRLZPrevention[];
extern const u8 BattleScript_PSNPrevention[];
extern const u8 BattleScript_ObliviousPreventsAttraction[];
extern const u8 BattleScript_FlinchPrevention[];
extern const u8 BattleScript_OwnTempoPrevents[];
extern const u8 BattleScript_SoundproofProtected[];
extern const u8 BattleScript_AbilityNoSpecificStatLoss[];
@ -308,7 +309,7 @@ extern const u8 BattleScript_MistySurgeActivates[];
extern const u8 BattleScript_ElectricSurgeActivates[];
extern const u8 BattleScript_SpectralThiefSteal[];
extern const u8 BattleScript_StatUpMsg[];
extern const u8 BattleScript_DefiantActivates[];
extern const u8 BattleScript_AbilityRaisesDefenderStat[];
extern const u8 BattleScript_PowderMoveNoEffect[];
extern const u8 BattleScript_GrassyTerrainHeals[];
extern const u8 BattleScript_VCreateStatLoss[];

View File

@ -134,6 +134,7 @@ u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilit
u16 GetTypeModifier(u8 atkType, u8 defType);
s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId);
u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId);
u16 GetPrimalReversionSpecies(u16 preEvoSpecies, u16 heldItemId);
u16 GetWishMegaEvolutionSpecies(u16 preEvoSpecies, u16 moveId1, u16 moveId2, u16 moveId3, u16 moveId4);
bool32 CanMegaEvolve(u8 battlerId);
void UndoMegaEvolution(u32 monId);
@ -171,6 +172,7 @@ void TryToApplyMimicry(u8 battlerId, bool8 various);
void TryToRevertMimicry(void);
void RestoreBattlerOriginalTypes(u8 battlerId);
u32 GetBattlerMoveTargetType(u8 battlerId, u16 move);
bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move);
// Ability checks
bool32 IsRolePlayBannedAbilityAtk(u16 ability);
bool32 IsRolePlayBannedAbility(u16 ability);

View File

@ -203,6 +203,7 @@
#define HITMARKER_CHARGING (1 << 27)
#define HITMARKER_FAINTED(battler) (gBitTable[battler] << 28)
#define HITMARKER_FAINTED2(battler) ((1 << 28) << battler)
#define HITMARKER_STRING_PRINTED (1 << 29)
// Per-side statuses that affect an entire party
#define SIDE_STATUS_REFLECT (1 << 0)

View File

@ -15,11 +15,13 @@
#define AI_TYPE_MOVE 4
// type effectiveness
#define AI_EFFECTIVENESS_x8 320
#define AI_EFFECTIVENESS_x4 160
#define AI_EFFECTIVENESS_x2 80
#define AI_EFFECTIVENESS_x1 40
#define AI_EFFECTIVENESS_x0_5 20
#define AI_EFFECTIVENESS_x0_25 10
#define AI_EFFECTIVENESS_x0_125 5
#define AI_EFFECTIVENESS_x0 0
// ai weather

View File

@ -395,6 +395,7 @@
#define ANIM_TAG_OMEGA_SYMBOL (ANIM_SPRITES_START + 383)
#define ANIM_TAG_PRIMAL_PARTICLES (ANIM_SPRITES_START + 384)
#define ANIM_TAG_STEEL_BEAM (ANIM_SPRITES_START + 385)
#define ANIM_TAG_POLTERGEIST (ANIM_SPRITES_START + 386)
// battlers
#define ANIM_ATTACKER 0

View File

@ -99,11 +99,12 @@
#endif
// Calculation settings
#define B_CRIT_CHANCE GEN_7 // Chances of a critical hit landing. See CalcCritChanceStage.
#define B_CRIT_CHANCE GEN_7 // Chances of a critical hit landing. See CalcCritChanceStage. Gen6+ chances guarantee that Farfetch'd and Sirfetch'd always get critical hits while holding a Leek and using high-crit ratio moves.
#define B_CRIT_MULTIPLIER GEN_7 // In Gen6+, critical hits multiply damage by 1.5 instead of 2.
#define B_PARALYSIS_SPEED GEN_7 // In Gen7+, Speed is decreased by 50% instead of 75%.
#define B_CONFUSION_SELF_DMG_CHANCE GEN_7 // In Gen7+, confusion has a 33.3% of self-damage, instead of 50%.
#define B_MULTI_HIT_CHANCE GEN_7 // In Gen5+, multi-hit moves have different %. See Cmd_setmultihitcounter for values.
#define B_WHITEOUT_MONEY GEN_7 // In Gen4+, the amount of money lost by losing a battle is determined by the amount of badges earned. Previously, it would cut the current money by half. (While this change was also in FRLG, for the sake of simplicity, setting this to GEN_3 will result in RSE behavior.)
// Exp and stat settings
#define B_EXP_CATCH GEN_7 // In Gen6+, Pokémon get experience from catching.
@ -116,6 +117,7 @@
// Damage settings
#define B_BURN_DAMAGE GEN_7 // In Gen7+, burn damage is 1/16th of max HP instead of 1/8th.
#define B_BURN_FACADE_DMG GEN_7 // In Gen6+, burn's effect of lowering the Attack stat no longer applies to Facade.
#define B_BINDING_DAMAGE GEN_7 // In Gen6+, binding damage is 1/8 of max HP instead of 1/16. (With Binding Band, 1/6 and 1/8 respectively.)
#define B_PSYWAVE_DMG GEN_7 // Psywave's damage formula. See Cmd_psywavedamageeffect.
#define B_PAYBACK_SWITCH_BOOST GEN_7 // In Gen5+, if the opponent switches out, Payback's damage will no longer be doubled.
@ -152,16 +154,18 @@
#define B_RECOIL_IF_MISS_DMG GEN_7 // In Gen5+, Jump Kick and High Jump Kick will always do half of the user's max HP when missing.
#define B_KLUTZ_FLING_INTERACTION GEN_7 // In Gen5+, Pokémon with the Klutz ability can't use Fling.
#define B_UPDATED_CONVERSION GEN_7 // In Gen6+, Conversion changes the user's type to match their first move's. Before, it would choose a move at random.
#define B_PP_REDUCED_BY_SPITE GEN_7 // In Gen4+, Spite reduces the foe's last move's PP by 4, instead of 2 to 5.
#define B_MINIMIZE_EVASION GEN_7 // In Gen5+, Minimize raises evasion by 2 stages instead of 1.
// Move accuracy settings
#define B_TOXIC_NEVER_MISS GEN_7 // In Gen6+, if Toxic is used by a Poison-type Pokémon, it will never miss.
#define B_MINIMIZE_DMG_ACC GEN_7 // In Gen6+, moves that causes double damage to minimized Pokémon will also skip accuracy checks.
#define B_BLIZZARD_HAIL GEN_7 // In Gen4+, Blizzard bypasses accuracy checks if it's hailing.
#define B_SHEER_COLD_ACC GEN_7 // In Gen7+, Sheer Cold's base chance of hitting is reduced to 20% if the user isn't Ice-typed.
// Other move settings
#define B_SOUND_SUBSTITUTE GEN_7 // In Gen6+, sound moves bypass Substitute.
#define B_INCINERATE_GEMS GEN_7 // In Gen6+, Incinerate can destroy Gems.
#define B_PP_REDUCED_BY_SPITE GEN_7 // In Gen4+, Spite reduces the foe's last move's PP by 4, instead of 2 to 5.
#define B_CAN_SPITE_FAIL GEN_7 // In Gen4+, Spite can no longer fail if the foe's last move only has 1 remaining PP.
#define B_CRASH_IF_TARGET_IMMUNE GEN_7 // In Gen4+, The user of Jump Kick or High Jump Kick will "keep going and crash" if it attacks a target that is immune to the move.
#define B_MEMENTO_FAIL GEN_7 // In Gen4+, Memento fails if there is no target or if the target is protected or behind substitute. But not if Atk/Sp. Atk are at -6.
@ -170,6 +174,10 @@
#define B_BRICK_BREAK GEN_7 // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune.
#define B_WISH_HP_SOURCE GEN_7 // In Gen5+, Wish heals half of the user's max HP instead of the target's.
#define B_RAMPAGE_CANCELLING GEN_7 // In Gen5+, a failed Thrash, etc, will cancel except on its last turn.
#define B_HEAL_BLOCKING GEN_7 // In Gen5+, Heal Block prevents healing by Black Sludge, Leftovers, Shell Bell. Affected Pokémon will not consume held HP-restoring Berries or Berry Juice.
// Draining abilities will not heal but will prevent damage. In Gen6+, Heal Block prevents the use of most HP-draining moves.
#define B_ROOTED_GROUNDING GEN_7 // In Gen4+, Ingrain causes the affected Pokémon to become grounded.
#define B_GROWTH_UNDER_SUN GEN_7 // In Gen5+, Growth's effects are doubled when under the effects of the sun.
#define B_TELEPORT_BEHAVIOR GEN_7 // In LGPE+, Teleport lets the user swap out with another party member.
// Ability settings
@ -182,11 +190,14 @@
#define B_FLASH_FIRE_FROZEN GEN_7 // In Gen5+, Flash Fire can trigger even when frozen, when it couldn't before.
#define B_SYNCHRONIZE_NATURE GEN_8 // In Gen8, if a Pokémon with Synchronize is leading the party, it's 100% guaranteed that wild Pokémon will have the same ability, as opposed to 50% previously.
#define B_SYNCHRONIZE_TOXIC GEN_8 // In Gen5+, if a Pokémon with Synchronize is badly poisoned, the opponent will also become badly poisoned. Previously, the opponent would become regular poisoned.
#define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities.
#define B_UPDATED_INTIMIDATE GEN_8 // In Gen8, Intimidate doesn't work on opponents with the Inner Focus, Scrappy, Own Tempo or Oblivious abilities. It also activates Rattled.
#define B_OBLIVIOUS_TAUNT GEN_7 // In Gen6+, Pokémon with Oblivious can't be taunted.
// Item settings
#define B_HP_BERRIES GEN_7 // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn.
#define B_BERRIES_INSTANT GEN_7 // In Gen4+, most berries activate on battle start/switch-in if applicable. In Gen3, they only activate either at the move end or turn end.
#define B_CONFUSE_BERRIES_HEAL GEN_8 // Before Gen7, Figy and similar berries restore 1/8th of HP and trigger at half HP. In Gen7 they restore half HP, triggering at 25% HP. In Gen8 they heal 1/3rd of HP.
// Requires using Item Expansion or manually editing the holdEffectParam of Figy, Wiki, Mago, Aguav and Iapapa berries.
#define B_X_ITEMS_BUFF GEN_7 // In Gen7+, the X Items raise a stat by 2 stages instead of 1.
#define B_MENTAL_HERB GEN_5 // In Gen5+, the Mental Herb cures Infatuation, Taunt, Encore, Torment, Heal Block, and Disable
#define B_TRAINERS_KNOCK_OFF_ITEMS TRUE // If TRUE, trainers can steal/swap your items (non-berries are restored after battle). In vanilla games trainers cannot steal items.
@ -202,7 +213,6 @@
#define B_HEAVY_BALL_MODIFIER GEN_7 // In Gen7+, Heavy Ball's ranges change. See Cmd_handleballthrow.
#define B_DREAM_BALL_MODIFIER GEN_8 // In Gen8, Dream Ball's catch multiplier is x4 when the target is asleep or has the ability Comatose.
#define B_SERENE_GRACE_BOOST GEN_7 // In Gen5+, Serene Grace boosts the added flinch chance of King's Rock and Razor Fang.
#define B_LEEK_ALWAYS_CRIT GEN_7 // In Gen6+, if a Farfetch'd or Sirfetch'd holding a Leek use a move with increased Critical Hit ratio, it will always result in a Critical Hit.
// Flag settings
// To use the following features in scripting, replace the 0s with the flag ID you're assigning it to.
@ -244,6 +254,7 @@
// Other settings
#define B_DOUBLE_WILD_CHANCE 0 // % chance of encountering two Pokémon in a Wild Encounter.
#define B_MULTI_BATTLE_WHITEOUT GEN_8 // In Gen4+, multi battles end when the Player and also their Partner don't have any more Pokémon to fight.
#define B_EVOLUTION_AFTER_WHITEOUT GEN_6 // In Gen6+, Pokemon that qualify for evolution after battle will evolve even if the player loses.
#define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper)
// Animation Settings

View File

@ -393,7 +393,8 @@
#define EFFECT_RISING_VOLTAGE 387
#define EFFECT_BEAK_BLAST 388
#define EFFECT_COURT_CHANGE 389
#define EFFECT_STEEL_BEAM 390
#define NUM_BATTLE_MOVE_EFFECTS 390
#define NUM_BATTLE_MOVE_EFFECTS 391
#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H

View File

@ -613,8 +613,10 @@
#define STRINGID_METEORBEAMCHARGING 611
#define STRINGID_HEATUPBEAK 612
#define STRINGID_COURTCHANGE 613
#define STRINGID_PLAYERLOSTTOENEMYTRAINER 614
#define STRINGID_PLAYERPAIDPRIZEMONEY 615
#define BATTLESTRINGS_COUNT 614
#define BATTLESTRINGS_COUNT 616
// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
@ -872,4 +874,16 @@
#define B_MSG_TERRAINPREVENTS_ELECTRIC 1
#define B_MSG_TERRAINPREVENTS_PSYCHIC 2
// gWrappedStringIds
#define B_MSG_WRAPPED_BIND 0
#define B_MSG_WRAPPED_WRAP 1
#define B_MSG_WRAPPED_FIRE_SPIN 2
#define B_MSG_WRAPPED_CLAMP 3
#define B_MSG_WRAPPED_WHIRLPOOL 4
#define B_MSG_WRAPPED_SAND_TOMB 5
#define B_MSG_WRAPPED_MAGMA_STORM 6
#define B_MSG_WRAPPED_INFESTATION 7
#define B_MSG_WRAPPED_SNAP_TRAP 8
#define TRAPPING_MOVES_COUNT 9
#endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H

View File

@ -379,14 +379,20 @@
#define EVO_SPECIFIC_MAP 32 // Pokémon levels up on specified map
#define EVO_LEVEL_NATURE_AMPED 33 // Pokémon reaches the specified level, it has a Hardy, Brave, Adamant, Naughty, Docile, Impish, Lax, Hasty, Jolly, Naive, Rash, Sassy, or Quirky nature.
#define EVO_LEVEL_NATURE_LOW_KEY 34 // Pokémon reaches the specified level, it has a Lonely, Bold, Relaxed, Timid, Serious, Modest, Mild, Quiet, Bashful, Calm, Gentle, or Careful nature.
#define EVO_CRITICAL_HITS 35 // Pokémon performs specified number of critical hits in one battle
#define EVO_SCRIPT_TRIGGER_DMG 36 // Pokémon has specified HP below max, then player interacts trigger
#define EVO_DARK_SCROLL 37 // interacts with Scroll of Darkness
#define EVO_WATER_SCROLL 38 // interacts with Scroll of Waters
#define EVOS_PER_MON 10
// Evolution 'modes,' for GetEvolutionTargetSpecies
#define EVO_MODE_NORMAL 0
#define EVO_MODE_TRADE 1
#define EVO_MODE_ITEM_USE 2
#define EVO_MODE_ITEM_CHECK 3 // If an Everstone is being held, still want to show that the stone *could* be used on that Pokémon to evolve
#define EVO_MODE_NORMAL 0
#define EVO_MODE_TRADE 1
#define EVO_MODE_ITEM_USE 2
#define EVO_MODE_ITEM_CHECK 3 // If an Everstone is being held, still want to show that the stone *could* be used on that Pokémon to evolve
#define EVO_MODE_BATTLE_SPECIAL 4
#define EVO_MODE_OVERWORLD_SPECIAL 5
#define NUM_MALE_LINK_FACILITY_CLASSES 8
#define NUM_FEMALE_LINK_FACILITY_CLASSES 8

View File

@ -8,6 +8,12 @@
#define TRAINER_HILL_ROOF 5
#define TRAINER_HILL_ENTRANCE 6
#define HILL_MODE_NORMAL 0
#define HILL_MODE_VARIETY 1
#define HILL_MODE_UNIQUE 2
#define HILL_MODE_EXPERT 3
#define NUM_TRAINER_HILL_MODES 4
#define NUM_TRAINER_HILL_FLOORS 4
#define NUM_TRAINER_HILL_FLOORS_JP 2
@ -30,20 +36,33 @@
#define TRAINER_HILL_FUNC_SET_GAME_SAVED 14
#define TRAINER_HILL_FUNC_CLEAR_GAME_SAVED 15
#define TRAINER_HILL_FUNC_GET_WON 16
#define TRAINER_HILL_FUNC_SET_TAG 17
#define TRAINER_HILL_FUNC_SET_MODE 17
#define TRAINER_HILL_TEXT_INTRO 2
#define TRAINER_HILL_TEXT_PLAYER_LOST 3
#define TRAINER_HILL_TEXT_PLAYER_WON 4
#define TRAINER_HILL_TEXT_AFTER 5
#define TRAINER_HILL_TRAINERS_PER_FLOOR 2
#define NUM_TRAINER_HILL_TRAINERS (NUM_TRAINER_HILL_FLOORS * TRAINER_HILL_TRAINERS_PER_FLOOR)
#define NUM_TRAINER_HILL_TRAINERS_JP (NUM_TRAINER_HILL_FLOORS_JP * TRAINER_HILL_TRAINERS_PER_FLOOR)
#define HILL_TRAINERS_PER_FLOOR 2
#define NUM_TRAINER_HILL_TRAINERS (NUM_TRAINER_HILL_FLOORS * HILL_TRAINERS_PER_FLOOR)
#define NUM_TRAINER_HILL_TRAINERS_JP (NUM_TRAINER_HILL_FLOORS_JP * HILL_TRAINERS_PER_FLOOR)
// Values returned by TrainerHillGetChallengeStatus
#define TRAINER_HILL_PLAYER_STATUS_LOST 0
#define TRAINER_HILL_PLAYER_STATUS_ECARD_SCANNED 1
#define TRAINER_HILL_PLAYER_STATUS_NORMAL 2
#define HILL_TRAINER_NAME_LENGTH 11
#define TRAINER_HILL_OTID 0x10000000
// The full map of each Trainer Hill floor is 16x21.
// The first 5x21 at the top is the entrance/exit area,
// and the remaining 16x16 is the randomized portion of
// the room where the trainers are.
#define HILL_FLOOR_WIDTH 16
#define HILL_FLOOR_HEIGHT_MAIN 16
#define HILL_FLOOR_HEIGHT_MARGIN 5
#define HILL_FLOOR_HEIGHT (HILL_FLOOR_HEIGHT_MAIN + HILL_FLOOR_HEIGHT_MARGIN)
#endif

View File

@ -35,7 +35,7 @@ struct EReaderTrainerHillTrainer
{
u8 trainerNum;
struct TrainerHillTrainer trainer;
struct TrHillDisplay display;
struct TrainerHillFloorMap map;
u32 checksum;
}; // size=0x274

View File

@ -14,6 +14,7 @@
#include "constants/maps.h"
#include "constants/pokemon.h"
#include "constants/easy_chat.h"
#include "constants/trainer_hill.h"
#include "constants/expansion_branches.h"
// Prevent cross-jump optimization.
@ -286,8 +287,6 @@ struct BattleTowerPokemon
u8 friendship;
};
#define NULL_BATTLE_TOWER_POKEMON { .nickname = __("$$$$$$$$$$$") }
struct EmeraldBattleTowerRecord
{
/*0x00*/ u8 lvlMode; // 0 = level 50, 1 = level 100
@ -815,7 +814,7 @@ struct TrainerNameRecord
u8 trainerName[PLAYER_NAME_LENGTH + 1];
};
struct SaveTrainerHill
struct TrainerHillSave
{
/*0x3D64*/ u32 timer;
/*0x3D68*/ u32 bestTime;
@ -827,7 +826,7 @@ struct SaveTrainerHill
/*0x3D6E*/ u16 hasLost:1;
/*0x3D6E*/ u16 maybeECardScanDuringChallenge:1;
/*0x3D6E*/ u16 field_3D6E_0f:1;
/*0x3D6E*/ u16 tag:2;
/*0x3D6E*/ u16 mode:2; // HILL_MODE_*
};
struct WonderNewsMetadata
@ -1010,7 +1009,7 @@ struct SaveBlock1
/*0x31F8*/ struct EnigmaBerry enigmaBerry;
/*0x322C*/ struct MysteryGiftSave mysteryGift;
/*0x3598*/ u8 unused_3598[0x180];
/*0x3718*/ u32 trainerHillTimes[4];
/*0x3718*/ u32 trainerHillTimes[NUM_TRAINER_HILL_MODES];
/*0x3728*/ struct RamScript ramScript;
/*0x3B14*/ struct RecordMixingGift recordMixingGift;
/*0x3B24*/ u8 seen2[NUM_DEX_FLAG_BYTES];
@ -1018,7 +1017,7 @@ struct SaveBlock1
/*0x3B98*/ struct TrainerNameRecord trainerNameRecords[20];
/*0x3C88*/ u8 registeredTexts[UNION_ROOM_KB_ROW_COUNT][21];
/*0x3D5A*/ u8 unused_3D5A[10];
/*0x3D64*/ struct SaveTrainerHill trainerHill;
/*0x3D64*/ struct TrainerHillSave trainerHill;
/*0x3D70*/ struct WaldaPhrase waldaPhrase;
// sizeof: 0x3D88
};

View File

@ -4906,6 +4906,7 @@ extern const u32 gBattleAnimSpriteGfx_StonePillar[];
extern const u32 gBattleAnimSpritePal_StonePillar[];
extern const u32 gBattleAnimSpriteGfx_StraightBeam[];
extern const u32 gBattleAnimSpritePal_StraightBeam[];
extern const u32 gBattleAnimSpritePal_Poltergeist[];
extern const u32 gBattleAnimSpriteGfx_SubstituteBack[];
extern const u32 gBattleAnimSpriteGfx_SubstituteFront[];
extern const u32 gBattleAnimSpritePal_SubstituteFront[];

View File

@ -1,13 +1,13 @@
#ifndef GUARD_TRAINER_HILL_H
#define GUARD_TRAINER_HILL_H
#define HILL_TRAINER_NAME_LENGTH 11
#define DUMMY_HILL_MON { .nickname = __("$$$$$$$$$$$") }
struct TrainerHillTrainer
{
u8 name[HILL_TRAINER_NAME_LENGTH];
u8 facilityClass;
u32 unused;
bool32 unused; // Set to TRUE on JP trainers
u16 speechBefore[EASY_CHAT_BATTLE_WORDS_COUNT];
u16 speechWin[EASY_CHAT_BATTLE_WORDS_COUNT];
u16 speechLose[EASY_CHAT_BATTLE_WORDS_COUNT];
@ -15,44 +15,30 @@ struct TrainerHillTrainer
struct BattleTowerPokemon mons[PARTY_SIZE];
};
struct TrHillRoomTrainers
struct TrainerHillFloorMap
{
u8 name[2][HILL_TRAINER_NAME_LENGTH];
u8 facilityClass[2];
u8 metatileData[HILL_FLOOR_WIDTH * HILL_FLOOR_HEIGHT_MAIN]; // Add NUM_METATILES_IN_PRIMARY to the values in this array to get metatile ids.
u16 collisionData[HILL_FLOOR_WIDTH]; // One bit for each tile in column-major order, so every array entry is one row. 1 = impassable, 0 = passable
u8 trainerCoords[HILL_TRAINERS_PER_FLOOR]; // Starting at (0,6). Format is 0bYYYYXXXX.
u8 trainerDirections; // DIR_* - 1, 4 bits per trainer
u8 trainerRanges; // 4 bits per trainer
};
struct TrHillDisplay
{
// Metatile data. Add 0x200 to the values in this array to get metatiles.
// This data then overwrites the metatiles in the map starting at (0,5)
u8 metatileData[0x100];
// Collision data. One bit for each tile in column-major order,
// so every array entry is one row. 1 = impassable, 0 = passable
u16 collisionData[16];
// Trainer coordinates, starting at (0,6). Format is 0bYYYYXXXX.
u8 coords[2];
// Trainer facing directions. Same as (DIR_* - 1).
// Effectively an array of nibbles, one for each trainer.
u8 direction;
// Trainer sight ranges. Effectively an array of nibbles, one for each trainer.
u8 range;
};
struct TrHillFloor
struct TrainerHillFloor
{
u8 trainerNum1;
u8 trainerNum2;
struct TrainerHillTrainer trainers[2];
struct TrHillDisplay display;
struct TrainerHillTrainer trainers[HILL_TRAINERS_PER_FLOOR];
struct TrainerHillFloorMap map;
};
struct TrHillTag
struct TrainerHillChallenge
{
u8 numTrainers;
u8 unused1;
u8 numFloors;
u32 checksum;
struct TrHillFloor floors[0];
u32 checksum; // A byte array sum of the floor data
struct TrainerHillFloor floors[0]; // Floor data is assumed to follow, so this will be intentionally read out of bounds
};
extern u32 *gTrainerHillVBlankCounter;

View File

@ -20,7 +20,9 @@ SECTIONS {
. = 0x1C000;
INCLUDE "sym_ewram.ld"
*libc.a:impure.o(.data);
*libc.a:locale.o(.data);
*libc.a:mallocr.o(.data);
. = 0x40000;
}
@ -464,6 +466,7 @@ SECTIONS {
src/mystery_gift_server.o(.rodata);
src/mystery_gift_client.o(.rodata);
src/mystery_gift_scripts.o(.rodata);
src/wonder_news.o(.rodata);
src/union_room_chat.o(.rodata);
src/berry_crush.o(.rodata);
src/berry_powder.o(.rodata);
@ -1250,9 +1253,43 @@ SECTIONS {
src/librfu_sio32id.o(.rodata);
*libgcc.a:_divdi3.o(.rodata);
*libgcc.a:_udivdi3.o(.rodata);
*libc.a(.rodata);
*libc.a(.data);
*libc.a:memcpy.o(.rodata);
*libc.a:memset.o(.rodata);
*libc.a:strcmp.o(.rodata);
*libc.a:strcpy.o(.rodata);
*libc.a:impure.o(.rodata);
*libc.a:vsprintf.o(.rodata);
*libc.a:vfprintf.o(.rodata);
*libc.a:wsetup.o(.rodata);
*libc.a:dtoa.o(.rodata);
*libc.a:fflush.o(.rodata);
*libc.a:findfp.o(.rodata);
*libc.a:freer.o(.rodata);
*libc.a:mtrim.o(.rodata);
*libc.a:fvwrite.o(.rodata);
*libc.a:fwalk.o(.rodata);
*libc.a:locale.o(.rodata);
*libc.a:makebuf.o(.rodata);
*libc.a:mallocr.o(.rodata);
*libc.a:mbtowc_r.o(.rodata);
*libc.a:memchr.o(.rodata);
*libc.a:memmove.o(.rodata);
*libc.a:mlock.o(.rodata);
*libc.a:mprec.o(.rodata);
*libc.a:s_isinf.o(.rodata);
*libc.a:s_isnan.o(.rodata);
*libc.a:sbrkr.o(.rodata);
*libc.a:stdio.o(.rodata);
*libc.a:strlen.o(.rodata);
*libc.a:syscalls.o(.rodata);
*libc.a:writer.o(.rodata);
*libc.a:callocr.o(.rodata);
*libc.a:closer.o(.rodata);
*libc.a:errno.o(.rodata);
*libc.a:fstatr.o(.rodata);
*libc.a:libcfunc.o(.rodata);
*libc.a:lseekr.o(.rodata);
*libc.a:readr.o(.rodata);
src/libisagbprn.o(.rodata);
} =0

View File

@ -438,6 +438,9 @@ static u8 ChooseMoveOrAction_Doubles(void)
{
if (gBattleMons[sBattler_AI].moves[j] != 0)
{
if (!CanTargetBattler(sBattler_AI, i, gBattleMons[sBattler_AI].moves[j]))
continue;
if (mostViableMovesScores[0] == AI_THINKING_STRUCT->score[j])
{
mostViableMovesScores[mostViableMovesNo] = AI_THINKING_STRUCT->score[j];
@ -552,7 +555,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
s32 moveType;
u16 moveTarget = AI_GetBattlerMoveTargetType(battlerAtk, move);
u16 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, move);
u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef);
u32 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef);
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
u32 i;
u16 predictedMove = gLastMoves[battlerDef]; // TODO better move prediction
@ -597,6 +600,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case AI_EFFECTIVENESS_x0:
RETURN_SCORE_MINUS(20);
break;
case AI_EFFECTIVENESS_x0_125:
case AI_EFFECTIVENESS_x0_25:
RETURN_SCORE_MINUS(10);
break;
@ -639,7 +643,7 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
RETURN_SCORE_MINUS(20);
break;
case ABILITY_WONDER_GUARD:
if (effectiveness != AI_EFFECTIVENESS_x2 && effectiveness != AI_EFFECTIVENESS_x4)
if (effectiveness < AI_EFFECTIVENESS_x2)
return 0;
break;
case ABILITY_SAP_SIPPER:
@ -2296,6 +2300,8 @@ static s16 AI_CheckBadMove(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
case EFFECT_HIT_ENEMY_HEAL_ALLY: // pollen puff
if (IsTargetingPartner(battlerAtk, battlerDef))
{
if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK)
return 0;
if (AtMaxHp(battlerDef))
score -= 10;
else if (gBattleMons[battlerDef].hp > gBattleMons[battlerDef].maxHP / 2)
@ -2519,33 +2525,17 @@ static s16 AI_TryToFaint(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
switch (AI_GetMoveEffectiveness(move, battlerAtk, battlerDef))
{
case AI_EFFECTIVENESS_x8:
score += 8;
break;
case AI_EFFECTIVENESS_x4:
if (WEATHER_HAS_EFFECT
&& gBattleWeather & B_WEATHER_STRONG_WINDS
&& IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING))
{
if (AI_RandLessThan(176)) //Consider it supereffective instead of hypereffective.
score += 2;
else
score++;
}
else
score += 4;
score += 4;
break;
case AI_EFFECTIVENESS_x2:
if (WEATHER_HAS_EFFECT
&& gBattleWeather & B_WEATHER_STRONG_WINDS
&& IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING))
{
break; // Don't increase score, consider it neutral.
}
if (AI_RandLessThan(176))
score += 2;
else
{
if (AI_RandLessThan(176))
score += 2;
else
score++;
}
score++;
break;
}
}
@ -2957,7 +2947,7 @@ static s16 AI_CheckViability(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
{
// move data
u16 moveEffect = gBattleMoves[move].effect;
u8 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef);
u32 effectiveness = AI_GetMoveEffectiveness(move, battlerAtk, battlerDef);
u8 atkPriority = GetMovePriority(battlerAtk, move);
u16 predictedMove = gLastMoves[battlerDef]; //for now
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
@ -4902,6 +4892,9 @@ static s16 AI_HPAware(u8 battlerAtk, u8 battlerDef, u16 move, s16 score)
|| (moveType == TYPE_ELECTRIC && AI_DATA->atkPartnerAbility == ABILITY_VOLT_ABSORB)
|| (moveType == TYPE_WATER && (AI_DATA->atkPartnerAbility == ABILITY_DRY_SKIN || AI_DATA->atkPartnerAbility == ABILITY_WATER_ABSORB)))
{
if (gStatuses3[battlerDef] & STATUS3_HEAL_BLOCK)
return 0;
if (CanTargetFaintAi(FOE(battlerAtk), AI_DATA->battlerAtkPartner)
|| (CanTargetFaintAi(BATTLE_PARTNER(FOE(battlerAtk)), AI_DATA->battlerAtkPartner)))
score--;

View File

@ -602,39 +602,39 @@ static u32 GetBestMonBatonPass(struct Pokemon *party, int firstId, int lastId, u
return PARTY_SIZE;
}
static u32 GestBestMonOffensive(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler)
static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId, u8 invalidMons, u32 opposingBattler)
{
int i, bits = 0;
while (bits != 0x3F) // All mons were checked.
{
int bestDmg = 0;
u32 bestResist = UQ_4_12(1.0);
int bestMonId = PARTY_SIZE;
// Find the mon whose type is the most suitable offensively.
// Find the mon whose type is the most suitable defensively.
for (i = firstId; i < lastId; i++)
{
if (!(gBitTable[i] & invalidMons) && !(gBitTable[i] & bits))
{
u16 species = GetMonData(&party[i], MON_DATA_SPECIES);
u32 typeDmg = UQ_4_12(1.0);
u32 typeEffectiveness = UQ_4_12(1.0);
u8 atkType1 = gBaseStats[species].type1;
u8 atkType2 = gBaseStats[species].type2;
u8 defType1 = gBattleMons[opposingBattler].type1;
u8 defType2 = gBattleMons[opposingBattler].type2;
u8 atkType1 = gBattleMons[opposingBattler].type1;
u8 atkType2 = gBattleMons[opposingBattler].type2;
u8 defType1 = gBaseStats[species].type1;
u8 defType2 = gBaseStats[species].type2;
typeDmg *= GetTypeModifier(atkType1, defType1);
typeEffectiveness *= GetTypeModifier(atkType1, defType1);
if (atkType2 != atkType1)
typeDmg *= GetTypeModifier(atkType2, defType1);
typeEffectiveness *= GetTypeModifier(atkType2, defType1);
if (defType2 != defType1)
{
typeDmg *= GetTypeModifier(atkType1, defType2);
typeEffectiveness *= GetTypeModifier(atkType1, defType2);
if (atkType2 != atkType1)
typeDmg *= GetTypeModifier(atkType2, defType2);
typeEffectiveness *= GetTypeModifier(atkType2, defType2);
}
if (bestDmg < typeDmg)
if (typeEffectiveness < bestResist)
{
bestDmg = typeDmg;
bestResist = typeEffectiveness;
bestMonId = i;
}
}
@ -698,7 +698,6 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
u8 GetMostSuitableMonToSwitchInto(void)
{
u32 opposingBattler = 0;
u32 bestDmg = 0;
u32 bestMonId = 0;
u8 battlerIn1 = 0, battlerIn2 = 0;
s32 firstId = 0;
@ -757,7 +756,7 @@ u8 GetMostSuitableMonToSwitchInto(void)
if (bestMonId != PARTY_SIZE)
return bestMonId;
bestMonId = GestBestMonOffensive(party, firstId, lastId, invalidMons, opposingBattler);
bestMonId = GetBestMonTypeMatchup(party, firstId, lastId, invalidMons, opposingBattler);
if (bestMonId != PARTY_SIZE)
return bestMonId;

View File

@ -950,10 +950,9 @@ u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
return typeEffectiveness;
}
u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
{
u8 damageVar;
u32 effectivenessMultiplier;
u32 damageVar, effectivenessMultiplier;
gMoveResultFlags = 0;
gCurrentMove = move;
@ -965,6 +964,9 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
default:
damageVar = AI_EFFECTIVENESS_x0;
break;
case UQ_4_12(0.125):
damageVar = AI_EFFECTIVENESS_x0_125;
break;
case UQ_4_12(0.25):
damageVar = AI_EFFECTIVENESS_x0_25;
break;
@ -980,6 +982,9 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
case UQ_4_12(4.0):
damageVar = AI_EFFECTIVENESS_x4;
break;
case UQ_4_12(8.0):
damageVar = AI_EFFECTIVENESS_x8;
break;
}
return damageVar;
@ -1499,6 +1504,10 @@ bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbilit
else // test the odds
{
u16 odds = accuracy + (gBattleMons[battlerAtk].level - gBattleMons[battlerDef].level);
#if B_SHEER_COLD_ACC >= GEN_7
if (gCurrentMove == MOVE_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE))
odds -= 10;
#endif
if (Random() % 100 + 1 < odds && gBattleMons[battlerAtk].level >= gBattleMons[battlerDef].level)
return TRUE;
}

View File

@ -2,6 +2,7 @@
#include "battle.h"
#include "battle_anim.h"
#include "gpu_regs.h"
#include "item_icon.h"
#include "palette.h"
#include "constants/rgb.h"
#include "scanline_effect.h"
@ -39,6 +40,7 @@ static void AnimGhostStatusSprite_Step(struct Sprite *);
static void AnimGrudgeFlame(struct Sprite *);
static void AnimMonMoveCircular(struct Sprite *);
static void AnimMonMoveCircular_Step(struct Sprite *);
static void AnimPoltergeistItem(struct Sprite *);
static const union AffineAnimCmd sAffineAnim_ConfuseRayBallBounce[] =
{
@ -270,6 +272,17 @@ const struct SpriteTemplate gFlashCannonBallMovementTemplate =
.callback = AnimShadowBall
};
const struct SpriteTemplate gPoltergeistEffectTemplate =
{
.tileTag = ANIM_TAG_POLTERGEIST,
.paletteTag = ANIM_TAG_POLTERGEIST,
.oam = &gOamData_AffineNormal_ObjNormal_32x32,
.anims = gDummySpriteAnimTable,
.images = NULL,
.affineAnims = gAffineAnims_ShadowBall,
.callback = AnimPoltergeistItem,
};
static void AnimConfuseRayBallBounce(struct Sprite *sprite)
{
InitSpritePosToAnimAttacker(sprite, TRUE);
@ -870,7 +883,8 @@ void AnimTask_DestinyBondWhiteShadow(u8 taskId)
&& battler != (gBattleAnimAttacker ^ 2)
&& IsBattlerSpriteVisible(battler))
{
if (gAnimMoveIndex == MOVE_DARK_VOID)
if (gAnimMoveIndex == MOVE_DARK_VOID
|| gAnimMoveIndex == MOVE_POLTERGEIST)
spriteId = CreateSprite(&gDarkVoidBlackHoleTemplate, baseX, baseY, 55); //dark void
else
spriteId = CreateSprite(&gDestinyBondWhiteShadowSpriteTemplate, baseX, baseY, 55); //destiny bond
@ -1395,3 +1409,36 @@ static void AnimMonMoveCircular_Step(struct Sprite *sprite)
sprite->callback = DestroySpriteAndMatrix;
}
}
void AnimTask_PoltergeistItem(u8 taskId)
{
struct Task *task = &gTasks[taskId];
u8 x = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_X);
u8 y = GetBattlerSpriteCoord(gBattleAnimTarget, BATTLER_COORD_Y) + (GetBattlerSpriteCoordAttr(gBattleAnimTarget, BATTLER_COORD_ATTR_HEIGHT) / 2);
task->data[0] = AddItemIconSprite(ANIM_TAG_ITEM_BAG, ANIM_TAG_ITEM_BAG, gLastUsedItem);
gSprites[task->data[0]].x = x + 4;
gSprites[task->data[0]].y = y + 4;
gSprites[task->data[0]].data[0] = x + 4;
gSprites[task->data[0]].data[1] = y + 4;
gSprites[task->data[0]].callback = AnimPoltergeistItem;
task->data[1] = CreateSprite(&gPoltergeistEffectTemplate, x, y, 1);
gSprites[task->data[1]].data[0] = x;
gSprites[task->data[1]].data[1] = y;
gAnimVisualTaskCount += 2;
DestroyAnimVisualTask(taskId);
}
static void AnimPoltergeistItem(struct Sprite *sprite)
{
sprite->data[2] += 4;
sprite->x = sprite->data[0] + Sin(sprite->data[2], 24);
sprite->y = sprite->data[1] + (Cos(sprite->data[2], 24) - 24);
if (sprite->data[2] == 256)
DestroyAnimSprite(sprite);
}

View File

@ -1399,16 +1399,9 @@ static void LinkOpponentHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
LinkOpponentBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = LinkOpponentDoMoveAnimation;
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = LinkOpponentDoMoveAnimation;
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
}
}

View File

@ -1231,16 +1231,9 @@ static void LinkPartnerHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
LinkPartnerBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = LinkPartnerDoMoveAnimation;
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = LinkPartnerDoMoveAnimation;
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
}
}

View File

@ -1461,15 +1461,8 @@ static void OpponentHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
OpponentBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = OpponentDoMoveAnimation;
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = OpponentDoMoveAnimation;
}
}
@ -1605,6 +1598,7 @@ static void OpponentHandleChooseMove(void)
else // Wild pokemon - use random move
{
u16 move;
u8 target;
do
{
chosenMoveId = Random() & 3;
@ -1615,6 +1609,10 @@ static void OpponentHandleChooseMove(void)
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (gActiveBattler << 8));
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
do {
target = GetBattlerAtPosition(Random() & 2);
} while (!CanTargetBattler(gActiveBattler, target, move));
#if B_WILD_NATURAL_ENEMIES == TRUE
// Don't bother to loop through table if the move can't attack ally
if (!(gBattleMoves[move].target & MOVE_TARGET_BOTH))
@ -1641,14 +1639,14 @@ static void OpponentHandleChooseMove(void)
break;
}
}
if (isPartnerEnemy)
if (isPartnerEnemy && CanTargetBattler(gActiveBattler, target, move))
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(BATTLE_PARTNER(gActiveBattler)) << 8));
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8));
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (target << 8));
}
else
#endif
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(Random() & 2) << 8));
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (target << 8));
}
else
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (GetBattlerAtPosition(B_POSITION_PLAYER_LEFT) << 8));

View File

@ -436,7 +436,8 @@ static void HandleInputChooseTarget(void)
break;
}
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor])
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor]
|| !CanTargetBattler(gActiveBattler, gMultiUsePlayerCursor, move))
i = 0;
} while (i == 0);
}
@ -485,7 +486,8 @@ static void HandleInputChooseTarget(void)
break;
}
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor])
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor]
|| !CanTargetBattler(gActiveBattler, gMultiUsePlayerCursor, move))
i = 0;
} while (i == 0);
}
@ -2660,16 +2662,9 @@ static void PlayerHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // Always returns FALSE.
{
PlayerBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = PlayerDoMoveAnimation;
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = PlayerDoMoveAnimation;
BattleTv_SetDataBasedOnMove(move, gWeatherMoveAnim, gAnimDisableStructPtr);
}
}

View File

@ -1428,15 +1428,8 @@ static void PlayerPartnerHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
PlayerPartnerBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = PlayerPartnerDoMoveAnimation;
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = PlayerPartnerDoMoveAnimation;
}
}

View File

@ -1327,15 +1327,8 @@ static void RecordedOpponentHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
RecordedOpponentBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = RecordedOpponentDoMoveAnimation;
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = RecordedOpponentDoMoveAnimation;
}
}

View File

@ -1331,15 +1331,8 @@ static void RecordedPlayerHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
RecordedPlayerBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = RecordedPlayerDoMoveAnimation;
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = RecordedPlayerDoMoveAnimation;
}
}

View File

@ -1114,16 +1114,8 @@ static void WallyHandleMoveAnimation(void)
gWeatherMoveAnim = gBattleResources->bufferA[gActiveBattler][12] | (gBattleResources->bufferA[gActiveBattler][13] << 8);
gAnimDisableStructPtr = (struct DisableStruct *)&gBattleResources->bufferA[gActiveBattler][16];
gTransformedPersonalities[gActiveBattler] = gAnimDisableStructPtr->transformedMonPersonality;
if (IsMoveWithoutAnimation(move, gAnimMoveTurn)) // always returns FALSE
{
WallyBufferExecCompleted();
}
else
{
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = WallyDoMoveAnimation;
}
gBattleSpritesDataPtr->healthBoxesData[gActiveBattler].animationState = 0;
gBattlerControllerFuncs[gActiveBattler] = WallyDoMoveAnimation;
}
static void WallyDoMoveAnimation(void)

View File

@ -526,15 +526,6 @@ static void Task_ClearBitWhenSpecialAnimDone(u8 taskId)
#undef tBattlerId
// Great function to include newly added moves that don't have animation yet.
bool8 IsMoveWithoutAnimation(u16 moveId, u8 animationTurn)
{
if (moveId >= (MOVES_COUNT - 1))
return TRUE;
else
return FALSE;
}
// Check if SE has finished or 30 calls, whichever comes first
bool8 IsBattleSEPlaying(u8 battlerId)
{
@ -914,6 +905,8 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool8 castform, bo
{
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], gBattleSpritesDataPtr->animationData->animArg);
paletteOffset = 0x100 + battlerAtk * 16;
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(targetSpecies, otId, personalityValue);
LZDecompressWram(lzPaletteData, gBattleStruct->castformPalette);
LoadPalette(gBattleStruct->castformPalette[gBattleSpritesDataPtr->animationData->animArg], paletteOffset, 32);
gBattleMonForms[battlerAtk] = gBattleSpritesDataPtr->animationData->animArg;
if (gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies != SPECIES_NONE)

View File

@ -3309,7 +3309,7 @@ bool32 CanThrowLastUsedBall(void)
#else
if (!CanThrowBall())
return FALSE;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FRONTIER))
return FALSE;
if (!CheckBagHasItem(gLastThrownBall, 1))
return FALSE;

View File

@ -64,6 +64,8 @@
#include "constants/trainers.h"
#include "cable_club.h"
extern struct Evolution gEvolutionTable[][EVOS_PER_MON];
extern const struct BgTemplate gBattleBgTemplates[];
extern const struct WindowTemplate *const gBattleWindowTemplates[];
@ -115,6 +117,7 @@ static void HandleEndTurn_MonFled(void);
static void HandleEndTurn_FinishBattle(void);
static void SpriteCB_UnusedBattleInit(struct Sprite* sprite);
static void SpriteCB_UnusedBattleInit_Main(struct Sprite *sprite);
static void TrySpecialEvolution(void);
EWRAM_DATA u16 gBattle_BG0_X = 0;
EWRAM_DATA u16 gBattle_BG0_Y = 0;
@ -237,6 +240,8 @@ EWRAM_DATA bool8 gHasFetchedBall = FALSE;
EWRAM_DATA u8 gLastUsedBall = 0;
EWRAM_DATA u16 gLastThrownBall = 0;
EWRAM_DATA bool8 gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
EWRAM_DATA u8 gPartyCriticalHits[PARTY_SIZE] = {0};
EWRAM_DATA static u8 sTriedEvolving = 0;
void (*gPreBattleCallback1)(void);
void (*gBattleMainFunc)(void);
@ -2999,6 +3004,7 @@ static void BattleStartClearSetData(void)
gBattleStruct->usedHeldItems[i][0] = 0;
gBattleStruct->usedHeldItems[i][1] = 0;
gBattleStruct->itemStolen[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM);
gPartyCriticalHits[i] = 0;
}
gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky
@ -3635,12 +3641,18 @@ static void TryDoEventsBeforeFirstTurn(void)
// Primal Reversion
for (i = 0; i < gBattlersCount; i++)
{
if (CanMegaEvolve(i)
&& GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_PRIMAL_ORB)
if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_PRIMAL_ORB)
{
gBattlerAttacker = i;
BattleScriptExecute(BattleScript_PrimalReversion);
return;
for (j = 0; j < EVOS_PER_MON; j++)
{
if (gEvolutionTable[gBattleMons[i].species][j].targetSpecies != SPECIES_NONE
&& gEvolutionTable[gBattleMons[i].species][j].method == EVO_PRIMAL_REVERSION)
{
gBattlerAttacker = i;
BattleScriptExecute(BattleScript_PrimalReversion);
return;
}
}
}
}
@ -4020,7 +4032,8 @@ static void HandleTurnActionSelectionState(void)
{
BtlController_EmitChoosePokemon(BUFFER_A, PARTY_ACTION_CANT_SWITCH, PARTY_SIZE, ABILITY_NONE, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
else if ((i = IsAbilityPreventingEscape(gActiveBattler)))
else if ((i = IsAbilityPreventingEscape(gActiveBattler)
&& ItemId_GetHoldEffect(gBattleMons[gActiveBattler].item) != HOLD_EFFECT_SHED_SHELL))
{
BtlController_EmitChoosePokemon(BUFFER_A, ((i - 1) << 4) | PARTY_ACTION_ABILITY_PREVENTS, PARTY_SIZE, gBattleMons[i - 1].ability, gBattleStruct->battlerPartyOrders[gActiveBattler]);
}
@ -5154,9 +5167,16 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void)
gIsFishingEncounter = FALSE;
gIsSurfingEncounter = FALSE;
ResetSpriteData();
if (gLeveledUpInBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT))
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_RECORDED_LINK
| BATTLE_TYPE_FIRST_BATTLE
| BATTLE_TYPE_SAFARI
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_WALLY_TUTORIAL))
&& (B_EVOLUTION_AFTER_WHITEOUT >= GEN_6 || gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT))
{
gBattleMainFunc = TryEvolvePokemon;
gBattleMainFunc = TrySpecialEvolution;
}
else
{
@ -5174,6 +5194,30 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void)
}
}
static void TrySpecialEvolution(void) // Attempts to perform non-level related battle evolutions (not the script command).
{
s32 i;
for (i = 0; i < PARTY_SIZE; i++)
{
#ifndef POKEMON_EXPANSION
u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i);
#else
u16 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, NULL);
#endif
if (species != SPECIES_NONE && !(sTriedEvolving & gBitTable[i]))
{
sTriedEvolving |= gBitTable[i];
FreeAllWindowBuffers();
gBattleMainFunc = WaitForEvoSceneToFinish;
EvolutionScene(&gPlayerParty[i], species, TRUE, i);
return;
}
}
sTriedEvolving = 0;
gBattleMainFunc = TryEvolvePokemon;
}
static void TryEvolvePokemon(void)
{
s32 i;
@ -5208,7 +5252,7 @@ static void TryEvolvePokemon(void)
static void WaitForEvoSceneToFinish(void)
{
if (gMain.callback2 == BattleMainCB2)
gBattleMainFunc = TryEvolvePokemon;
gBattleMainFunc = TrySpecialEvolution;
}
static void ReturnFromBattleToOverworld(void)

View File

@ -77,8 +77,14 @@ static const u8 sText_ItDoesntAffect[] = _("It doesn't affect\n{B_DEF_NAME_WITH_
static const u8 sText_AttackerFainted[] = _("{B_ATK_NAME_WITH_PREFIX}\nfainted!\p");
static const u8 sText_TargetFainted[] = _("{B_DEF_NAME_WITH_PREFIX}\nfainted!\p");
static const u8 sText_PlayerGotMoney[] = _("{B_PLAYER_NAME} got ¥{B_BUFF1}\nfor winning!\p");
static const u8 sText_PlayerLostToEnemyTrainer[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\pPlayer lost against\n{B_TRAINER1_CLASS} {B_TRAINER1_NAME}!{PAUSE_UNTIL_PRESS}");
static const u8 sText_PlayerPaidPrizeMoney[] = _("{B_PLAYER_NAME} paid ¥{B_BUFF1} as the prize\nmoney…\p… … … …\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}");
static const u8 sText_PlayerWhiteout[] = _("{B_PLAYER_NAME} is out of\nusable POKéMON!\p");
#if B_WHITEOUT_MONEY >= GEN_4
static const u8 sText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} panicked and lost ¥{B_BUFF1}…\p… … … …\p{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}");
#else
static const u8 sText_PlayerWhiteout2[] = _("{B_PLAYER_NAME} whited out!{PAUSE_UNTIL_PRESS}");
#endif
static const u8 sText_PreventsEscape[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} prevents\nescape with {B_SCR_ACTIVE_ABILITY}!\p");
static const u8 sText_CantEscape2[] = _("Can't escape!\p");
static const u8 sText_AttackerCantEscape[] = _("{B_ATK_NAME_WITH_PREFIX} can't escape!");
@ -220,7 +226,7 @@ static const u8 sText_PkmnForesawAttack[] = _("{B_ATK_NAME_WITH_PREFIX} foresaw\
static const u8 sText_PkmnTookAttack[] = _("{B_DEF_NAME_WITH_PREFIX} took the\n{B_BUFF1} attack!");
static const u8 sText_PkmnChoseXAsDestiny[] = _("{B_ATK_NAME_WITH_PREFIX} chose\n{B_CURRENT_MOVE} as its destiny!");
static const u8 sText_PkmnAttack[] = _("{B_BUFF1}'s attack!");
static const u8 sText_PkmnCenterAttention[] = _("{B_ATK_NAME_WITH_PREFIX} became the\ncenter of attention!");
static const u8 sText_PkmnCenterAttention[] = _("{B_DEF_NAME_WITH_PREFIX} became the\ncenter of attention!");
static const u8 sText_PkmnChargingPower[] = _("{B_ATK_NAME_WITH_PREFIX} began\ncharging power!");
static const u8 sText_NaturePowerTurnedInto[] = _("NATURE POWER turned into\n{B_CURRENT_MOVE}!");
static const u8 sText_PkmnStatusNormal[] = _("{B_ATK_NAME_WITH_PREFIX}'s status\nreturned to normal!");
@ -741,6 +747,8 @@ static const u8 sText_CourtChange[] = _("{B_ATK_NAME_WITH_PREFIX} swapped the ba
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{
[STRINGID_PLAYERLOSTTOENEMYTRAINER - BATTLESTRINGS_TABLE_START] = sText_PlayerLostToEnemyTrainer,
[STRINGID_PLAYERPAIDPRIZEMONEY - BATTLESTRINGS_TABLE_START] = sText_PlayerPaidPrizeMoney,
[STRINGID_COURTCHANGE - BATTLESTRINGS_TABLE_START] = sText_CourtChange,
[STRINGID_HEATUPBEAK - BATTLESTRINGS_TABLE_START] = sText_HeatingUpBeak,
[STRINGID_METEORBEAMCHARGING - BATTLESTRINGS_TABLE_START] = sText_MeteorBeamCharging,
@ -1562,17 +1570,17 @@ const u16 gFirstTurnOfTwoStringIds[] =
};
// Index copied from move's index in sTrappingMoves
const u16 gWrappedStringIds[] =
const u16 gWrappedStringIds[TRAPPING_MOVES_COUNT] =
{
STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND
STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP
STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_FIRE_SPIN
STRINGID_PKMNCLAMPED, // MOVE_CLAMP
STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL
STRINGID_PKMNTRAPPEDBYSANDTOMB, // MOVE_SAND_TOMB
STRINGID_TRAPPEDBYSWIRLINGMAGMA, // MOVE_MAGMA_STORM
STRINGID_INFESTATION, // MOVE_INFESTATION
STRINGID_PKMNINSNAPTRAP, // MOVE_SNAPTRAP
[B_MSG_WRAPPED_BIND] = STRINGID_PKMNSQUEEZEDBYBIND, // MOVE_BIND
[B_MSG_WRAPPED_WRAP] = STRINGID_PKMNWRAPPEDBY, // MOVE_WRAP
[B_MSG_WRAPPED_FIRE_SPIN] = STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_FIRE_SPIN
[B_MSG_WRAPPED_CLAMP] = STRINGID_PKMNCLAMPED, // MOVE_CLAMP
[B_MSG_WRAPPED_WHIRLPOOL] = STRINGID_PKMNTRAPPEDINVORTEX, // MOVE_WHIRLPOOL
[B_MSG_WRAPPED_SAND_TOMB] = STRINGID_PKMNTRAPPEDBYSANDTOMB, // MOVE_SAND_TOMB
[B_MSG_WRAPPED_MAGMA_STORM] = STRINGID_TRAPPEDBYSWIRLINGMAGMA, // MOVE_MAGMA_STORM
[B_MSG_WRAPPED_INFESTATION] = STRINGID_INFESTATION, // MOVE_INFESTATION
[B_MSG_WRAPPED_SNAP_TRAP] = STRINGID_PKMNINSNAPTRAP, // MOVE_SNAP_TRAP
};
const u16 gMistUsedStringIds[] =

View File

@ -279,11 +279,18 @@ static const s32 sExperienceScalingFactors[] =
159767,
};
static const u16 sTrappingMoves[] =
static const u16 sTrappingMoves[TRAPPING_MOVES_COUNT] =
{
MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, MOVE_SNAP_TRAP, 0xFFFF
MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, MOVE_SNAP_TRAP,
};
static const u16 sBadgeFlags[8] = {
FLAG_BADGE01_GET, FLAG_BADGE02_GET, FLAG_BADGE03_GET, FLAG_BADGE04_GET,
FLAG_BADGE05_GET, FLAG_BADGE06_GET, FLAG_BADGE07_GET, FLAG_BADGE08_GET,
};
static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 64, 80, 100, 120 };
#define STAT_CHANGE_WORKED 0
#define STAT_CHANGE_DIDNT_WORK 1
@ -1357,24 +1364,20 @@ static void Cmd_attackcanceler(void)
GET_MOVE_TYPE(gCurrentMove, moveType);
if (moveType == TYPE_FIRE
&& (gBattleWeather & B_WEATHER_RAIN_PRIMAL)
&& WEATHER_HAS_EFFECT
&& gBattleMoves[gCurrentMove].power)
if (WEATHER_HAS_EFFECT && gBattleMoves[gCurrentMove].power)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_PrimordialSeaFizzlesOutFireTypeMoves;
return;
}
if (moveType == TYPE_WATER
&& (gBattleWeather & B_WEATHER_SUN_PRIMAL)
&& WEATHER_HAS_EFFECT
&& gBattleMoves[gCurrentMove].power)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_DesolateLandEvaporatesWaterTypeMoves;
return;
if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL))
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_PrimordialSeaFizzlesOutFireTypeMoves;
return;
}
else if (moveType == TYPE_WATER && (gBattleWeather & B_WEATHER_SUN_PRIMAL))
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_DesolateLandEvaporatesWaterTypeMoves;
return;
}
}
if (gBattleOutcome != 0)
@ -1878,11 +1881,7 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)
|| move == MOVE_SURGING_STRIKES
#if B_LEEK_ALWAYS_CRIT >= GEN_6
|| ((gBattleMoves[gCurrentMove].flags & FLAG_HIGH_CRIT) && BENEFITS_FROM_LEEK(battlerAtk, holdEffectAtk))
#endif
)
|| move == MOVE_SURGING_STRIKES)
{
critChance = -2;
}
@ -1914,6 +1913,7 @@ s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move)
static void Cmd_critcalc(void)
{
u16 partySlot;
s32 critChance = CalcCritChanceStage(gBattlerAttacker, gBattlerTarget, gCurrentMove, TRUE);
gPotentialItemEffectBattler = gBattlerAttacker;
@ -1928,6 +1928,12 @@ static void Cmd_critcalc(void)
else
gIsCriticalHit = FALSE;
// Counter for EVO_CRITICAL_HITS.
partySlot = gBattlerPartyIndexes[gBattlerAttacker];
if (gIsCriticalHit && GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER
&& !(gBattleTypeFlags & BATTLE_TYPE_MULTI && GetBattlerPosition(gBattlerAttacker) == B_POSITION_PLAYER_LEFT))
gPartyCriticalHits[partySlot]++;
gBattlescriptCurrInstr++;
}
@ -2949,7 +2955,17 @@ void SetMoveEffect(bool32 primary, u32 certain)
case MOVE_EFFECT_FLINCH:
if (battlerAbility == ABILITY_INNER_FOCUS)
{
gBattlescriptCurrInstr++;
if (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)
{
gLastUsedAbility = ABILITY_INNER_FOCUS;
gBattlerAbility = gEffectBattler;
RecordAbilityBattle(gEffectBattler, ABILITY_INNER_FOCUS);
gBattlescriptCurrInstr = BattleScript_FlinchPrevention;
}
else
{
gBattlescriptCurrInstr++;
}
}
else
{
@ -3028,10 +3044,8 @@ void SetMoveEffect(bool32 primary, u32 certain)
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleScripting.moveEffect];
for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; ; gBattleCommunication[MULTISTRING_CHOOSER]++)
for (gBattleCommunication[MULTISTRING_CHOOSER] = 0; gBattleCommunication[MULTISTRING_CHOOSER] < TRAPPING_MOVES_COUNT; gBattleCommunication[MULTISTRING_CHOOSER]++)
{
if (gBattleCommunication[MULTISTRING_CHOOSER] > ARRAY_COUNT(sTrappingMoves) - 1)
break;
if (sTrappingMoves[gBattleCommunication[MULTISTRING_CHOOSER]] == gCurrentMove)
break;
}
@ -6773,13 +6787,38 @@ static u32 GetTrainerMoneyToGive(u16 trainerId)
static void Cmd_getmoneyreward(void)
{
u32 moneyReward = GetTrainerMoneyToGive(gTrainerBattleOpponent_A);
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
moneyReward += GetTrainerMoneyToGive(gTrainerBattleOpponent_B);
u32 money;
u8 sPartyLevel = 1;
AddMoney(&gSaveBlock1Ptr->money, moneyReward);
PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, moneyReward);
if (gBattleOutcome == B_OUTCOME_WON)
{
money = GetTrainerMoneyToGive(gTrainerBattleOpponent_A);
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
money += GetTrainerMoneyToGive(gTrainerBattleOpponent_B);
AddMoney(&gSaveBlock1Ptr->money, money);
}
else
{
s32 i, count;
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_NONE
&& GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) != SPECIES_EGG)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_LEVEL) > sPartyLevel)
sPartyLevel = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL);
}
}
for (count = 0, i = 0; i < ARRAY_COUNT(sBadgeFlags); i++)
{
if (FlagGet(sBadgeFlags[i]) == TRUE)
++count;
}
money = sWhiteOutBadgeMoney[count] * sPartyLevel;
RemoveMoney(&gSaveBlock1Ptr->money, money);
}
PREPARE_WORD_NUMBER_BUFFER(gBattleTextBuff1, 5, money);
gBattlescriptCurrInstr++;
}
@ -7904,7 +7943,7 @@ static void Cmd_various(void)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
return;
case VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS:
if ((gStatuses3[gActiveBattler] & (STATUS3_SEMI_INVULNERABLE))
if ((gStatuses3[gActiveBattler] & (STATUS3_SEMI_INVULNERABLE | STATUS3_HEAL_BLOCK))
|| BATTLER_MAX_HP(gActiveBattler)
|| !gBattleMons[gActiveBattler].hp
|| !(IsBattlerGrounded(gActiveBattler)))
@ -8579,7 +8618,7 @@ static void Cmd_various(void)
gBattleStruct->mega.playerPrimalRevertedSpecies = gBattleStruct->mega.primalRevertedSpecies[gActiveBattler];
}
// Checks Primal Reversion
primalSpecies = GetMegaEvolutionSpecies(gBattleStruct->mega.primalRevertedSpecies[gActiveBattler], gBattleMons[gActiveBattler].item);
primalSpecies = GetPrimalReversionSpecies(gBattleStruct->mega.primalRevertedSpecies[gActiveBattler], gBattleMons[gActiveBattler].item);
gBattleMons[gActiveBattler].species = primalSpecies;
PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species);
@ -9471,6 +9510,7 @@ static void Cmd_various(void)
else
{
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].item);
gLastUsedItem = gBattleMons[gActiveBattler].item;
gBattlescriptCurrInstr += 7;
}
return;
@ -9923,7 +9963,7 @@ static void Cmd_manipulatedamage(void)
gBattleMoveDamage = GetDrainedBigRootHp(gBattlerAttacker, gBattleMoveDamage);
break;
case DMG_1_2_ATTACKER_HP:
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 2;
gBattleMoveDamage = (gBattleMons[gBattlerAttacker].maxHP + 1) / 2; // Half of Max HP Rounded UP
break;
case DMG_RECOIL_FROM_IMMUNE:
gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2;
@ -10943,6 +10983,10 @@ static void Cmd_tryKO(void)
else
{
u16 odds = gBattleMoves[gCurrentMove].accuracy + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level);
#if B_SHEER_COLD_ACC >= GEN_7
if (gCurrentMove == MOVE_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE))
odds -= 10;
#endif
if (Random() % 100 + 1 < odds && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level)
lands = TRUE;
}
@ -12438,9 +12482,9 @@ static void Cmd_jumpifattackandspecialattackcannotfall(void) // memento
static void Cmd_setforcedtarget(void) // follow me
{
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTimer = 1;
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmeTarget = gBattlerAttacker;
gSideTimers[GetBattlerSide(gBattlerAttacker)].followmePowder = TestMoveFlags(gCurrentMove, FLAG_POWDER);
gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer = 1;
gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTarget = gBattlerTarget;
gSideTimers[GetBattlerSide(gBattlerTarget)].followmePowder = TestMoveFlags(gCurrentMove, FLAG_POWDER);
gBattlescriptCurrInstr++;
}
@ -12515,13 +12559,16 @@ static void Cmd_jumpifnodamage(void)
static void Cmd_settaunt(void)
{
#if B_OBLIVIOUS_TAUNT >= GEN_6
if (GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS)
{
gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp;
gLastUsedAbility = ABILITY_OBLIVIOUS;
RecordAbilityBattle(gBattlerTarget, ABILITY_OBLIVIOUS);
}
else if (gDisableStructs[gBattlerTarget].tauntTimer == 0)
else
#endif
if (gDisableStructs[gBattlerTarget].tauntTimer == 0)
{
#if B_TAUNT_TURNS >= GEN_5
u8 turns = 4;

View File

@ -1575,12 +1575,22 @@ void PrepareStringBattle(u16 stringId, u8 battler)
gBattleScripting.stickyWebStatDrop = 0;
gBattlerAbility = gBattlerTarget;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_DefiantActivates;
gBattlescriptCurrInstr = BattleScript_AbilityRaisesDefenderStat;
if (targetAbility == ABILITY_DEFIANT)
SET_STATCHANGER(STAT_ATK, 2, FALSE);
else
SET_STATCHANGER(STAT_SPATK, 2, FALSE);
}
#if B_UPDATED_INTIMIDATE >= GEN_8
else if (stringId == STRINGID_PKMNCUTSATTACKWITH && targetAbility == ABILITY_RATTLED
&& CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
{
gBattlerAbility = gBattlerTarget;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AbilityRaisesDefenderStat;
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
}
#endif
gActiveBattler = battler;
BtlController_EmitPrintString(BUFFER_A, stringId);
@ -1680,15 +1690,21 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move)
switch (gBattleMoves[move].effect)
{
#if B_HEAL_BLOCKING >= GEN_6
case EFFECT_ABSORB:
case EFFECT_STRENGTH_SAP:
case EFFECT_DREAM_EATER:
#endif
case EFFECT_MORNING_SUN:
case EFFECT_SYNTHESIS:
case EFFECT_MOONLIGHT:
case EFFECT_RESTORE_HP:
case EFFECT_REST:
case EFFECT_ROOST:
case EFFECT_HEALING_WISH:
case EFFECT_WISH:
case EFFECT_DREAM_EATER:
case EFFECT_HEAL_PULSE:
case EFFECT_JUNGLE_HEALING:
return TRUE;
default:
return FALSE;
@ -4907,7 +4923,11 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
if (effect == 1) // Drain Hp ability.
{
#if B_HEAL_BLOCKING >= GEN_5
if (BATTLER_MAX_HP(battler) || gStatuses3[battler] & STATUS3_HEAL_BLOCK)
#else
if (BATTLER_MAX_HP(battler))
#endif
{
if ((gProtectStructs[gBattlerAttacker].notFirstStrike))
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless;
@ -6080,9 +6100,19 @@ bool32 HasEnoughHpToEatBerry(u32 battlerId, u32 hpFraction, u32 itemId)
return FALSE;
}
#if B_CONFUSE_BERRIES_HEAL >= GEN_7
#define CONFUSE_BERRY_HP_FRACTION 4
#else
#define CONFUSE_BERRY_HP_FRACTION 2
#endif
static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2)
{
if (HasEnoughHpToEatBerry(battlerId, 2, itemId))
#if B_HEAL_BLOCKING >= GEN_5
if (HasEnoughHpToEatBerry(battlerId, CONFUSE_BERRY_HP_FRACTION, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK))
#else
if (HasEnoughHpToEatBerry(battlerId, CONFUSE_BERRY_HP_FRACTION, itemId))
#endif
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, flavorId);
@ -6118,6 +6148,8 @@ static u8 HealConfuseBerry(u32 battlerId, u32 itemId, u8 flavorId, bool32 end2)
return 0;
}
#undef CONFUSE_BERRY_HP_FRACTION
static u8 StatRaiseBerry(u32 battlerId, u32 itemId, u32 statId, bool32 end2)
{
if (CompareStat(battlerId, statId, MAX_STAT_STAGE, CMP_LESS_THAN) && HasEnoughHpToEatBerry(battlerId, GetBattlerHoldEffectParam(battlerId), itemId))
@ -6268,7 +6300,11 @@ u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 exec
static u8 ItemHealHp(u32 battlerId, u32 itemId, bool32 end2, bool32 percentHeal)
{
#if B_HEAL_BLOCKING >= GEN_5
if (HasEnoughHpToEatBerry(battlerId, 2, itemId) && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK)
#else
if (HasEnoughHpToEatBerry(battlerId, 2, itemId)
#endif
&& !(gBattleScripting.overrideBerryRequirements && gBattleMons[battlerId].hp == gBattleMons[battlerId].maxHP))
{
if (percentHeal)
@ -6707,7 +6743,11 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
break;
case HOLD_EFFECT_LEFTOVERS:
LEFTOVERS:
#if B_HEAL_BLOCKING >= GEN_5
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK))
#else
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn)
#endif
{
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16;
if (gBattleMoveDamage == 0)
@ -7137,7 +7177,11 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
if (gSpecialStatuses[gBattlerAttacker].damagedMons // Need to have done damage
&& gBattlerAttacker != gBattlerTarget
&& gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP
#if B_HEAL_BLOCKING >= GEN_5
&& gBattleMons[gBattlerAttacker].hp != 0 && !(gStatuses3[battlerId] & STATUS3_HEAL_BLOCK))
#else
&& gBattleMons[gBattlerAttacker].hp != 0)
#endif
{
gLastUsedItem = atkItem;
gPotentialItemEffectBattler = gBattlerAttacker;
@ -7727,31 +7771,35 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move)
return FALSE;
}
bool32 IsBattlerGrounded(u8 battlerId)
// Only called directly when calculating damage type effectiveness
static bool32 IsBattlerGrounded2(u8 battlerId, bool32 considerInverse)
{
if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_IRON_BALL)
return TRUE;
else if (gFieldStatuses & STATUS_FIELD_GRAVITY)
if (gFieldStatuses & STATUS_FIELD_GRAVITY)
return TRUE;
else if (gStatuses3[battlerId] & STATUS3_ROOTED)
#if B_ROOTED_GROUNDING >= GEN_4
if (gStatuses3[battlerId] & STATUS3_ROOTED)
return TRUE;
else if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN)
#endif
if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN)
return TRUE;
if (gStatuses3[battlerId] & STATUS3_TELEKINESIS)
return FALSE;
if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE)
return FALSE;
if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_AIR_BALLOON)
return FALSE;
if (GetBattlerAbility(battlerId) == ABILITY_LEVITATE)
return FALSE;
if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING) && (!considerInverse || !FlagGet(B_FLAG_INVERSE_BATTLE)))
return FALSE;
return TRUE;
}
else if (gStatuses3[battlerId] & STATUS3_TELEKINESIS)
return FALSE;
else if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE)
return FALSE;
else if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_AIR_BALLOON)
return FALSE;
else if (GetBattlerAbility(battlerId) == ABILITY_LEVITATE)
return FALSE;
else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING))
return FALSE;
else
return TRUE;
bool32 IsBattlerGrounded(u8 battlerId)
{
IsBattlerGrounded2(battlerId, FALSE);
}
bool32 IsBattlerAlive(u8 battlerId)
@ -8119,7 +8167,8 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef)
basePower *= 2;
break;
case EFFECT_BOLT_BEAK:
if (GetBattlerTurnOrderNum(battlerAtk) < GetBattlerTurnOrderNum(battlerDef))
if (GetBattlerTurnOrderNum(battlerAtk) < GetBattlerTurnOrderNum(battlerDef)
|| gDisableStructs[battlerDef].isFirstTurn == 2)
basePower *= 2;
break;
case EFFECT_ROUND:
@ -8875,7 +8924,8 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
// check burn
if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && IS_MOVE_PHYSICAL(move)
&& gBattleMoves[move].effect != EFFECT_FACADE && abilityAtk != ABILITY_GUTS)
&& (gBattleMoves[move].effect != EFFECT_FACADE || B_BURN_FACADE_DMG < GEN_6)
&& abilityAtk != ABILITY_GUTS)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
// check sunny/rain weather
@ -8895,7 +8945,7 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
}
// check stab
if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE)
if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE && move != MOVE_NONE)
{
if (abilityAtk == ABILITY_ADAPTABILITY)
MulModifier(&finalModifier, UQ_4_12(2.0));
@ -9125,7 +9175,7 @@ static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 bat
&& gBattleMons[battlerDef].type3 != gBattleMons[battlerDef].type1)
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type3, battlerAtk, recordAbilities);
if (moveType == TYPE_GROUND && !IsBattlerGrounded(battlerDef) && !(gBattleMoves[move].flags & FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING))
if (moveType == TYPE_GROUND && !IsBattlerGrounded2(battlerDef, TRUE) && !(gBattleMoves[move].flags & FLAG_DMG_UNGROUNDED_IGNORE_TYPE_IF_FLYING))
{
modifier = UQ_4_12(0.0);
if (recordAbilities && defAbility == ABILITY_LEVITATE)
@ -9281,8 +9331,20 @@ u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId)
for (i = 0; i < EVOS_PER_MON; i++)
{
if ((gEvolutionTable[preEvoSpecies][i].method == EVO_MEGA_EVOLUTION
|| gEvolutionTable[preEvoSpecies][i].method == EVO_PRIMAL_REVERSION)
if (gEvolutionTable[preEvoSpecies][i].method == EVO_MEGA_EVOLUTION
&& gEvolutionTable[preEvoSpecies][i].param == heldItemId)
return gEvolutionTable[preEvoSpecies][i].targetSpecies;
}
return SPECIES_NONE;
}
u16 GetPrimalReversionSpecies(u16 preEvoSpecies, u16 heldItemId)
{
u32 i;
for (i = 0; i < EVOS_PER_MON; i++)
{
if (gEvolutionTable[preEvoSpecies][i].method == EVO_PRIMAL_REVERSION
&& gEvolutionTable[preEvoSpecies][i].param == heldItemId)
return gEvolutionTable[preEvoSpecies][i].targetSpecies;
}
@ -9323,12 +9385,10 @@ bool32 CanMegaEvolve(u8 battlerId)
// Check if trainer already mega evolved a pokemon.
if (mega->alreadyEvolved[battlerPosition])
return FALSE;
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
if (IsPartnerMonFromSameTrainer(battlerId)
&& (mega->alreadyEvolved[partnerPosition] || (mega->toEvolve & gBitTable[BATTLE_PARTNER(battlerId)])))
return FALSE;
}
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& IsPartnerMonFromSameTrainer(battlerId)
&& (mega->alreadyEvolved[partnerPosition] || (mega->toEvolve & gBitTable[BATTLE_PARTNER(battlerId)])))
return FALSE;
// Check if mon is currently held by Sky Drop
if (gStatuses3[battlerId] & STATUS3_SKY_DROPPED)
@ -9364,14 +9424,6 @@ bool32 CanMegaEvolve(u8 battlerId)
gBattleStruct->mega.isWishMegaEvo = FALSE;
return TRUE;
}
// Can undergo Primal Reversion.
if (holdEffect == HOLD_EFFECT_PRIMAL_ORB)
{
gBattleStruct->mega.isWishMegaEvo = FALSE;
gBattleStruct->mega.isPrimalReversion = TRUE;
return TRUE;
}
}
// Check if there is an entry in the evolution table for Wish Mega Evolution.
@ -9476,9 +9528,8 @@ bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId)
// Mail can be stolen now
if (itemId == ITEM_ENIGMA_BERRY)
return FALSE;
else if (GET_BASE_SPECIES_ID(species) == SPECIES_KYOGRE && itemId == ITEM_BLUE_ORB) // includes primal
return FALSE;
else if (GET_BASE_SPECIES_ID(species) == SPECIES_GROUDON && itemId == ITEM_RED_ORB) // includes primal
// Primal Reversion inducing items cannot be lost if pokemon's base species can undergo primal reversion with it.
else if (holdEffect == HOLD_EFFECT_PRIMAL_ORB && (GetPrimalReversionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE))
return FALSE;
// Mega stone cannot be lost if pokemon's base species can mega evolve with it.
else if (holdEffect == HOLD_EFFECT_MEGA_STONE && (GetMegaEvolutionSpecies(GET_BASE_SPECIES_ID(species), itemId) != SPECIES_NONE))
@ -10064,3 +10115,12 @@ u32 GetBattlerMoveTargetType(u8 battlerId, u16 move)
else
return gBattleMoves[move].target;
}
bool32 CanTargetBattler(u8 battlerAtk, u8 battlerDef, u16 move)
{
if (gBattleMoves[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY
&& GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef)
&& gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK)
return FALSE; // Pokémon affected by Heal Block cannot target allies with Pollen Puff
return TRUE;
}

View File

@ -1188,9 +1188,9 @@ static void SetBerrySpriteData(struct Sprite* sprite, s16 x, s16 y, s16 bounceSp
#undef sXSpeed
#undef sYDownSpeed
static void CreateBerrySprite(u16 a0, u8 playerId)
static void CreateBerrySprite(u16 itemId, u8 playerId)
{
u8 spriteId = CreateSpinningBerrySprite(a0 + FIRST_BERRY_INDEX - 10, 0, 80, playerId & 1);
u8 spriteId = CreateSpinningBerrySprite(ITEM_TO_BERRY(itemId) - 1, 0, 80, playerId & 1);
SetBerrySpriteData(&gSprites[spriteId],
sBerrySpriteData[playerId][0],
sBerrySpriteData[playerId][1],

View File

@ -1451,6 +1451,7 @@ const struct CompressedSpriteSheet gBattleAnimPicTable[] =
{gBattleAnimSpriteGfx_OmegaSymbol, 0x0200, ANIM_TAG_OMEGA_SYMBOL},
{gBattleAnimSpriteGfx_PrimalParticles, 0x0180, ANIM_TAG_PRIMAL_PARTICLES},
{gBattleAnimSpriteGfx_Orbs, 0x0180, ANIM_TAG_STEEL_BEAM},
{gBattleAnimSpriteGfx_AuraSphere, 0x200, ANIM_TAG_POLTERGEIST},
};
const struct CompressedSpritePalette gBattleAnimPaletteTable[] =
@ -1902,6 +1903,7 @@ const struct CompressedSpritePalette gBattleAnimPaletteTable[] =
{gBattleAnimSpritePal_OmegaSymbol, ANIM_TAG_OMEGA_SYMBOL},
{gBattleAnimSpritePal_PrimalParticles, ANIM_TAG_PRIMAL_PARTICLES},
{gBattleAnimSpritePal_SteelBeam, ANIM_TAG_STEEL_BEAM},
{gBattleAnimSpritePal_Poltergeist, ANIM_TAG_POLTERGEIST},
};
const struct BattleAnimBackground gBattleAnimBackgroundTable[] =

File diff suppressed because it is too large Load Diff

View File

@ -11221,7 +11221,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_STEEL_BEAM] =
{
.effect = EFFECT_RECOIL_50,
.effect = EFFECT_STEEL_BEAM,
.power = 140,
.type = TYPE_STEEL,
.accuracy = 95,

View File

@ -79,7 +79,11 @@ static const u8 sFlyDescription[] = _(
static const u8 sBindDescription[] = _(
"Binds and squeezes the foe\n"
#if B_BINDING_TURNS >= GEN_5
"for 4 or 5 turns.");
#else
"for 2 to 5 turns.");
#endif
static const u8 sSlamDescription[] = _(
"Slams the foe with a long\n"
@ -139,7 +143,11 @@ static const u8 sBodySlamDescription[] = _(
static const u8 sWrapDescription[] = _(
"Wraps and squeezes the foe\n"
#if B_BINDING_TURNS >= GEN_5
"4 or 5 times with vines, etc.");
#else
"2 to 5 times with vines, etc.");
#endif
static const u8 sTakeDownDescription[] = _(
"A reckless charge attack\n"
@ -331,7 +339,11 @@ static const u8 sDragonRageDescription[] = _(
static const u8 sFireSpinDescription[] = _(
"Traps the foe in a ring of\n"
#if B_BINDING_TURNS >= GEN_5
"fire for 4 or 5 turns.");
#else
"fire for 2 to 5 turns.");
#endif
static const u8 sThunderShockDescription[] = _(
"An electrical attack that\n"
@ -511,7 +523,11 @@ static const u8 sWaterfallDescription[] = _(
static const u8 sClampDescription[] = _(
"Traps and squeezes the\n"
#if B_BINDING_TURNS >= GEN_5
"foe for 4 or 5 turns.");
#else
"foe for 2 to 5 turns.");
#endif
static const u8 sSwiftDescription[] = _(
"Sprays star-shaped rays\n"
@ -999,7 +1015,11 @@ static const u8 sRockSmashDescription[] = _(
static const u8 sWhirlpoolDescription[] = _(
"Traps and hurts the foe in\n"
#if B_BINDING_TURNS >= GEN_5
"a whirlpool for 4 or 5 turns.");
#else
"a whirlpool for 2 to 5 turns.");
#endif
static const u8 sBeatUpDescription[] = _(
"Summons party Pokémon to\n"
@ -1311,7 +1331,11 @@ static const u8 sSkyUppercutDescription[] = _(
static const u8 sSandTombDescription[] = _(
"Traps and hurts the foe in\n"
#if B_BINDING_TURNS >= GEN_5
"quicksand for 4 or 5 turns.");
#else
"quicksand for 2 to 5 turns.");
#endif
static const u8 sSheerColdDescription[] = _(
"A chilling attack that\n"
@ -1815,7 +1839,11 @@ static const u8 sSpacialRendDescription[] = _(
static const u8 sMagmaStormDescription[] = _(
"Traps the foe in a vortex\n"
#if B_BINDING_TURNS >= GEN_5
"of fire for 4 or 5 turns.");
#else
"of fire for 2 to 5 turns.");
#endif
static const u8 sDarkVoidDescription[] = _(
"Drags the foe into total\n"
@ -2367,7 +2395,11 @@ static const u8 sNuzzleDescription[] = _(
static const u8 sInfestationDescription[] = _(
"The foe is infested and\n"
#if B_BINDING_TURNS >= GEN_5
"attacked for 4 or 5 turns.");
#else
"attacked for 2 to 5 turns.");
#endif
static const u8 sPowerUpPunchDescription[] = _(
"A hard punch that raises\n"
@ -2912,7 +2944,11 @@ static const u8 sSurgingStrikesDescription[] = _(
static const u8 sThunderCageDescription[] = _(
"Traps the foe in a cage of\n"
#if B_BINDING_TURNS >= GEN_5
"electricity for 4 or 5 turns.");
#else
"electricity for 2 to 5 turns.");
#endif
static const u8 sDragonEnergyDescription[] = _(
"The higher the user's HP\n"

View File

@ -57,22 +57,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_WORD_TO_HER, EC_WORD_WIN, EC_WORD_JOKING, EC_WORD_HIGHS, EC_WORD_SCARY, EC_WORD_ELLIPSIS_EXCL },
.speechAfter = { EC_WORD_IGNORANT, EC_WORD_SO, EC_WORD_TODAY, EC_WORD_NIGHTTIME, EC_WORD_YOU_RE, EC_WORD_ELLIPSIS_ELLIPSIS_ELLIPSIS },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_SWALOT,
.heldItem = ITEM_SHELL_BELL,
.moves = { MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_PAIN_SPLIT, MOVE_YAWN },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 55,
.attackEV = 255,
.defenseEV = 100,
.speedEV = 0,
.spAttackEV = 0,
.spDefenseEV = 100,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -82,21 +80,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 1,
.personality = 0x80,
.nickname = __("マルノーム$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_DUSTOX,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_SILVER_WIND, MOVE_SLUDGE_BOMB, MOVE_SHADOW_BALL, MOVE_GIGA_DRAIN },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -106,21 +102,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x6,
.nickname = __("ドクケイル$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_RELICANTH,
.heldItem = ITEM_QUICK_CLAW,
.moves = { MOVE_ANCIENT_POWER, MOVE_SURF, MOVE_EARTHQUAKE, MOVE_AMNESIA },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 100,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 155,
.spDefenseEV = 255,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -130,7 +124,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x2f,
.nickname = __("ジーランス$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -143,22 +137,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_MOVE2(MINIMIZE), EC_WORD_AS_MUCH_AS, EC_EMPTY_WORD, EC_WORD_THEY_RE, EC_WORD_SAD, EC_WORD_EXCL },
.speechAfter = { EC_MOVE(BITE), EC_WORD_AS_MUCH_AS, EC_EMPTY_WORD, EC_WORD_THEY_RE, EC_WORD_ANGRY, EC_WORD_EXCL },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_CACTURNE,
.heldItem = ITEM_QUICK_CLAW,
.moves = { MOVE_GIGA_DRAIN, MOVE_FEINT_ATTACK, MOVE_THUNDER_PUNCH, MOVE_GROWTH },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 55,
.attackEV = 0,
.defenseEV = 100,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 100,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -168,21 +160,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x8c,
.nickname = __("ノクタス$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_SWELLOW,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_FACADE, MOVE_AERIAL_ACE, MOVE_QUICK_ATTACK, MOVE_DOUBLE_TEAM },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 0,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -192,21 +182,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x80,
.nickname = __("オオスバメ$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_WHISCASH,
.heldItem = ITEM_CHESTO_BERRY,
.moves = { MOVE_SURF, MOVE_EARTHQUAKE, MOVE_AMNESIA, MOVE_REST },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -216,7 +204,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x0,
.nickname = __("ナマズン$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -229,22 +217,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_WORD_THAT, EC_WORD_ABOVE, EC_WORD_LOST, EC_WORD_STORES, EC_WORD_JOKING, EC_WORD_ELLIPSIS_ELLIPSIS_ELLIPSIS },
.speechAfter = { EC_WORD_ENTERTAINING, EC_WORD_NONE, EC_WORD_HEY_QUES, EC_WORD_ALMOST, EC_WORD_EXCL, EC_EMPTY_WORD },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_DELCATTY,
.heldItem = ITEM_LUM_BERRY,
.moves = { MOVE_SING, MOVE_BODY_SLAM, MOVE_SHADOW_BALL, MOVE_IRON_TAIL },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 255,
.defenseEV = 0,
.speedEV = 255,
.spAttackEV = 0,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -254,21 +240,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x3,
.nickname = __("エネコロロ$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_ROSELIA,
.heldItem = ITEM_LEFTOVERS,
.moves = { MOVE_GIGA_DRAIN, MOVE_GRASS_WHISTLE, MOVE_TOXIC, MOVE_LEECH_SEED },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -278,21 +262,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 1,
.personality = 0x6,
.nickname = __("ロゼリア$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_BEAUTIFLY,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_SILVER_WIND, MOVE_AERIAL_ACE, MOVE_ATTRACT, MOVE_PSYCHIC },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 100,
.attackEV = 200,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 200,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -302,7 +284,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x6,
.nickname = __("アゲハント$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -315,22 +297,20 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.speechLose = { EC_WORD_OUTSIDE, EC_WORD_UNCLE, EC_WORD_SURPRISE, EC_WORD_THESE, EC_WORD_HEY_QUES, EC_WORD_ELLIPSIS_EXCL },
.speechAfter = { EC_WORD_HE_S, EC_WORD_NO_1, EC_WORD_STRONG, EC_WORD_CHILDREN, EC_WORD_CAN_T, EC_WORD_EXCL_EXCL },
.mons = {
[0] = NULL_BATTLE_TOWER_POKEMON,
[1] = NULL_BATTLE_TOWER_POKEMON,
[2] = NULL_BATTLE_TOWER_POKEMON,
[0] = DUMMY_HILL_MON,
[1] = DUMMY_HILL_MON,
[2] = DUMMY_HILL_MON,
[3] = {
.species = SPECIES_MAWILE,
.heldItem = ITEM_BRIGHT_POWDER,
.moves = { MOVE_CRUNCH, MOVE_FLAMETHROWER, MOVE_THUNDER_PUNCH, MOVE_COMET_PUNCH },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 0,
.attackEV = 0,
.defenseEV = 100,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 155,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -340,21 +320,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 1,
.personality = 0x0,
.nickname = __("クチート$$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[4] = {
.species = SPECIES_SHARPEDO,
.heldItem = ITEM_SCOPE_LENS,
.moves = { MOVE_SURF, MOVE_CRUNCH, MOVE_DOUBLE_EDGE, MOVE_EARTHQUAKE },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -364,21 +342,19 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x96,
.nickname = __("サメハダー$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
[5] = {
.species = SPECIES_BANETTE,
.heldItem = ITEM_LUM_BERRY,
.moves = { MOVE_PSYCHIC, MOVE_SHADOW_BALL, MOVE_THUNDERBOLT, MOVE_WILL_O_WISP },
.level = 0,
.ppBonuses = 0x0,
.hpEV = 255,
.attackEV = 0,
.defenseEV = 0,
.speedEV = 0,
.spAttackEV = 255,
.spDefenseEV = 0,
.otId = 0x10000000,
.otId = TRAINER_HILL_OTID,
.hpIV = 5,
.attackIV = 5,
.defenseIV = 5,
@ -388,7 +364,7 @@ static const struct TrainerHillTrainer sTrainerHillTrainerTemplates_JP[] = {
.abilityNum = 0,
.personality = 0x96,
.nickname = __("ジュペッタ$$$$$$"),
.friendship = 255
.friendship = MAX_FRIENDSHIP
},
}
},
@ -447,40 +423,40 @@ static bool32 ValidateTrainerHillChecksum(struct EReaderTrainerHillSet *hillSet)
return TRUE;
}
static bool32 TryWriteTrainerHill_Internal(struct EReaderTrainerHillSet * hillSet, struct TrHillTag * hillTag)
static bool32 TryWriteTrainerHill_Internal(struct EReaderTrainerHillSet * hillSet, struct TrainerHillChallenge * challenge)
{
int i;
AGB_ASSERT_EX(hillSet->dummy == 0, "cereader_tool.c", 450);
AGB_ASSERT_EX(hillSet->id == 0, "cereader_tool.c", 452);
memset(hillTag, 0, SECTOR_SIZE);
hillTag->numTrainers = hillSet->numTrainers;
hillTag->unused1 = GetTrainerHillUnkVal();
hillTag->numFloors = (hillSet->numTrainers + 1) / TRAINER_HILL_TRAINERS_PER_FLOOR;
memset(challenge, 0, SECTOR_SIZE);
challenge->numTrainers = hillSet->numTrainers;
challenge->unused1 = GetTrainerHillUnkVal();
challenge->numFloors = (hillSet->numTrainers + 1) / HILL_TRAINERS_PER_FLOOR;
for (i = 0; i < hillSet->numTrainers; i++)
{
if (!(i & 1))
{
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainerNum1 = hillSet->trainers[i].trainerNum;
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].display = hillSet->trainers[i].display;
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[0] = hillSet->trainers[i].trainer;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainerNum1 = hillSet->trainers[i].trainerNum;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].map = hillSet->trainers[i].map;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[0] = hillSet->trainers[i].trainer;
}
else
{
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainerNum2 = hillSet->trainers[i].trainerNum;
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[1] = hillSet->trainers[i].trainer;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainerNum2 = hillSet->trainers[i].trainerNum;
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[1] = hillSet->trainers[i].trainer;
}
}
if (i & 1)
{
hillTag->floors[i / TRAINER_HILL_TRAINERS_PER_FLOOR].trainers[1] = sTrainerHillTrainerTemplates_JP[i / TRAINER_HILL_TRAINERS_PER_FLOOR];
challenge->floors[i / HILL_TRAINERS_PER_FLOOR].trainers[1] = sTrainerHillTrainerTemplates_JP[i / HILL_TRAINERS_PER_FLOOR];
}
hillTag->checksum = CalcByteArraySum((u8 *)hillTag->floors, NUM_TRAINER_HILL_FLOORS * sizeof(struct TrHillFloor));
if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_HILL, (u8 *)hillTag) != SAVE_STATUS_OK)
challenge->checksum = CalcByteArraySum((u8 *)challenge->floors, NUM_TRAINER_HILL_FLOORS * sizeof(struct TrainerHillFloor));
if (TryWriteSpecialSaveSector(SECTOR_ID_TRAINER_HILL, (u8 *)challenge) != SAVE_STATUS_OK)
return FALSE;
return TRUE;

View File

@ -269,6 +269,8 @@ const u32 gBattleAnimSpritePal_Steamroller[] = INCBIN_U32("graphics/battle_anims
const u32 gBattleAnimSpriteGfx_StonePillar[] = INCBIN_U32("graphics/battle_anims/sprites/new/stone_pillar.4bpp.lz");
const u32 gBattleAnimSpritePal_StonePillar[] = INCBIN_U32("graphics/battle_anims/sprites/new/stone_pillar.gbapal.lz");
const u32 gBattleAnimSpritePal_Poltergeist[] = INCBIN_U32("graphics/battle_anims/sprites/new/poltergeist.gbapal.lz");
const u32 gBattleAnimSpriteGfx_StraightBeam[] = INCBIN_U32("graphics/battle_anims/sprites/new/straight_beam.4bpp.lz");
const u32 gBattleAnimSpritePal_StraightBeam[] = INCBIN_U32("graphics/battle_anims/sprites/new/straight_beam.gbapal.lz");

View File

@ -31,7 +31,7 @@ void AGBPrintFlush1Block(void);
void AGBPrintInit(void)
{
volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR;
u16 *pWSCNT = &REG_WAITCNT;
vu16 *pWSCNT = &REG_WAITCNT;
u16 *pProtect = (u16 *)AGB_PRINT_PROTECT_ADDR;
u16 nOldWSCNT = *pWSCNT;
*pWSCNT = WSCNT_DATA;
@ -57,7 +57,7 @@ static void AGBPutcInternal(const char cChr)
void AGBPutc(const char cChr)
{
u16 *pWSCNT = &REG_WAITCNT;
vu16 *pWSCNT = &REG_WAITCNT;
u16 nOldWSCNT = *pWSCNT;
volatile struct AGBPrintStruct *pPrint;
*pWSCNT = WSCNT_DATA;
@ -71,7 +71,7 @@ void AGBPutc(const char cChr)
void AGBPrint(const char *pBuf)
{
volatile struct AGBPrintStruct *pPrint = (struct AGBPrintStruct *)AGB_PRINT_STRUCT_ADDR;
u16 *pWSCNT = &REG_WAITCNT;
vu16 *pWSCNT = &REG_WAITCNT;
u16 nOldWSCNT = *pWSCNT;
*pWSCNT = WSCNT_DATA;
while (*pBuf)
@ -95,9 +95,9 @@ void AGBPrintf(const char *pBuf, ...)
static void AGBPrintTransferDataInternal(u32 bAllData)
{
LPFN_PRINT_FLUSH lpfnFuncFlush;
u16 *pIME;
vu16 *pIME;
u16 nIME;
u16 *pWSCNT;
vu16 *pWSCNT;
u16 nOldWSCNT;
u16 *pProtect;
volatile struct AGBPrintStruct *pPrint;

View File

@ -506,9 +506,13 @@ static void IncrementCardStat(u32 statType)
}
if (stat == NULL)
{
AGB_ASSERT(0);
}
else if (++(*stat) > MAX_WONDER_CARD_STAT)
{
*stat = MAX_WONDER_CARD_STAT;
}
}
}

View File

@ -361,7 +361,9 @@ static void (*const gMovementStatusHandler[])(struct LinkPlayerObjectEvent *, st
void DoWhiteOut(void)
{
ScriptContext2_RunNewScript(EventScript_WhiteOut);
#if B_WHITEOUT_MONEY == GEN_3
SetMoney(&gSaveBlock1Ptr->money, GetMoney(&gSaveBlock1Ptr->money) / 2);
#endif
HealPlayerParty();
Overworld_ResetStateAfterWhiteOut();
SetWarpDestinationToLastHealLocation();

View File

@ -6459,6 +6459,9 @@ void SetWildMonHeldItem(void)
for (i = 0; i < count; i++)
{
if (GetMonData(&gEnemyParty[i], MON_DATA_HELD_ITEM, NULL) != ITEM_NONE)
continue; // prevent ovewriting previously set item
rnd = Random() % 100;
species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES, 0);
if (gMapHeader.mapLayoutId == LAYOUT_ALTERING_CAVE)

View File

@ -32,23 +32,21 @@
#include "constants/trainer_hill.h"
#include "constants/trainer_types.h"
#define HILL_TAG_NORMAL 0
#define HILL_TAG_VARIETY 1
#define HILL_TAG_UNIQUE 2
#define HILL_TAG_EXPERT 3
#define HILL_MAX_TIME 215999 // 60 * 60 * 60 - 1
// EWRAM
struct TrHillStruct2
struct FloorTrainers
{
u8 floorId;
struct TrHillTag tag;
struct TrHillFloor floors[NUM_TRAINER_HILL_FLOORS];
u8 name[HILL_TRAINERS_PER_FLOOR][HILL_TRAINER_NAME_LENGTH];
u8 facilityClass[HILL_TRAINERS_PER_FLOOR];
};
static EWRAM_DATA struct TrHillStruct2 *sHillData = NULL;
static EWRAM_DATA struct TrHillRoomTrainers *sRoomTrainers = NULL;
static EWRAM_DATA struct {
u8 floorId;
struct TrainerHillChallenge challenge;
struct TrainerHillFloor floors[NUM_TRAINER_HILL_FLOORS];
} *sHillData = NULL;
static EWRAM_DATA struct FloorTrainers *sFloorTrainers = NULL;
EWRAM_DATA u32 *gTrainerHillVBlankCounter = NULL;
// This file's functions.
@ -69,7 +67,7 @@ static void GetGameSaved(void);
static void SetGameSaved(void);
static void ClearGameSaved(void);
static void GetChallengeWon(void);
static void TrainerHillSetTag(void);
static void TrainerHillSetMode(void);
static void SetUpDataStruct(void);
static void FreeDataStruct(void);
static void TrainerHillDummy(void);
@ -202,12 +200,12 @@ static const u16 *const *const sPrizeListSets[] =
static const u16 sEReader_Pal[] = INCBIN_U16("graphics/trainer_hill/ereader.gbapal");
static const u8 sRecordWinColors[] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY};
static const struct TrHillTag *const sDataPerTag[] =
static const struct TrainerHillChallenge *const sChallengeData[NUM_TRAINER_HILL_MODES] =
{
&sDataTagNormal,
&sDataTagVariety,
&sDataTagUnique,
&sDataTagExpert,
[HILL_MODE_NORMAL] = &sChallenge_Normal,
[HILL_MODE_VARIETY] = &sChallenge_Variety,
[HILL_MODE_UNIQUE] = &sChallenge_Unique,
[HILL_MODE_EXPERT] = &sChallenge_Expert,
};
// Unused.
@ -238,15 +236,15 @@ static void (* const sHillFunctions[])(void) =
[TRAINER_HILL_FUNC_SET_GAME_SAVED] = SetGameSaved,
[TRAINER_HILL_FUNC_CLEAR_GAME_SAVED] = ClearGameSaved,
[TRAINER_HILL_FUNC_GET_WON] = GetChallengeWon,
[TRAINER_HILL_FUNC_SET_TAG] = TrainerHillSetTag,
[TRAINER_HILL_FUNC_SET_MODE] = TrainerHillSetMode,
};
static const u8 *const sTagMatchStrings[] =
static const u8 *const sModeStrings[NUM_TRAINER_HILL_MODES] =
{
gText_NormalTagMatch,
gText_VarietyTagMatch,
gText_UniqueTagMatch,
gText_ExpertTagMatch,
[HILL_MODE_NORMAL] = gText_NormalTagMatch,
[HILL_MODE_VARIETY] = gText_VarietyTagMatch,
[HILL_MODE_UNIQUE] = gText_UniqueTagMatch,
[HILL_MODE_EXPERT] = gText_ExpertTagMatch,
};
static const struct ObjectEventTemplate sTrainerObjectEventTemplate =
@ -261,18 +259,17 @@ static const struct ObjectEventTemplate sTrainerObjectEventTemplate =
static const u32 sNextFloorMapNum[NUM_TRAINER_HILL_FLOORS] =
{
MAP_NUM(TRAINER_HILL_2F),
MAP_NUM(TRAINER_HILL_3F),
MAP_NUM(TRAINER_HILL_4F),
MAP_NUM(TRAINER_HILL_ROOF)
[TRAINER_HILL_1F - 1] = MAP_NUM(TRAINER_HILL_2F),
[TRAINER_HILL_2F - 1] = MAP_NUM(TRAINER_HILL_3F),
[TRAINER_HILL_3F - 1] = MAP_NUM(TRAINER_HILL_4F),
[TRAINER_HILL_4F - 1] = MAP_NUM(TRAINER_HILL_ROOF)
};
static const u8 sTrainerPartySlots[][PARTY_SIZE / 2] =
static const u8 sTrainerPartySlots[HILL_TRAINERS_PER_FLOOR][PARTY_SIZE / 2] =
{
{0, 1, 2},
{3, 4, 5}
};
// code
void CallTrainerHillFunction(void)
{
SetUpDataStruct();
@ -287,7 +284,7 @@ void ResetTrainerHillResults(void)
gSaveBlock2Ptr->frontier.savedGame = 0;
gSaveBlock2Ptr->frontier.unk_EF9 = 0;
gSaveBlock1Ptr->trainerHill.bestTime = 0;
for (i = 0; i < 4; i++)
for (i = 0; i < NUM_TRAINER_HILL_MODES; i++)
SetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i], HILL_MAX_TIME);
}
@ -300,7 +297,7 @@ u8 GetTrainerHillOpponentClass(u16 trainerId)
{
u8 id = trainerId - 1;
return gFacilityClassToTrainerClass[sRoomTrainers->facilityClass[id]];
return gFacilityClassToTrainerClass[sFloorTrainers->facilityClass[id]];
}
void GetTrainerHillTrainerName(u8 *dst, u16 trainerId)
@ -309,7 +306,7 @@ void GetTrainerHillTrainerName(u8 *dst, u16 trainerId)
u8 id = trainerId - 1;
for (i = 0; i < HILL_TRAINER_NAME_LENGTH; i++)
dst[i] = sRoomTrainers->name[id][i];
dst[i] = sFloorTrainers->name[id][i];
}
u8 GetTrainerHillTrainerFrontSpriteId(u16 trainerId)
@ -329,15 +326,14 @@ void InitTrainerHillBattleStruct(void)
s32 i, j;
SetUpDataStruct();
sRoomTrainers = AllocZeroed(sizeof(*sRoomTrainers));
sFloorTrainers = AllocZeroed(sizeof(*sFloorTrainers));
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
for (j = 0; j < HILL_TRAINER_NAME_LENGTH; j++)
{
sRoomTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j];
}
sRoomTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass;
sFloorTrainers->name[i][j] = sHillData->floors[sHillData->floorId].trainers[i].name[j];
sFloorTrainers->facilityClass[i] = sHillData->floors[sHillData->floorId].trainers[i].facilityClass;
}
SetTrainerHillVBlankCounter(&gSaveBlock1Ptr->trainerHill.timer);
FreeDataStruct();
@ -345,8 +341,7 @@ void InitTrainerHillBattleStruct(void)
void FreeTrainerHillBattleStruct(void)
{
if (sRoomTrainers != NULL)
FREE_AND_SET_NULL(sRoomTrainers);
TRY_FREE_AND_SET_NULL(sFloorTrainers);
}
static void SetUpDataStruct(void)
@ -355,15 +350,20 @@ static void SetUpDataStruct(void)
{
sHillData = AllocZeroed(sizeof(*sHillData));
sHillData->floorId = gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F;
CpuCopy32(sDataPerTag[gSaveBlock1Ptr->trainerHill.tag], &sHillData->tag, sizeof(sHillData->tag) + 4 * sizeof(struct TrHillFloor));
// This copy depends on the floor data for each challenge being directly after the
// challenge header data, and for the field 'floors' in sHillData to come directly
// after the field 'challenge'.
// e.g. for HILL_MODE_NORMAL, it will copy sChallenge_Normal to sHillData->challenge and
// it will copy sFloors_Normal to sHillData->floors
CpuCopy32(sChallengeData[gSaveBlock1Ptr->trainerHill.mode], &sHillData->challenge, sizeof(sHillData->challenge) + sizeof(sHillData->floors));
TrainerHillDummy();
}
}
static void FreeDataStruct(void)
{
if (sHillData != NULL)
FREE_AND_SET_NULL(sHillData);
TRY_FREE_AND_SET_NULL(sHillData);
}
void CopyTrainerHillTrainerText(u8 which, u16 trainerId)
@ -428,7 +428,7 @@ static void GiveChallengePrize(void)
{
u16 itemId = GetPrizeItemId();
if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize)
if (sHillData->challenge.numFloors != NUM_TRAINER_HILL_FLOORS || gSaveBlock1Ptr->trainerHill.receivedPrize)
{
gSpecialVar_Result = 2;
}
@ -456,7 +456,7 @@ static void CheckFinalTime(void)
else if (GetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime) > gSaveBlock1Ptr->trainerHill.timer)
{
SetTimerValue(&gSaveBlock1Ptr->trainerHill.bestTime, gSaveBlock1Ptr->trainerHill.timer);
gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.tag] = gSaveBlock1Ptr->trainerHill.bestTime;
gSaveBlock1Ptr->trainerHillTimes[gSaveBlock1Ptr->trainerHill.mode] = gSaveBlock1Ptr->trainerHill.bestTime;
gSpecialVar_Result = 0;
}
else
@ -529,9 +529,9 @@ static void BufferChallengeTime(void)
static void GetAllFloorsUsed(void)
{
SetUpDataStruct();
if (sHillData->tag.numFloors != NUM_TRAINER_HILL_FLOORS)
if (sHillData->challenge.numFloors != NUM_TRAINER_HILL_FLOORS)
{
ConvertIntToDecimalStringN(gStringVar1, sHillData->tag.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1);
ConvertIntToDecimalStringN(gStringVar1, sHillData->challenge.numFloors, STR_CONV_MODE_LEFT_ALIGN, 1);
gSpecialVar_Result = FALSE;
}
else
@ -592,9 +592,9 @@ void PrintOnTrainerHillRecordsWindow(void)
AddTextPrinterParameterized3(0, FONT_NORMAL, x, 2, sRecordWinColors, TEXT_SKIP_DRAW, gText_TimeBoard);
y = 18;
for (i = 0; i < 4; i++)
for (i = 0; i < NUM_TRAINER_HILL_MODES; i++)
{
AddTextPrinterParameterized3(0, FONT_NORMAL, 0, y, sRecordWinColors, TEXT_SKIP_DRAW, sTagMatchStrings[i]);
AddTextPrinterParameterized3(0, FONT_NORMAL, 0, y, sRecordWinColors, TEXT_SKIP_DRAW, sModeStrings[i]);
y += 15;
total = GetTimerValue(&gSaveBlock1Ptr->trainerHillTimes[i]);
minutes = total / (60 * 60);
@ -637,23 +637,23 @@ void LoadTrainerHillObjectEventTemplates(void)
return;
SetUpDataStruct();
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
gSaveBlock2Ptr->frontier.trainerIds[i] = 0xFFFF;
CpuFill32(0, gSaveBlock1Ptr->objectEventTemplates, sizeof(gSaveBlock1Ptr->objectEventTemplates));
floorId = GetFloorId();
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
u8 bits;
eventTemplates[i] = sTrainerObjectEventTemplate;
eventTemplates[i].localId = i + 1;
eventTemplates[i].graphicsId = FacilityClassToGraphicsId(sHillData->floors[floorId].trainers[i].facilityClass);
eventTemplates[i].x = sHillData->floors[floorId].display.coords[i] & 0xF;
eventTemplates[i].y = ((sHillData->floors[floorId].display.coords[i] >> 4) & 0xF) + 5;
eventTemplates[i].x = sHillData->floors[floorId].map.trainerCoords[i] & 0xF;
eventTemplates[i].y = ((sHillData->floors[floorId].map.trainerCoords[i] >> 4) & 0xF) + 5;
bits = i << 2;
eventTemplates[i].movementType = ((sHillData->floors[floorId].display.direction >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP;
eventTemplates[i].trainerRange_berryTreeId = (sHillData->floors[floorId].display.range >> bits) & 0xF;
eventTemplates[i].movementType = ((sHillData->floors[floorId].map.trainerDirections >> bits) & 0xF) + MOVEMENT_TYPE_FACE_UP;
eventTemplates[i].trainerRange_berryTreeId = (sHillData->floors[floorId].map.trainerRanges >> bits) & 0xF;
eventTemplates[i].script = TrainerHill_EventScript_TrainerBattle;
gSaveBlock2Ptr->frontier.trainerIds[i] = i + 1;
}
@ -669,14 +669,14 @@ bool32 LoadTrainerHillFloorObjectEventScripts(void)
return TRUE;
}
static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride is always 16
static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 floorWidth) // floorWidth is always 16
{
bool8 impassable;
u16 metatile;
u16 elevation;
impassable = (sHillData->floors[floorId].display.collisionData[y] >> (15 - x) & 1);
metatile = sHillData->floors[floorId].display.metatileData[stride * y + x] + NUM_METATILES_IN_PRIMARY;
impassable = (sHillData->floors[floorId].map.collisionData[y] >> (15 - x) & 1);
metatile = sHillData->floors[floorId].map.metatileData[floorWidth * y + x] + NUM_METATILES_IN_PRIMARY;
elevation = 3 << MAPGRID_ELEVATION_SHIFT;
return ((impassable << MAPGRID_COLLISION_SHIFT) & MAPGRID_COLLISION_MASK) | elevation | (metatile & MAPGRID_METATILE_ID_MASK);
@ -684,7 +684,7 @@ static u16 GetMetatileForFloor(u8 floorId, u32 x, u32 y, u32 stride) // stride i
void GenerateTrainerHillFloorLayout(u16 *mapArg)
{
s32 i, j;
s32 y, x;
u16 *src, *dst;
u8 mapId = GetCurrentTrainerHillMapId();
@ -705,24 +705,25 @@ void GenerateTrainerHillFloorLayout(u16 *mapArg)
mapId = GetFloorId();
src = gMapHeader.mapLayout->map;
gBackupMapLayout.map = mapArg;
gBackupMapLayout.width = 31;
gBackupMapLayout.height = 35;
// Dimensions include border area loaded beyond map
gBackupMapLayout.width = HILL_FLOOR_WIDTH + 15;
gBackupMapLayout.height = HILL_FLOOR_HEIGHT + 14;
dst = mapArg + 224;
// First 5 rows of the map (Entrance / Exit) are always the same
for (i = 0; i < 5; i++)
for (y = 0; y < HILL_FLOOR_HEIGHT_MARGIN; y++)
{
for (j = 0; j < 16; j++)
dst[j] = src[j];
for (x = 0; x < HILL_FLOOR_WIDTH; x++)
dst[x] = src[x];
dst += 31;
src += 16;
}
// Load the 16x16 floor-specific layout
for (i = 0; i < 16; i++)
for (y = 0; y < HILL_FLOOR_HEIGHT_MAIN; y++)
{
for (j = 0; j < 16; j++)
dst[j] = GetMetatileForFloor(mapId, j, i, 16);
for (x = 0; x < HILL_FLOOR_WIDTH; x++)
dst[x] = GetMetatileForFloor(mapId, x, y, HILL_FLOOR_WIDTH);
dst += 31;
}
@ -812,8 +813,8 @@ u16 LocalIdToHillTrainerId(u8 localId)
bool8 GetHillTrainerFlag(u8 objectEventId)
{
u32 floorId = GetFloorId() * 2;
u8 bitId = gObjectEvents[objectEventId].localId - 1 + floorId;
u32 trainerIndexStart = GetFloorId() * HILL_TRAINERS_PER_FLOOR;
u8 bitId = gObjectEvents[objectEventId].localId - 1 + trainerIndexStart;
return gSaveBlock2Ptr->frontier.trainerFlags & gBitTable[bitId];
}
@ -821,24 +822,24 @@ bool8 GetHillTrainerFlag(u8 objectEventId)
void SetHillTrainerFlag(void)
{
u8 i;
u8 floorId = GetFloorId() * 2;
u8 trainerIndexStart = GetFloorId() * HILL_TRAINERS_PER_FLOOR;
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_A)
{
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i];
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[trainerIndexStart + i];
break;
}
}
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
{
for (i = 0; i < 2; i++)
for (i = 0; i < HILL_TRAINERS_PER_FLOOR; i++)
{
if (gSaveBlock2Ptr->frontier.trainerIds[i] == gTrainerBattleOpponent_B)
{
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[floorId + i];
gSaveBlock2Ptr->frontier.trainerFlags |= gBitTable[trainerIndexStart + i];
break;
}
}
@ -861,14 +862,14 @@ static void CreateNPCTrainerHillParty(u16 trainerId, u8 firstMonId)
u8 trId, level;
s32 i, floorId, partySlot;
if (trainerId == 0 || trainerId > 2)
if (trainerId == 0 || trainerId > HILL_TRAINERS_PER_FLOOR)
return;
trId = trainerId - 1;
SetUpDataStruct();
level = GetHighestLevelInPlayerParty();
floorId = GetFloorId();
for (i = firstMonId, partySlot = 0; i < firstMonId + 3; i++, partySlot++)
for (i = firstMonId, partySlot = 0; i < firstMonId + PARTY_SIZE / 2; i++, partySlot++)
{
u8 id = sTrainerPartySlots[trId][partySlot];
struct Pokemon *mon = &gEnemyParty[i];
@ -890,7 +891,7 @@ void FillHillTrainersParties(void)
{
ZeroEnemyPartyMons();
CreateNPCTrainerHillParty(gTrainerBattleOpponent_A, 0);
CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, 3);
CreateNPCTrainerHillParty(gTrainerBattleOpponent_B, PARTY_SIZE / 2);
}
// This function is unused, but my best guess is
@ -935,7 +936,7 @@ u8 GetNumFloorsInTrainerHillChallenge(void)
u8 floors;
SetUpDataStruct();
floors = sHillData->tag.numFloors;
floors = sHillData->challenge.numFloors;
FreeDataStruct();
return floors;
@ -989,16 +990,20 @@ static void GetChallengeWon(void)
gSpecialVar_Result = TRUE;
}
static void TrainerHillSetTag(void)
static void TrainerHillSetMode(void)
{
gSaveBlock1Ptr->trainerHill.tag = gSpecialVar_0x8005;
gSaveBlock1Ptr->trainerHill.mode = gSpecialVar_0x8005;
gSaveBlock1Ptr->trainerHill.bestTime = gSaveBlock1Ptr->trainerHillTimes[gSpecialVar_0x8005];
}
static u8 GetPrizeListId(bool8 maxTrainers)
// Determines which prize list to use from the set of prize lists.
static u8 GetPrizeListId(bool8 allowTMs)
{
u8 prizeListId, i, modBy;
// The initial selection depends on the trainer numbers for the completed challenge.
// These don't change with the available challenge modes, so Normal/Unique will always
// have a prizeListId of 8, and Variety/Expert will have a prizeListId of 24.
prizeListId = 0;
for (i = 0; i < NUM_TRAINER_HILL_FLOORS; i++)
{
@ -1006,8 +1011,10 @@ static u8 GetPrizeListId(bool8 maxTrainers)
prizeListId ^= sHillData->floors[i].trainerNum2 & 0x1F;
}
// Not possible to win TMs with fewer than 8 trainers
if (maxTrainers)
// In practice, the conditional below is always true.
// The 2nd half of the lists in both sets of lists all have a TM as the "grand prize", while the 1st half do not,
// so taking the mod of the (total / 2) ensures that a prize list without a TM will be used.
if (allowTMs)
modBy = NUM_TRAINER_HILL_PRIZE_LISTS;
else
modBy = NUM_TRAINER_HILL_PRIZE_LISTS / 2;
@ -1020,38 +1027,64 @@ static u16 GetPrizeItemId(void)
{
u8 i;
const u16 *prizeList;
s32 var = 0, prizeListSetId, minutes, id;
s32 trainerNumSum = 0, prizeListSetId, minutes, id;
// First determine which set of prize lists to use. The sets of lists only differ in
// what TMs they can offer as the "grand prize" for a time under 12 minutes.
// Which set of lists gets used is based on the sum of all the trainer numbers for that
// challenge. These don't change with the available challenge modes, so Normal will always
// have a prizeListSetId of 0, and Unique/Variety/Expert will have a prizeListSetId of 1.
for (i = 0; i < NUM_TRAINER_HILL_FLOORS; i++)
{
var += sHillData->floors[i].trainerNum1;
var += sHillData->floors[i].trainerNum2;
trainerNumSum += sHillData->floors[i].trainerNum1;
trainerNumSum += sHillData->floors[i].trainerNum2;
}
prizeListSetId = trainerNumSum / 256;
prizeListSetId %= (int)ARRAY_COUNT(sPrizeListSets);
prizeListSetId = var / 256;
prizeListSetId %= 2;
if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->tag.numTrainers == NUM_TRAINER_HILL_TRAINERS)
// Now get which prize list to use from the set. See GetPrizeListId for details.
// The below conditional will always be true, because a Trainer Hill challenge can't be entered
// until the player has entered the Hall of Fame (FLAG_SYS_GAME_CLEAR is set) and because all
// of the available challenge modes have the full 8 trainers (NUM_TRAINER_HILL_TRAINERS).
if (FlagGet(FLAG_SYS_GAME_CLEAR) && sHillData->challenge.numTrainers == NUM_TRAINER_HILL_TRAINERS)
i = GetPrizeListId(TRUE);
else
i = GetPrizeListId(FALSE);
if (gSaveBlock1Ptr->trainerHill.tag == HILL_TAG_EXPERT)
// 1 is added to Expert mode's prize list selection because otherwise it has the same prizes as Variety
if (gSaveBlock1Ptr->trainerHill.mode == HILL_MODE_EXPERT)
i = (i + 1) % NUM_TRAINER_HILL_PRIZE_LISTS;
// After the above (non-random) calculations, the following are the possible prize list selections:
// sPrizeListSets[0][8] (Normal)
// sPrizeListSets[1][4] (Variety)
// sPrizeListSets[1][8] (Unique)
// sPrizeListSets[1][5] (Expert)
prizeList = sPrizeListSets[prizeListSetId][i];
// Which prize is given from the list depends on the time scored.
// The prize for any time after 12 minutes is the same in every list.
// The prizes for a time under 12 minutes are:
// - ITEM_TM11_SUNNY_DAY (Normal)
// - ITEM_ELIXIR (Variety)
// - ITEM_TM19_GIGA_DRAIN (Unique)
// - ITEM_TM31_BRICK_BREAK (Expert)
// As an additional note, if players were allowed to enter a Trainer Hill challenge before
// entering the Hall of Fame, there would be 1 additional prize possibility (ITEM_MAX_ETHER)
// as Normal / Unique modes would use sPrizeListSets[0][3] / sPrizeListSets[1][3] respectively.
minutes = (signed)(gSaveBlock1Ptr->trainerHill.timer) / (60 * 60);
if (minutes < 12)
id = 0;
id = 0; // Depends on list
else if (minutes < 13)
id = 1;
id = 1; // ITEM_ETHER
else if (minutes < 14)
id = 2;
id = 2; // ITEM_MAX_POTION
else if (minutes < 16)
id = 3;
id = 3; // ITEM_REVIVE
else if (minutes < 18)
id = 4;
id = 4; // ITEM_FLUFFY_TAIL
else
id = 5;
id = 5; // ITEM_GREAT_BALL
return prizeList[id];
}

View File

@ -1,8 +1,10 @@
CC = gcc
CFLAGS = -Wall -Wextra -Werror -Wno-sign-compare -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK
CFLAGS += $(shell pkg-config --cflags libpng)
LIBS = -lpng -lz
LDFLAGS += $(shell pkg-config --libs-only-L libpng)
SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c rl.c util.c font.c huff.c

View File

@ -1,8 +1,10 @@
CC ?= gcc
CFLAGS = -Wall -Wextra -Werror -std=c11 -O2 -DPNG_SKIP_SETJMP_CHECK
CFLAGS += $(shell pkg-config --cflags libpng)
LIBS = -lpng -lz
LDFLAGS += $(shell pkg-config --libs-only-L libpng)
SRCS = main.c convert_png.c util.c font.c