merge w be

This commit is contained in:
ghoulslash 2022-07-17 12:40:43 -04:00
commit 6b84a9f0b3
124 changed files with 4127 additions and 3716 deletions

View File

@ -305,6 +305,20 @@ Then proceed to [Choosing where to store pokeemerald (Linux)](#choosing-where-to
> then you will have to install devkitARM. Install all the above packages except binutils-arm-none-eabi, and follow the instructions to
> [install devkitARM on Debian/Ubuntu-based distributions](#installing-devkitarm-on-debianubuntu-based-distributions).
</details>
### Arch Linux
Run this command as root to install the necessary packages:
```bash
pacman -S base-devel arm-none-eabi-binutils git libpng
```
Then proceed to [Choosing where to store pokeemerald (Linux)](#choosing-where-to-store-pokeemerald-linux).
<details>
<summary><i>Note for legacy repos...</i></summary>
> If the repository you plan to build has an **[older revision of the INSTALL.md](https://github.com/pret/pokeemerald/blob/571c598/INSTALL.md)**,
> then you will have to install devkitARM. Install all the above packages except binutils-arm-none-eabi, and follow the instructions to
> [install devkitARM on Arch Linux](#installing-devkitarm-on-arch-linux).
</details>
### Other distributions
_(Specific instructions for other distributions would be greatly appreciated!)_
@ -437,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:
@ -520,7 +527,25 @@ devkitARM is now installed.
devkitARM is now installed.
## Other toolchains
### 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.
```console
pacman -S gba-dev
```
This will ask for the selection of packages to install. Just press Enter to install all of them, followed by entering Y to proceed with the installation.
3. Run the following command to set devkitPro related environment variables (alternatively, close and re-open the Terminal):
```bash
source /etc/profile.d/devkit-env.sh
```
devkitARM is now installed.
### 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
@ -532,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

@ -1936,6 +1936,50 @@
various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK
.endm
.macro jumpifcantfling battler:req, ptr:req
various \battler, VARIOUS_JUMP_IF_CANT_FLING
.4byte \ptr
.endm
.macro curecertainstatuses battler:req
various \battler, VARIOUS_CURE_CERTAIN_STATUSES
.endm
.macro tryresetnegativestatstages battler:req
various \battler, VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES
.endm
.macro jumpiflastuseditemberry ptr:req
various BS_ATTACKER, VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY
.4byte \ptr
.endm
.macro jumpiflastuseditemholdeffect battler:req, holdEffect:req, ptr:req
various \battler, VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT
.byte \holdEffect
.4byte \ptr
.endm
.macro savebattleritem battler:req
various \battler, VARIOUS_SAVE_BATTLER_ITEM
.endm
.macro restorebattleritem battler:req
various \battler, VARIOUS_RESTORE_BATTLER_ITEM
.endm
.macro battleritemtolastuseditem battler:req
various \battler, VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM
.endm
.macro setbeakblast battler:req
various \battler, VARIOUS_SET_BEAK_BLAST
.endm
.macro swapsidestatuses
various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES
.endm
@ helpful macros
.macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER, \stat | \stages << 3 | \down << 7

View File

@ -828,10 +828,10 @@
.endm
@ Sets the movement type (MOVEMENT_TYPE_*) for an object's template.
.macro setobjectmovementtype word:req, byte:req
.macro setobjectmovementtype localId:req, movementType:req
.byte 0x65
.2byte \word
.byte \byte
.2byte \localId
.byte \movementType
.endm
@ If a standard message box (or its text) is being drawn on-screen, this command blocks script execution until the
@ -1457,48 +1457,48 @@
.endm
@ Equivalent to goto using the relative address set by setvaddress.
.macro vgoto pointer:req
.macro vgoto destination:req
.byte 0xb9
.4byte \pointer
.4byte \destination
.endm
@ Equivalent to call using the relative address set by setvaddress.
.macro vcall pointer:req
.macro vcall destination:req
.byte 0xba
.4byte \pointer
.4byte \destination
.endm
@ Equivalent to goto_if using the relative address set by setvaddress.
.macro vgoto_if byte:req, pointer:req
.macro vgoto_if condition:req, destination:req
.byte 0xbb
.byte \byte
.4byte \pointer
.byte \condition
.4byte \destination
.endm
@ Equivalent to call_if using the relative address set by setvaddress.
.macro vcall_if byte:req, pointer:req
.macro vcall_if condition:req, destination:req
.byte 0xbc
.byte \byte
.4byte \pointer
.byte \condition
.4byte \destination
.endm
@ Equivalent to message using the relative address set by setvaddress.
.macro vmessage pointer:req
.macro vmessage text:req
.byte 0xbd
.4byte \pointer
.4byte \text
.endm
@ Expands the given text at the pointer (- the relative address set by setvaddress) into gStringVar4
.macro vbuffermessage ptr:req
.macro vbuffermessage text:req
.byte 0xbe
.4byte \ptr
.4byte \text
.endm
@ Equivalent to bufferstring using the relative address set by setvaddress.
.macro vbufferstring stringVarIndex:req, pointer:req
.macro vbufferstring stringVarIndex:req, text:req
.byte 0xbf
stringvar \stringVarIndex
.4byte \pointer
.4byte \text
.endm
@ Create a window showing how many Coins the player has.
@ -1555,9 +1555,9 @@
.endm
@ Used only in FireRed/LeafGreen, does nothing in Emerald.
.macro loadhelp pointer:req
.macro loadhelp text:req
.byte 0xc8
.4byte \pointer
.4byte \text
.endm
@ Used only in FireRed/LeafGreen, does nothing in Emerald.

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

@ -866,6 +866,8 @@ gBattleAnims_General::
.4byte General_StrongWinds @ B_ANIM_STRONG_WINDS
.4byte General_PrimalReversion @ B_ANIM_PRIMAL_REVERSION
.4byte General_AquaRingHeal @ B_ANIM_AQUA_RING_HEAL
.4byte General_BeakBlastSetUp @ B_ANIM_BEAK_BLAST_SETUP
.4byte General_ShellTrapSetUp @ B_ANIM_SHELL_TRAP_SETUP
.4byte General_ZMoveActivate @ B_ANIM_ZMOVE_ACTIVATE
.align 2
@ -11773,7 +11775,7 @@ Move_INSTRUCT::
blendoff
end
Move_BEAK_BLAST::
General_BeakBlastSetUp:
loadspritegfx ANIM_TAG_SMALL_EMBER @Fire
playsewithpan SE_M_DRAGON_RAGE, SOUND_PAN_ATTACKER
delay 0x3
@ -11781,7 +11783,7 @@ Move_BEAK_BLAST::
launchtemplate gFireSpiralOutwardSpriteTemplate 0x3 0x4 0x0 0x0 0x38 0x0
waitforvisualfinish
end
BeakBlastUnleash:
Move_BEAK_BLAST::
loadspritegfx ANIM_TAG_IMPACT
launchtask AnimTask_BlendBattleAnimPal 0xA 0x5 ANIM_PAL_ATK 0x2 0x0 0x9 0x1F
waitforvisualfinish
@ -11930,8 +11932,7 @@ Move_AURORA_VEIL::
blendoff
end
Move_SHELL_TRAP::
ShellTrapChargeUp:
General_ShellTrapSetUp:
loadspritegfx ANIM_TAG_SMALL_EMBER
loadspritegfx ANIM_TAG_IMPACT
monbg ANIM_TARGET
@ -11948,6 +11949,7 @@ ShellTrapChargeUp:
clearmonbg ANIM_TARGET
blendoff
end
Move_SHELL_TRAP::
ShellTrapUnleash:
loadspritegfx ANIM_TAG_IMPACT @pound
loadspritegfx ANIM_TAG_SMALL_RED_EYE @red
@ -13643,8 +13645,8 @@ Move_DRUM_BEATING::
blendoff
end
Move_SNAP_TRAP::
end @ to do:
Move_SNAP_TRAP:: @ placeholder
goto Move_BITE
Move_PYRO_BALL::
loadspritegfx ANIM_TAG_FLAT_ROCK
@ -14116,8 +14118,8 @@ Move_SHELL_SIDE_ARM_SPECIAL: @ Modified Snipe Shot, placeholder
loadspritegfx ANIM_TAG_LEER
createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT_2, 0, 6, 6, RGB_MAGENTA
createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_LEER, 0, 6, 6, RGB_MAGENTA
launchtemplate gLeerSpriteTemplate 0x82, 2 0x18 -12
playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER
launchtemplate gLeerSpriteTemplate 0x82, 2 0x18 -12
waitforvisualfinish
delay 0x20
playsewithpan SE_M_GIGA_DRAIN, SOUND_PAN_TARGET
@ -14229,7 +14231,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:
@ -24252,6 +24289,7 @@ General_TurnTrap:
jumpargeq 0, TRAP_ANIM_SAND_TOMB, Status_SandTomb
jumpargeq 0, TRAP_ANIM_MAGMA_STORM, Status_MagmaStorm
jumpargeq 0, TRAP_ANIM_INFESTATION, Status_Infestation
jumpargeq 0, TRAP_ANIM_SNAP_TRAP, Status_Snap_Trap
goto Status_BindWrap
Status_BindWrap:
loadspritegfx ANIM_TAG_TENDRILS
@ -24338,6 +24376,9 @@ Status_Clamp:
waitforvisualfinish
end
Status_Snap_Trap: @ placeholder
goto Move_BITE
Status_SandTomb:
loadspritegfx ANIM_TAG_MUD_SAND
createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 0, 4, 2, 0, 7, RGB(19, 17, 0)

View File

@ -235,7 +235,7 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectDragonDance @ EFFECT_DRAGON_DANCE
.4byte BattleScript_EffectCamouflage @ EFFECT_CAMOUFLAGE
.4byte BattleScript_EffectHit @ EFFECT_PLEDGE
.4byte BattleScript_EffectHit @ EFFECT_FLING
.4byte BattleScript_EffectFling @ EFFECT_FLING
.4byte BattleScript_EffectNaturalGift @ EFFECT_NATURAL_GIFT
.4byte BattleScript_EffectWakeUpSlap @ EFFECT_WAKE_UP_SLAP
.4byte BattleScript_EffectHit @ EFFECT_WRING_OUT
@ -404,9 +404,166 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectClangorousSoul @ EFFECT_CLANGOROUS_SOUL
.4byte BattleScript_EffectHit @ EFFECT_BOLT_BEAK
.4byte BattleScript_EffectSkyDrop @ EFFECT_SKY_DROP
.4byte BattleScript_EffectHit @ EFFECT_EXPANDING_FORCE
.4byte BattleScript_EffectScaleShot @ EFFECT_SCALE_SHOT
.4byte BattleScript_EffectMeteorBeam @ EFFECT_METEOR_BEAM
.4byte BattleScript_EffectHit @ EFFECT_RISING_VOLTAGE
.4byte BattleScript_EffectHit @ EFFECT_BEAK_BLAST
.4byte BattleScript_EffectCourtChange @ EFFECT_COURT_CHANGE
.4byte BattleScript_EffectSteelBeam @ EFFECT_STEEL_BEAM
.4byte BattleScript_EffectExtremeEvoboost @ EFFECT_EXTREME_EVOBOOST
.4byte BattleScript_EffectTerrainHit @ EFFECT_DAMAGE_SET_TERRAIN
.4byte BattleScript_EffectHit @ NUM_BATTLE_MOVE_EFFECTS
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
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
swapsidestatuses
attackanimation
waitanimation
printstring STRINGID_COURTCHANGE
waitmessage 0x40
goto BattleScript_MoveEnd
BattleScript_BeakBlastSetUp::
setbeakblast BS_ATTACKER
printstring STRINGID_EMPTYSTRING3
waitmessage 0x1
playanimation BS_ATTACKER, B_ANIM_BEAK_BLAST_SETUP, NULL
printstring STRINGID_HEATUPBEAK
waitmessage 0x40
end2
BattleScript_BeakBlastBurn::
setbyte cMULTISTRING_CHOOSER, 0
copybyte gEffectBattler, gBattlerAttacker
call BattleScript_MoveEffectBurn
return
BattleScript_EffectMeteorBeam::
@ DecideTurn
jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn
jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn
setbyte sTWOTURN_STRINGID, B_MSG_TURN1_METEOR_BEAM
call BattleScript_FirstChargingTurnMeteorBeam
jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd
call BattleScript_PowerHerbActivation
goto BattleScript_TwoTurnMovesSecondTurn
BattleScript_FirstChargingTurnMeteorBeam::
attackcanceler
printstring STRINGID_EMPTYSTRING3
ppreduce
attackanimation
waitanimation
orword gHitMarker, HITMARKER_CHARGING
setmoveeffect MOVE_EFFECT_CHARGING | MOVE_EFFECT_AFFECTS_USER
seteffectprimary
copybyte cMULTISTRING_CHOOSER, sTWOTURN_STRINGID
printfromtable gFirstTurnOfTwoStringIds
waitmessage 0x40
setmoveeffect MOVE_EFFECT_SP_ATK_PLUS_1 | MOVE_EFFECT_AFFECTS_USER
seteffectsecondary
return
BattleScript_EffectScaleShot::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
setmultihitcounter 0x0
initmultihitstring
sethword sMULTIHIT_EFFECT, 0x0
BattleScript_ScaleShotLoop::
jumpifhasnohp BS_ATTACKER, BattleScript_ScaleShotEnd
jumpifhasnohp BS_TARGET, BattleScript_ScaleShotPrintStrings
jumpifhalfword CMP_EQUAL, gChosenMove, MOVE_SLEEP_TALK, BattleScript_ScaleShotDoMultiHit
jumpifstatus BS_ATTACKER, STATUS1_SLEEP, BattleScript_ScaleShotPrintStrings
BattleScript_ScaleShotDoMultiHit::
movevaluescleanup
copyhword sMOVE_EFFECT, sMULTIHIT_EFFECT
critcalc
damagecalc
jumpifmovehadnoeffect BattleScript_ScaleShotMultiHitNoMoreHits
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage 0x40
multihitresultmessage
printstring STRINGID_EMPTYSTRING3
waitmessage 0x1
addbyte sMULTIHIT_STRING + 4, 0x1
moveendto MOVEEND_NEXT_TARGET
jumpifbyte CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_FOE_ENDURED, BattleScript_ScaleShotPrintStrings
decrementmultihit BattleScript_ScaleShotLoop
goto BattleScript_ScaleShotPrintStrings
BattleScript_ScaleShotMultiHitNoMoreHits::
pause 0x20
BattleScript_ScaleShotPrintStrings::
resultmessage
waitmessage 0x40
jumpifmovehadnoeffect BattleScript_ScaleShotEnd
copyarray gBattleTextBuff1, sMULTIHIT_STRING, 0x6
printstring STRINGID_HITXTIMES
waitmessage 0x40
BattleScript_ScaleShotEnd::
setmoveeffect MOVE_EFFECT_SCALE_SHOT | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN
seteffectwithchance
tryfaintmon BS_TARGET
moveendcase MOVEEND_SYNCHRONIZE_TARGET
moveendfrom MOVEEND_STATUS_IMMUNITY_ABILITIES
end
BattleScript_EffectSkyDrop:
jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_SkyDropTurn2
@ -466,6 +623,92 @@ BattleScript_SkyDropFlyingAlreadyConfused:
setbyte BS_ATTACKER, BS_TARGET
goto BattleScript_ThrashConfuses
BattleScript_EffectFling:
jumpifcantfling BS_ATTACKER, BattleScript_ButItFailedAtkStringPpReduce
jumpifstatus3 BS_ATTACKER, STATUS3_EMBARGO, BattleScript_ButItFailedAtkStringPpReduce
jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_MAGIC_ROOM, BattleScript_ButItFailedAtkStringPpReduce
setlastuseditem BS_ATTACKER
removeitem BS_ATTACKER
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
pause B_WAIT_TIME_SHORT
printstring STRINGID_PKMNFLUNG
waitmessage B_WAIT_TIME_SHORT
ppreduce
critcalc
damagecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_MED
resultmessage
waitmessage B_WAIT_TIME_MED
jumpiflastuseditemberry BattleScript_EffectFlingConsumeBerry
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_FLAME_ORB, BattleScript_FlingFlameOrb
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_FLINCH, BattleScript_FlingFlinch
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_LIGHT_BALL, BattleScript_FlingLightBall
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_MENTAL_HERB, BattleScript_FlingMentalHerb
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_POISON_POWER, BattleScript_FlingPoisonBarb
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_TOXIC_ORB, BattleScript_FlingToxicOrb
jumpiflastuseditemholdeffect BS_ATTACKER, HOLD_EFFECT_RESTORE_STATS, BattleScript_FlingWhiteHerb
BattleScript_EffectFlingConsumeBerry:
savebattleritem BS_TARGET
battleritemtolastuseditem BS_TARGET
setbyte sBERRY_OVERRIDE, TRUE @ override the requirements for eating berries
orword gHitMarker, HITMARKER_NO_ANIMATIONS
consumeberry BS_TARGET
bicword gHitMarker, HITMARKER_NO_ANIMATIONS
setbyte sBERRY_OVERRIDE, FALSE
restorebattleritem BS_TARGET
BattleScript_FlingEnd:
tryfaintmon BS_TARGET
goto BattleScript_MoveEnd
BattleScript_FlingFlameOrb:
setmoveeffect MOVE_EFFECT_BURN
seteffectprimary
goto BattleScript_FlingEnd
BattleScript_FlingFlinch:
setmoveeffect MOVE_EFFECT_FLINCH
seteffectprimary
goto BattleScript_FlingEnd
BattleScript_FlingLightBall:
setmoveeffect MOVE_EFFECT_PARALYSIS
seteffectprimary
goto BattleScript_FlingEnd
BattleScript_FlingMentalHerb:
curecertainstatuses BS_TARGET
savetarget
copybyte gBattlerAttacker, gBattlerTarget
playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL
printfromtable gMentalHerbCureStringIds
waitmessage B_WAIT_TIME_LONG
updatestatusicon BS_ATTACKER
restoretarget
goto BattleScript_FlingEnd
BattleScript_FlingPoisonBarb:
setmoveeffect MOVE_EFFECT_POISON
seteffectprimary
goto BattleScript_FlingEnd
BattleScript_FlingToxicOrb:
setmoveeffect MOVE_EFFECT_TOXIC
seteffectprimary
goto BattleScript_FlingEnd
BattleScript_FlingWhiteHerb:
tryresetnegativestatstages BS_TARGET
swapattackerwithtarget
printstring STRINGID_PKMNSTATUSNORMAL
waitmessage B_WAIT_TIME_MED
swapattackerwithtarget
goto BattleScript_FlingEnd
BattleScript_EffectShellSideArm:
shellsidearmcheck
setmoveeffect MOVE_EFFECT_POISON
@ -1076,6 +1319,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
@ -1910,7 +2154,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:
@ -1921,7 +2167,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:
@ -2144,7 +2392,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
@ -2213,6 +2461,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
@ -2907,6 +3157,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
@ -2926,6 +3177,7 @@ BattleScript_AbsorbUpdateHp::
waitmessage B_WAIT_TIME_LONG
BattleScript_AbsorbTryFainting::
tryfaintmon BS_ATTACKER
BattleScript_AbsorbHealBlock::
tryfaintmon BS_TARGET
goto BattleScript_MoveEnd
@ -3032,6 +3284,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
@ -4337,7 +4590,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::
@ -6009,12 +6266,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::
@ -6256,9 +6531,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::
@ -6297,6 +6574,7 @@ BattleScript_DamagingWeatherContinuesEnd::
BattleScript_SandStormHailEnds::
printfromtable gSandStormHailEndStringIds
waitmessage B_WAIT_TIME_LONG
call BattleScript_WeatherFormChanges
end2
BattleScript_SunlightContinues::
@ -6308,6 +6586,7 @@ BattleScript_SunlightContinues::
BattleScript_SunlightFaded::
printstring STRINGID_SUNLIGHTFADED
waitmessage B_WAIT_TIME_LONG
call BattleScript_WeatherFormChanges
end2
BattleScript_OverworldWeatherStarts::
@ -6677,6 +6956,7 @@ BattleScript_ToxicSpikesPoisoned::
BattleScript_StickyWebOnSwitchIn::
savetarget
copybyte gBattlerTarget, sBATTLER
setbyte sSTICKY_WEB_STAT_DROP, 1
printstring STRINGID_STICKYWEBSWITCHIN
waitmessage B_WAIT_TIME_LONG
jumpifability BS_TARGET, ABILITY_MIRROR_ARMOR, BattleScript_MirrorArmorReflectStickyWeb
@ -7085,6 +7365,26 @@ BattleScript_DefSpDefDownTrySpDef::
BattleScript_DefSpDefDownRet::
return
BattleScript_DefDownSpeedUp::
jumpifstat BS_ATTACKER, CMP_GREATER_THAN, STAT_DEF, MIN_STAT_STAGE, BattleScript_DefDownSpeedUpTryDef
jumpifstat BS_ATTACKER, CMP_EQUAL, STAT_SPEED, MAX_STAT_STAGE, BattleScript_DefDownSpeedUpRet
BattleScript_DefDownSpeedUpTryDef::
playstatchangeanimation BS_ATTACKER, BIT_DEF, STAT_CHANGE_NEGATIVE | STAT_CHANGE_CANT_PREVENT
setstatchanger STAT_DEF, 1, TRUE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_DefDownSpeedUpTrySpeed
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpTrySpeed
printfromtable gStatDownStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_DefDownSpeedUpTrySpeed:
playstatchangeanimation BS_ATTACKER, BIT_SPEED, 0
setstatchanger STAT_SPEED, 1, FALSE
statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_BUFF_ALLOW_PTR | MOVE_EFFECT_CERTAIN, BattleScript_DefDownSpeedUpRet
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_DefDownSpeedUpRet
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_DefDownSpeedUpRet::
return
BattleScript_KnockedOff::
playanimation BS_TARGET, B_ANIM_ITEM_KNOCKOFF
printstring STRINGID_PKMNKNOCKEDOFF
@ -7708,7 +8008,7 @@ BattleScript_DrizzleActivates::
call BattleScript_WeatherFormChanges
end3
BattleScript_DefiantActivates::
BattleScript_AbilityRaisesDefenderStat::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
statbuffchange 0, NULL
@ -7988,8 +8288,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::
@ -8006,8 +8308,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::
@ -8218,6 +8522,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
@ -9317,7 +9628,6 @@ BattleScript_EffectTerrainHit:
resultmessage
waitmessage 0x40
setterrain BattleScript_TryFaint
@@@ TODO - 'restore' bg @@@
printfromtable gTerrainStringIds
BattleScript_TryFaint:
tryfaintmon BS_TARGET

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

View File

Before

Width:  |  Height:  |  Size: 567 B

After

Width:  |  Height:  |  Size: 567 B

View File

Before

Width:  |  Height:  |  Size: 469 B

After

Width:  |  Height:  |  Size: 469 B

View File

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 189 B

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

@ -141,10 +141,12 @@ struct ProtectStruct
u32 usedMicleBerry:1;
u32 usedCustapBerry:1; // also quick claw
u32 touchedProtectLike:1;
u32 disableEjectPack:1;
u32 statFell:1;
u32 pranksterElevated:1;
u32 quickDraw:1;
// End of 32-bit bitfield
u16 disableEjectPack:1;
u16 statFell:1;
u16 pranksterElevated:1;
u16 quickDraw:1;
u16 beakBlastCharge:1;
u32 physicalDmg;
u32 specialDmg;
u8 physicalBattlerId;
@ -194,19 +196,21 @@ struct SideTimer
u8 mistBattlerId;
u8 safeguardTimer;
u8 safeguardBattlerId;
u8 followmeTimer;
u8 followmeTarget:3;
u8 followmePowder:1; // Rage powder, does not affect grass type pokemon.
u8 spikesAmount;
u8 toxicSpikesAmount;
u8 stealthRockAmount;
u8 stickyWebAmount;
u8 stickyWebBattlerSide; // Used for Court Change
u8 auroraVeilTimer;
u8 auroraVeilBattlerId;
u8 tailwindTimer;
u8 tailwindBattlerId;
u8 luckyChantTimer;
u8 luckyChantBattlerId;
// Timers below this point are not swapped by Court Change
u8 followmeTimer;
u8 followmeTarget:3;
u8 followmePowder:1; // Rage powder, does not affect grass type pokemon.
u8 retaliateTimer;
};
@ -243,33 +247,20 @@ struct AI_SavedBattleMon
struct AiLogicData
{
//attacker data
u16 atkAbility;
u16 atkItem;
u16 atkHoldEffect;
u8 atkParam;
u16 atkSpecies;
// target data
u16 defAbility;
u16 defItem;
u16 defHoldEffect;
u8 defParam;
u16 defSpecies;
// attacker partner data
u8 battlerAtkPartner;
u16 abilities[MAX_BATTLERS_COUNT];
u16 items[MAX_BATTLERS_COUNT];
u16 holdEffects[MAX_BATTLERS_COUNT];
u8 holdEffectParams[MAX_BATTLERS_COUNT];
u16 predictedMoves[MAX_BATTLERS_COUNT];
u8 hpPercents[MAX_BATTLERS_COUNT];
u16 partnerMove;
u16 atkPartnerAbility;
u16 atkPartnerHoldEffect;
bool32 targetSameSide;
// target partner data
u8 battlerDefPartner;
u16 defPartnerAbility;
u16 defPartnerHoldEffect;
s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 effectiveness[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, moveIndex
u8 moveLimitations[MAX_BATTLERS_COUNT];
};
struct AI_ThinkingStruct
{
struct AiLogicData data;
u8 aiState;
u8 movesetIndex;
u16 moveConsidered;
@ -278,7 +269,6 @@ struct AI_ThinkingStruct
u32 aiFlags;
u8 aiAction;
u8 aiLogicId;
s32 simulatedDmg[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, move
struct AI_SavedBattleMon saved[4];
bool8 switchMon; // Because all available moves have no/little effect.
};
@ -294,6 +284,7 @@ struct BattleHistory
u8 moveHistoryIndex[MAX_BATTLERS_COUNT];
u16 trainerItems[MAX_BATTLERS_COUNT];
u8 itemsNo;
u16 heldItems[MAX_BATTLERS_COUNT];
};
struct BattleScriptsStack
@ -321,13 +312,14 @@ struct BattleResources
struct BattleCallbacksStack* battleCallbackStack;
struct StatsArray* beforeLvlUp;
struct AI_ThinkingStruct *ai;
struct AiLogicData *aiData;
struct BattleHistory *battleHistory;
u8 bufferA[MAX_BATTLERS_COUNT][0x200];
u8 bufferB[MAX_BATTLERS_COUNT][0x200];
};
#define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai))
#define AI_DATA ((struct AiLogicData *)(&gBattleResources->ai->data))
#define AI_DATA ((struct AiLogicData *)(gBattleResources->aiData))
#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory))
struct BattleResults
@ -464,7 +456,6 @@ struct MegaEvolutionData
bool8 playerSelect;
u8 triggerSpriteId;
bool8 isWishMegaEvo;
bool8 isPrimalReversion;
};
struct Illusion
@ -613,7 +604,8 @@ struct BattleStruct
bool8 spriteIgnore0Hp;
struct Illusion illusion[MAX_BATTLERS_COUNT];
s8 aiFinalScore[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // AI, target, moves to make debugging easier
s32 aiSimulatedDamage[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT][MAX_MON_MOVES]; // attacker, target, move to make debugging easier
u8 aiMoveOrAction[MAX_BATTLERS_COUNT];
u8 aiChosenTarget[MAX_BATTLERS_COUNT];
u8 soulheartBattlerId;
u8 friskedBattler; // Frisk needs to identify 2 battlers in double battles.
bool8 friskedAbility; // If identifies two mons, show the ability pop-up only once.
@ -649,7 +641,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; \
@ -718,6 +710,7 @@ struct BattleScripting
u16 abilityPopupOverwrite;
u8 switchCase; // Special switching conditions, eg. red card
u8 overrideBerryRequirements;
u8 stickyWebStatDrop; // To prevent Defiant activating on a Court Change'd Sticky Web
};
struct BattleSpriteInfo
@ -946,5 +939,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

@ -19,11 +19,12 @@
return score; \
}
u8 ComputeBattleAiScores(u8 battler);
void BattleAI_SetupItems(void);
void BattleAI_SetupFlags(void);
void BattleAI_SetupAIData(u8 defaultScoreMoves);
u8 BattleAI_ChooseMoveOrAction(void);
void GetAiLogicData(void);
extern u8 sBattler_AI;

View File

@ -20,6 +20,7 @@ void ClearBattlerItemEffectHistory(u8 battlerId);
void SaveBattlerData(u8 battlerId);
void SetBattlerData(u8 battlerId);
void RestoreBattlerData(u8 battlerId);
u16 GetAIChosenMove(u8 battlerId);
bool32 WillAIStrikeFirst(void);
u32 GetTotalBaseStat(u32 species);
@ -27,13 +28,13 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler);
bool32 AtMaxHp(u8 battler);
u32 GetHealthPercentage(u8 battler);
bool32 IsBattlerTrapped(u8 battler, bool8 switching);
u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2);
u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 consideredMove);
bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk);
bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits);
bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod);
s32 AI_GetAbility(u32 battlerId);
u16 AI_GetHoldEffect(u32 battlerId);
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move);
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 move);
bool32 DoesBattlerIgnoreAbilityChecks(u16 atkAbility, u16 move);
bool32 AI_WeatherHasEffect(void);
bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits);
@ -45,7 +46,7 @@ bool32 HasDamagingMoveOfType(u8 battlerId, u8 type);
u32 GetBattlerSecondaryDamage(u8 battlerId);
bool32 BattlerWillFaintFromWeather(u8 battler, u16 ability);
bool32 BattlerWillFaintFromSecondaryDamage(u8 battler, u16 ability);
bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move);
bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move);
bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveIndex);
u16 GetBattlerSideSpeedAverage(u8 battler);
bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage);
@ -60,6 +61,7 @@ bool32 IsAbilityOfRating(u16 ability, s8 rating);
s8 GetAbilityRating(u16 ability);
bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability);
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u16 move);
u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move);
bool32 ShouldUseZMove(u8 activeId, u8 targetId, u16 chosenMove);
// stat stage checks
@ -81,11 +83,11 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility);
// move checks
bool32 IsAffectedByPowder(u8 battler, u16 ability, u16 holdEffect);
bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split);
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, bool32 considerZPower);
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *effectiveness, bool32 considerZPower);
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);
@ -144,7 +146,7 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move);
bool32 IsWakeupTurn(u8 battler);
// partner logic
u16 GetAllyChosenMove(void);
u16 GetAllyChosenMove(u8 battlerId);
bool32 IsValidDoubleBattle(u8 battlerAtk);
bool32 IsTargetingPartner(u8 battlerAtk, u8 battlerDef);
bool32 DoesPartnerHaveSameMoveEffect(u8 battlerAtkPartner, u8 battlerDef, u16 move, u16 partnerMove);

View File

@ -6,7 +6,7 @@ u8 BattleArena_ShowJudgmentWindow(u8 *state);
void BattleArena_InitPoints(void);
void BattleArena_AddMindPoints(u8 battler);
void BattleArena_AddSkillPoints(u8 battler);
void BattleArena_DeductMindPoints(u8 battler, u16 stringId);
void BattleArena_DeductSkillPoints(u8 battler, u16 stringId);
void DrawArenaRefereeTextBox(void);
void EraseArenaRefereeTextBox(void);

View File

@ -3,7 +3,7 @@
void CallBattleFactoryFunction(void);
bool8 InBattleFactory(void);
u8 GetFactoryMonFixedIV(u8 arg0, u8 arg1);
u8 GetFactoryMonFixedIV(u8 challengeNum, bool8 isLastBattle);
void FillFactoryBrainParty(void);
u8 GetNumPastRentalsRank(u8 battleMode, u8 lvlMode);
u32 GetAiScriptsInBattleFactory(void);

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

@ -15,7 +15,7 @@ struct StatFractions
s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbility);
s8 GetInverseCritChance(u8 battlerAtk, u8 battlerDef, u32 move);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
u8 GetBattlerTurnOrderNum(u8 battlerId);
bool32 NoAliveMonsForEitherParty(void);
void SetMoveEffect(bool32 primary, u32 certain);

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[];
@ -416,6 +417,9 @@ extern const u8 BattleScript_BothCanNoLongerEscape[];
extern const u8 BattleScript_OctolockEndTurn[];
extern const u8 BattleScript_NeutralizingGasExits[];
extern const u8 BattleScript_MagicianActivates[];
extern const u8 BattleScript_BeakBlastSetUp[];
extern const u8 BattleScript_BeakBlastBurn[];
extern const u8 BattleScript_DefDownSpeedUp[];
// zmoves
extern const u8 BattleScript_ZMoveActivateDamaging[];

View File

@ -129,11 +129,13 @@ bool32 IsBattlerAlive(u8 battlerId);
u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move);
u32 GetBattlerWeight(u8 battlerId);
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags);
s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, u16 *typeEffectivenessModifier);
u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities);
u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
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);
@ -172,7 +174,8 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags);
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

@ -81,6 +81,8 @@
#define WILD_DOUBLE_BATTLE ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_TRAINER))))
#define BATTLE_TWO_VS_ONE_OPPONENT ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gTrainerBattleOpponent_B == 0xFFFF))
#define BATTLE_TYPE_HAS_AI (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER)
// Battle Outcome defines
#define B_OUTCOME_WON 1
@ -203,6 +205,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)
@ -363,8 +366,9 @@
#define MOVE_EFFECT_RELIC_SONG 0x47
#define MOVE_EFFECT_TRAP_BOTH 0x48
#define MOVE_EFFECT_SKY_DROP 0x49
#define MOVE_EFFECT_SCALE_SHOT 0x4A
#define NUM_MOVE_EFFECTS 0x50
#define NUM_MOVE_EFFECTS 0x4B
#define MOVE_EFFECT_AFFECTS_USER 0x4000
#define MOVE_EFFECT_CERTAIN 0x8000

View File

@ -15,11 +15,13 @@
#define AI_TYPE_MOVE 4
// type effectiveness
#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_x8 7
#define AI_EFFECTIVENESS_x4 6
#define AI_EFFECTIVENESS_x2 5
#define AI_EFFECTIVENESS_x1 4
#define AI_EFFECTIVENESS_x0_5 3
#define AI_EFFECTIVENESS_x0_25 2
#define AI_EFFECTIVENESS_x0_125 1
#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
@ -532,7 +533,9 @@
#define B_ANIM_STRONG_WINDS 30
#define B_ANIM_PRIMAL_REVERSION 31
#define B_ANIM_AQUA_RING_HEAL 32
#define B_ANIM_ZMOVE_ACTIVATE 33 // Using Z Moves
#define B_ANIM_BEAK_BLAST_SETUP 33
#define B_ANIM_SHELL_TRAP_SETUP 34
#define B_ANIM_ZMOVE_ACTIVATE 35 // Using Z Moves
// special animations table (gBattleAnims_Special)
#define B_ANIM_LVL_UP 0
@ -571,6 +574,7 @@
#define TRAP_ANIM_SAND_TOMB 4
#define TRAP_ANIM_MAGMA_STORM 5
#define TRAP_ANIM_INFESTATION 6
#define TRAP_ANIM_SNAP_TRAP 7
// Weather defines for battle animation scripts.
#define ANIM_WEATHER_NONE 0

View File

@ -134,11 +134,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.
@ -151,6 +152,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.
@ -185,17 +187,20 @@
#define B_KINGS_SHIELD_LOWER_ATK GEN_7 // In Gen7+, it lowers Atk by 1 stage instead of 2 of oponents that hit it.
#define B_SPEED_BUFFING_RAPID_SPIN GEN_8 // In Gen8, Rapid Spin raises the user's Speed by 1 stage.
#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.
@ -204,6 +209,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.
// Ability settings
#define B_EXPANDED_ABILITY_NAMES TRUE // If TRUE, ability names are increased from 12 characters to 16 characters.
@ -215,11 +224,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.
@ -235,7 +247,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.
@ -277,6 +288,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

@ -387,9 +387,16 @@
#define EFFECT_CLANGOROUS_SOUL 381
#define EFFECT_BOLT_BEAK 382
#define EFFECT_SKY_DROP 383
#define EFFECT_EXTREME_EVOBOOST 384
#define EFFECT_DAMAGE_SET_TERRAIN 385 // genesis supernova
#define EFFECT_EXPANDING_FORCE 384
#define EFFECT_SCALE_SHOT 385
#define EFFECT_METEOR_BEAM 386
#define EFFECT_RISING_VOLTAGE 387
#define EFFECT_BEAK_BLAST 388
#define EFFECT_COURT_CHANGE 389
#define EFFECT_STEEL_BEAM 390
#define EFFECT_EXTREME_EVOBOOST 391
#define EFFECT_DAMAGE_SET_TERRAIN 392 // genesis supernova
#define NUM_BATTLE_MOVE_EFFECTS 386
#define NUM_BATTLE_MOVE_EFFECTS 393
#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H

View File

@ -39,6 +39,7 @@
#define sABILITY_OVERWRITE (gBattleScripting + 0x34) // abilityPopupOverwrite
#define sSWITCH_CASE (gBattleScripting + 0x36) // switchCase
#define sBERRY_OVERRIDE (gBattleScripting + 0x37) // overrideBerryRequirements
#define sSTICKY_WEB_STAT_DROP (gBattleScripting + 0x38) // stickyWebStatDrop
// Array entries for battle communication
#define MULTIUSE_STATE 0
@ -87,149 +88,160 @@
#define CMP_NO_COMMON_BITS 5
// Cmd_various
#define VARIOUS_CANCEL_MULTI_TURN_MOVES 0
#define VARIOUS_SET_MAGIC_COAT_TARGET 1
#define VARIOUS_IS_RUNNING_IMPOSSIBLE 2
#define VARIOUS_GET_MOVE_TARGET 3
#define VARIOUS_GET_BATTLER_FAINTED 4
#define VARIOUS_RESET_INTIMIDATE_TRACE_BITS 5
#define VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP 6
#define VARIOUS_RESET_PLAYER_FAINTED 7
#define VARIOUS_PALACE_FLAVOR_TEXT 8
#define VARIOUS_ARENA_JUDGMENT_WINDOW 9
#define VARIOUS_ARENA_OPPONENT_MON_LOST 10
#define VARIOUS_ARENA_PLAYER_MON_LOST 11
#define VARIOUS_ARENA_BOTH_MONS_LOST 12
#define VARIOUS_EMIT_YESNOBOX 13
#define VARIOUS_DRAW_ARENA_REF_TEXT_BOX 14
#define VARIOUS_ERASE_ARENA_REF_TEXT_BOX 15
#define VARIOUS_ARENA_JUDGMENT_STRING 16
#define VARIOUS_ARENA_WAIT_STRING 17
#define VARIOUS_WAIT_CRY 18
#define VARIOUS_RETURN_OPPONENT_MON1 19
#define VARIOUS_RETURN_OPPONENT_MON2 20
#define VARIOUS_VOLUME_DOWN 21
#define VARIOUS_VOLUME_UP 22
#define VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT 23
#define VARIOUS_PALACE_TRY_ESCAPE_STATUS 24
#define VARIOUS_SET_TELEPORT_OUTCOME 25
#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26
#define VARIOUS_STAT_TEXT_BUFFER 27
#define VARIOUS_SWITCHIN_ABILITIES 28
#define VARIOUS_SAVE_TARGET 29
#define VARIOUS_RESTORE_TARGET 30
#define VARIOUS_INSTANT_HP_DROP 31
#define VARIOUS_CLEAR_STATUS 32
#define VARIOUS_RESTORE_PP 33
#define VARIOUS_TRY_ACTIVATE_MOXIE 34
#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 35
#define VARIOUS_PLAY_MOVE_ANIMATION 36
#define VARIOUS_SET_LUCKY_CHANT 37
#define VARIOUS_SUCKER_PUNCH_CHECK 38
#define VARIOUS_SET_SIMPLE_BEAM 39
#define VARIOUS_TRY_ENTRAINMENT 40
#define VARIOUS_SET_LAST_USED_ABILITY 41
#define VARIOUS_TRY_HEAL_PULSE 42
#define VARIOUS_TRY_QUASH 43
#define VARIOUS_INVERT_STAT_STAGES 44
#define VARIOUS_SET_TERRAIN 45
#define VARIOUS_TRY_ME_FIRST 46
#define VARIOUS_JUMP_IF_BATTLE_END 47
#define VARIOUS_TRY_ELECTRIFY 48
#define VARIOUS_TRY_REFLECT_TYPE 49
#define VARIOUS_TRY_SOAK 50
#define VARIOUS_HANDLE_MEGA_EVO 51
#define VARIOUS_TRY_LAST_RESORT 52
#define VARIOUS_ARGUMENT_STATUS_EFFECT 53
#define VARIOUS_TRY_HIT_SWITCH_TARGET 54
#define VARIOUS_TRY_AUTOTOMIZE 55
#define VARIOUS_TRY_COPYCAT 56
#define VARIOUS_ABILITY_POPUP 57
#define VARIOUS_DEFOG 58
#define VARIOUS_JUMP_IF_TARGET_ALLY 59
#define VARIOUS_TRY_SYNCHRONOISE 60
#define VARIOUS_PSYCHO_SHIFT 61
#define VARIOUS_CURE_STATUS 62
#define VARIOUS_POWER_TRICK 63
#define VARIOUS_AFTER_YOU 64
#define VARIOUS_BESTOW 65
#define VARIOUS_ARGUMENT_TO_MOVE_EFFECT 66
#define VARIOUS_JUMP_IF_NOT_GROUNDED 67
#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 68
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 69
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 70
#define VARIOUS_SET_AURORA_VEIL 71
#define VARIOUS_TRY_THIRD_TYPE 72
#define VARIOUS_ACUPRESSURE 73
#define VARIOUS_SET_POWDER 74
#define VARIOUS_SPECTRAL_THIEF 75
#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76
#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77
#define VARIOUS_JUMP_IF_ROAR_FAILS 78
#define VARIOUS_TRY_INSTRUCT 79
#define VARIOUS_JUMP_IF_NOT_BERRY 80
#define VARIOUS_TRACE_ABILITY 81
#define VARIOUS_UPDATE_NICK 82
#define VARIOUS_TRY_ILLUSION_OFF 83
#define VARIOUS_SET_SPRITEIGNORE0HP 84
#define VARIOUS_HANDLE_FORM_CHANGE 85
#define VARIOUS_GET_STAT_VALUE 86
#define VARIOUS_JUMP_IF_FULL_HP 87
#define VARIOUS_LOSE_TYPE 88
#define VARIOUS_TRY_ACTIVATE_SOULHEART 89
#define VARIOUS_TRY_ACTIVATE_RECEIVER 90
#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 91
#define VARIOUS_TRY_FRISK 92
#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 93
#define VARIOUS_TRY_FAIRY_LOCK 94
#define VARIOUS_JUMP_IF_NO_ALLY 95
#define VARIOUS_POISON_TYPE_IMMUNITY 96
#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 97
#define VARIOUS_INFATUATE_WITH_BATTLER 98
#define VARIOUS_SET_LAST_USED_ITEM 99
#define VARIOUS_PARALYZE_TYPE_IMMUNITY 100
#define VARIOUS_JUMP_IF_ABSENT 101
#define VARIOUS_DESTROY_ABILITY_POPUP 102
#define VARIOUS_TOTEM_BOOST 103
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104
#define VARIOUS_MOVEEND_ITEM_EFFECTS 105
#define VARIOUS_TERRAIN_SEED 106
#define VARIOUS_MAKE_INVISIBLE 107
#define VARIOUS_ROOM_SERVICE 108
#define VARIOUS_JUMP_IF_TERRAIN_AFFECTED 109
#define VARIOUS_EERIE_SPELL_PP_REDUCE 110
#define VARIOUS_JUMP_IF_TEAM_HEALTHY 111
#define VARIOUS_TRY_HEAL_QUARTER_HP 112
#define VARIOUS_REMOVE_TERRAIN 113
#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 114
#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 115
#define VARIOUS_GET_ROTOTILLER_TARGETS 116
#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 117
#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 118
#define VARIOUS_CONSUME_BERRY 119
#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 120
#define VARIOUS_HANDLE_PRIMAL_REVERSION 121
#define VARIOUS_APPLY_PLASMA_FISTS 122
#define VARIOUS_JUMP_IF_SPECIES 123
#define VARIOUS_UPDATE_ABILITY_POPUP 124
#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 125
#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 126
#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 127
#define VARIOUS_TRY_TO_APPLY_MIMICRY 128
#define VARIOUS_PHOTON_GEYSER_CHECK 129
#define VARIOUS_SHELL_SIDE_ARM_CHECK 130
#define VARIOUS_TRY_NO_RETREAT 131
#define VARIOUS_TRY_TAR_SHOT 132
#define VARIOUS_CAN_TAR_SHOT_WORK 133
#define VARIOUS_CHECK_POLTERGEIST 134
#define VARIOUS_SET_OCTOLOCK 135
#define VARIOUS_CUT_1_3_HP_RAISE_STATS 136
#define VARIOUS_TRY_END_NEUTRALIZING_GAS 137
#define VARIOUS_JUMP_IF_UNDER_200 138
#define VARIOUS_SET_SKY_DROP 139
#define VARIOUS_CLEAR_SKY_DROP 140
#define VARIOUS_SKY_DROP_YAWN 141
#define VARIOUS_SET_Z_EFFECT 142
#define VARIOUS_CANCEL_MULTI_TURN_MOVES 0
#define VARIOUS_SET_MAGIC_COAT_TARGET 1
#define VARIOUS_IS_RUNNING_IMPOSSIBLE 2
#define VARIOUS_GET_MOVE_TARGET 3
#define VARIOUS_GET_BATTLER_FAINTED 4
#define VARIOUS_RESET_INTIMIDATE_TRACE_BITS 5
#define VARIOUS_UPDATE_CHOICE_MOVE_ON_LVL_UP 6
#define VARIOUS_RESET_PLAYER_FAINTED 7
#define VARIOUS_PALACE_FLAVOR_TEXT 8
#define VARIOUS_ARENA_JUDGMENT_WINDOW 9
#define VARIOUS_ARENA_OPPONENT_MON_LOST 10
#define VARIOUS_ARENA_PLAYER_MON_LOST 11
#define VARIOUS_ARENA_BOTH_MONS_LOST 12
#define VARIOUS_EMIT_YESNOBOX 13
#define VARIOUS_DRAW_ARENA_REF_TEXT_BOX 14
#define VARIOUS_ERASE_ARENA_REF_TEXT_BOX 15
#define VARIOUS_ARENA_JUDGMENT_STRING 16
#define VARIOUS_ARENA_WAIT_STRING 17
#define VARIOUS_WAIT_CRY 18
#define VARIOUS_RETURN_OPPONENT_MON1 19
#define VARIOUS_RETURN_OPPONENT_MON2 20
#define VARIOUS_VOLUME_DOWN 21
#define VARIOUS_VOLUME_UP 22
#define VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT 23
#define VARIOUS_PALACE_TRY_ESCAPE_STATUS 24
#define VARIOUS_SET_TELEPORT_OUTCOME 25
#define VARIOUS_PLAY_TRAINER_DEFEATED_MUSIC 26
#define VARIOUS_STAT_TEXT_BUFFER 27
#define VARIOUS_SWITCHIN_ABILITIES 28
#define VARIOUS_SAVE_TARGET 29
#define VARIOUS_RESTORE_TARGET 30
#define VARIOUS_INSTANT_HP_DROP 31
#define VARIOUS_CLEAR_STATUS 32
#define VARIOUS_RESTORE_PP 33
#define VARIOUS_TRY_ACTIVATE_MOXIE 34
#define VARIOUS_TRY_ACTIVATE_FELL_STINGER 35
#define VARIOUS_PLAY_MOVE_ANIMATION 36
#define VARIOUS_SET_LUCKY_CHANT 37
#define VARIOUS_SUCKER_PUNCH_CHECK 38
#define VARIOUS_SET_SIMPLE_BEAM 39
#define VARIOUS_TRY_ENTRAINMENT 40
#define VARIOUS_SET_LAST_USED_ABILITY 41
#define VARIOUS_TRY_HEAL_PULSE 42
#define VARIOUS_TRY_QUASH 43
#define VARIOUS_INVERT_STAT_STAGES 44
#define VARIOUS_SET_TERRAIN 45
#define VARIOUS_TRY_ME_FIRST 46
#define VARIOUS_JUMP_IF_BATTLE_END 47
#define VARIOUS_TRY_ELECTRIFY 48
#define VARIOUS_TRY_REFLECT_TYPE 49
#define VARIOUS_TRY_SOAK 50
#define VARIOUS_HANDLE_MEGA_EVO 51
#define VARIOUS_TRY_LAST_RESORT 52
#define VARIOUS_ARGUMENT_STATUS_EFFECT 53
#define VARIOUS_TRY_HIT_SWITCH_TARGET 54
#define VARIOUS_TRY_AUTOTOMIZE 55
#define VARIOUS_TRY_COPYCAT 56
#define VARIOUS_ABILITY_POPUP 57
#define VARIOUS_DEFOG 58
#define VARIOUS_JUMP_IF_TARGET_ALLY 59
#define VARIOUS_TRY_SYNCHRONOISE 60
#define VARIOUS_PSYCHO_SHIFT 61
#define VARIOUS_CURE_STATUS 62
#define VARIOUS_POWER_TRICK 63
#define VARIOUS_AFTER_YOU 64
#define VARIOUS_BESTOW 65
#define VARIOUS_ARGUMENT_TO_MOVE_EFFECT 66
#define VARIOUS_JUMP_IF_NOT_GROUNDED 67
#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 68
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 69
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 70
#define VARIOUS_SET_AURORA_VEIL 71
#define VARIOUS_TRY_THIRD_TYPE 72
#define VARIOUS_ACUPRESSURE 73
#define VARIOUS_SET_POWDER 74
#define VARIOUS_SPECTRAL_THIEF 75
#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 76
#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 77
#define VARIOUS_JUMP_IF_ROAR_FAILS 78
#define VARIOUS_TRY_INSTRUCT 79
#define VARIOUS_JUMP_IF_NOT_BERRY 80
#define VARIOUS_TRACE_ABILITY 81
#define VARIOUS_UPDATE_NICK 82
#define VARIOUS_TRY_ILLUSION_OFF 83
#define VARIOUS_SET_SPRITEIGNORE0HP 84
#define VARIOUS_HANDLE_FORM_CHANGE 85
#define VARIOUS_GET_STAT_VALUE 86
#define VARIOUS_JUMP_IF_FULL_HP 87
#define VARIOUS_LOSE_TYPE 88
#define VARIOUS_TRY_ACTIVATE_SOULHEART 89
#define VARIOUS_TRY_ACTIVATE_RECEIVER 90
#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 91
#define VARIOUS_TRY_FRISK 92
#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 93
#define VARIOUS_TRY_FAIRY_LOCK 94
#define VARIOUS_JUMP_IF_NO_ALLY 95
#define VARIOUS_POISON_TYPE_IMMUNITY 96
#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 97
#define VARIOUS_INFATUATE_WITH_BATTLER 98
#define VARIOUS_SET_LAST_USED_ITEM 99
#define VARIOUS_PARALYZE_TYPE_IMMUNITY 100
#define VARIOUS_JUMP_IF_ABSENT 101
#define VARIOUS_DESTROY_ABILITY_POPUP 102
#define VARIOUS_TOTEM_BOOST 103
#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 104
#define VARIOUS_MOVEEND_ITEM_EFFECTS 105
#define VARIOUS_TERRAIN_SEED 106
#define VARIOUS_MAKE_INVISIBLE 107
#define VARIOUS_ROOM_SERVICE 108
#define VARIOUS_JUMP_IF_TERRAIN_AFFECTED 109
#define VARIOUS_EERIE_SPELL_PP_REDUCE 110
#define VARIOUS_JUMP_IF_TEAM_HEALTHY 111
#define VARIOUS_TRY_HEAL_QUARTER_HP 112
#define VARIOUS_REMOVE_TERRAIN 113
#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 114
#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 115
#define VARIOUS_GET_ROTOTILLER_TARGETS 116
#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 117
#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 118
#define VARIOUS_CONSUME_BERRY 119
#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 120
#define VARIOUS_HANDLE_PRIMAL_REVERSION 121
#define VARIOUS_APPLY_PLASMA_FISTS 122
#define VARIOUS_JUMP_IF_SPECIES 123
#define VARIOUS_UPDATE_ABILITY_POPUP 124
#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 125
#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 126
#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 127
#define VARIOUS_TRY_TO_APPLY_MIMICRY 128
#define VARIOUS_PHOTON_GEYSER_CHECK 129
#define VARIOUS_SHELL_SIDE_ARM_CHECK 130
#define VARIOUS_TRY_NO_RETREAT 131
#define VARIOUS_TRY_TAR_SHOT 132
#define VARIOUS_CAN_TAR_SHOT_WORK 133
#define VARIOUS_CHECK_POLTERGEIST 134
#define VARIOUS_SET_OCTOLOCK 135
#define VARIOUS_CUT_1_3_HP_RAISE_STATS 136
#define VARIOUS_TRY_END_NEUTRALIZING_GAS 137
#define VARIOUS_JUMP_IF_UNDER_200 138
#define VARIOUS_SET_SKY_DROP 139
#define VARIOUS_CLEAR_SKY_DROP 140
#define VARIOUS_SKY_DROP_YAWN 141
#define VARIOUS_JUMP_IF_CANT_FLING 142
#define VARIOUS_JUMP_IF_HOLD_EFFECT 143
#define VARIOUS_CURE_CERTAIN_STATUSES 144
#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 145
#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 146
#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 147
#define VARIOUS_SAVE_BATTLER_ITEM 148
#define VARIOUS_RESTORE_BATTLER_ITEM 149
#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 150
#define VARIOUS_SET_BEAK_BLAST 151
#define VARIOUS_SWAP_SIDE_STATUSES 152
#define VARIOUS_SET_Z_EFFECT 153
// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0

View File

@ -1,8 +1,6 @@
#ifndef GUARD_CONSTANTS_BATTLE_STRING_IDS_H
#define GUARD_CONSTANTS_BATTLE_STRING_IDS_H
#define BATTLESTRINGS_ID_ADDER 12 // all battlestrings have its ID + 12, because first 5 are reserved
#define STRINGID_INTROMSG 0
#define STRINGID_INTROSENDOUT 1
#define STRINGID_RETURNMON 2
@ -611,17 +609,28 @@
#define STRINGID_NEUTRALIZINGGASOVER 607
#define STRINGID_TARGETTOOHEAVY 608
#define STRINGID_PKMNTOOKTARGETHIGH 609
#define STRINGID_ZPOWERSURROUNDS 610
#define STRINGID_ZMOVEUNLEASHED 611
#define STRINGID_ZMOVERESETSSTATS 612
#define STRINGID_ZMOVEALLSTATSUP 613
#define STRINGID_ZMOVEZBOOSTCRIT 614
#define STRINGID_ZMOVERESTOREHP 615
#define STRINGID_ZMOVESTATUP 616
#define STRINGID_ZMOVEHPTRAP 617
#define STRINGID_TERRAINREMOVED 618
#define STRINGID_PKMNINSNAPTRAP 610
#define STRINGID_METEORBEAMCHARGING 611
#define STRINGID_HEATUPBEAK 612
#define STRINGID_COURTCHANGE 613
#define STRINGID_PLAYERLOSTTOENEMYTRAINER 614
#define STRINGID_PLAYERPAIDPRIZEMONEY 615
#define STRINGID_ZPOWERSURROUNDS 616
#define STRINGID_ZMOVEUNLEASHED 617
#define STRINGID_ZMOVERESETSSTATS 618
#define STRINGID_ZMOVEALLSTATSUP 619
#define STRINGID_ZMOVEZBOOSTCRIT 620
#define STRINGID_ZMOVERESTOREHP 621
#define STRINGID_ZMOVESTATUP 622
#define STRINGID_ZMOVEHPTRAP 623
#define STRINGID_TERRAINREMOVED 624
#define BATTLESTRINGS_COUNT 619
#define BATTLESTRINGS_COUNT 625
// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
// and are instead handled explicitly by BufferStringBattle.
#define BATTLESTRINGS_TABLE_START STRINGID_TRAINER1LOSETEXT
// The below IDs are all indexes into battle message tables,
// used to determine which of a set of messages to print.
@ -673,6 +682,7 @@
#define B_MSG_TURN1_GEOMANCY 9
#define B_MSG_TURN1_FREEZE_SHOCK 10
#define B_MSG_TURN1_SKY_DROP 11
#define B_MSG_TURN1_METEOR_BEAM 12
// gMoveWeatherChangeStringIds
#define B_MSG_STARTED_RAIN 0
@ -873,13 +883,25 @@
#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
// z effects
#define MULTISTRING_Z_RESET_STATS 0
#define MULTISTRING_Z_ALL_STATS_UP 1
#define MULTISTRING_Z_BOOST_CRITS 2
#define MULTISTRING_Z_FOLLOW_ME 3
#define MULTISTRING_Z_RECOVER_HP 4
#define MULTISTRING_Z_STAT_UP 5
#define MULTISTRING_Z_HP_TRAP 6
#define B_MSG_Z_RESET_STATS 0
#define B_MSG_Z_ALL_STATS_UP 1
#define B_MSG_Z_BOOST_CRITS 2
#define B_MSG_Z_FOLLOW_ME 3
#define B_MSG_Z_RECOVER_HP 4
#define B_MSG_Z_STAT_UP 5
#define B_MSG_Z_HP_TRAP 6
#endif // GUARD_CONSTANTS_BATTLE_STRING_IDS_H

View File

@ -273,14 +273,14 @@
#define ANIM_RUN_WEST (ANIM_STD_COUNT + 2)
#define ANIM_RUN_EAST (ANIM_STD_COUNT + 3)
#define ANIM_BUNNY_HOPPY_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 0)
#define ANIM_BUNNY_HOPPY_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 1)
#define ANIM_BUNNY_HOPPY_BACK_WHEEL_WEST (ANIM_STD_COUNT + 2)
#define ANIM_BUNNY_HOPPY_BACK_WHEEL_EAST (ANIM_STD_COUNT + 3)
#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_SOUTH (ANIM_STD_COUNT + 4)
#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_NORTH (ANIM_STD_COUNT + 5)
#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_WEST (ANIM_STD_COUNT + 6)
#define ANIM_BUNNY_HOPPY_FRONT_WHEEL_EAST (ANIM_STD_COUNT + 7)
#define ANIM_BUNNY_HOP_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 0)
#define ANIM_BUNNY_HOP_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 1)
#define ANIM_BUNNY_HOP_BACK_WHEEL_WEST (ANIM_STD_COUNT + 2)
#define ANIM_BUNNY_HOP_BACK_WHEEL_EAST (ANIM_STD_COUNT + 3)
#define ANIM_BUNNY_HOP_FRONT_WHEEL_SOUTH (ANIM_STD_COUNT + 4)
#define ANIM_BUNNY_HOP_FRONT_WHEEL_NORTH (ANIM_STD_COUNT + 5)
#define ANIM_BUNNY_HOP_FRONT_WHEEL_WEST (ANIM_STD_COUNT + 6)
#define ANIM_BUNNY_HOP_FRONT_WHEEL_EAST (ANIM_STD_COUNT + 7)
#define ANIM_STANDING_WHEELIE_BACK_WHEEL_SOUTH (ANIM_STD_COUNT + 8)
#define ANIM_STANDING_WHEELIE_BACK_WHEEL_NORTH (ANIM_STD_COUNT + 9)
#define ANIM_STANDING_WHEELIE_BACK_WHEEL_WEST (ANIM_STD_COUNT + 10)

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

@ -21,6 +21,7 @@ struct Item
u8 battleUsage;
ItemUseFunc battleUseFunc;
u8 secondaryId;
u8 flingPower;
};
struct BagPocket
@ -75,6 +76,6 @@ ItemUseFunc ItemId_GetFieldFunc(u16 itemId);
u8 ItemId_GetBattleUsage(u16 itemId);
ItemUseFunc ItemId_GetBattleFunc(u16 itemId);
u8 ItemId_GetSecondaryId(u16 itemId);
bool32 IsPinchBerryItemEffect(u16 holdEffect);
u8 ItemId_GetFlingPower(u16 itemId);
#endif // GUARD_ITEM_H

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;
}
@ -465,6 +467,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);
@ -1252,9 +1255,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

@ -636,7 +636,7 @@ $(FLDEFFGFXDIR)/tall_grass.4bpp: %.4bpp: %.png
$(FLDEFFGFXDIR)/tree_disguise.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 4
$(FLDEFFGFXDIR)/unknown_16.4bpp: %.4bpp: %.png
$(FLDEFFGFXDIR)/jump_long_grass.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 2 -mheight 2
$(FLDEFFGFXDIR)/unknown_17.4bpp: %.4bpp: %.png

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,8 @@
static bool8 HasSuperEffectiveMoveAgainstOpponents(bool8 noRng);
static bool8 FindMonWithFlagsAndSuperEffective(u16 flags, u8 moduloPercent);
static bool8 ShouldUseItem(void);
static bool32 AI_ShouldHeal(u32 healAmount);
static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount);
void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId)
{
@ -602,39 +604,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 +700,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 +758,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;
@ -788,6 +789,25 @@ static u8 GetAI_ItemType(u16 itemId, const u8 *itemEffect)
return AI_ITEM_NOT_RECOGNIZABLE;
}
static bool32 AiExpectsToFaintPlayer(void)
{
bool32 canFaintPlayer;
u32 i;
u8 target = gBattleStruct->aiChosenTarget[gActiveBattler];
if (gBattleStruct->aiMoveOrAction[gActiveBattler] > 3)
return FALSE; // AI not planning to use move
if (GetBattlerSide(target) != GetBattlerSide(gActiveBattler)
&& CanIndexMoveFaintTarget(gActiveBattler, target, gBattleStruct->aiMoveOrAction[gActiveBattler], 0)
&& AI_WhoStrikesFirst(gActiveBattler, target, GetAIChosenMove(gActiveBattler)) == AI_IS_FASTER) {
// We expect to faint the target and move first -> dont use an item
return TRUE;
}
return FALSE;
}
static bool8 ShouldUseItem(void)
{
struct Pokemon *party;
@ -802,6 +822,9 @@ static bool8 ShouldUseItem(void)
if (gStatuses3[gActiveBattler] & STATUS3_EMBARGO)
return FALSE;
if (AiExpectsToFaintPlayer())
return FALSE;
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
party = gPlayerParty;
@ -843,21 +866,10 @@ static bool8 ShouldUseItem(void)
switch (*(gBattleStruct->AI_itemType + gActiveBattler / 2))
{
case AI_ITEM_FULL_RESTORE:
if (gBattleMons[gActiveBattler].hp >= gBattleMons[gActiveBattler].maxHP / 4)
break;
if (gBattleMons[gActiveBattler].hp == 0)
break;
shouldUse = TRUE;
shouldUse = AI_ShouldHeal(0);
break;
case AI_ITEM_HEAL_HP:
paramOffset = GetItemEffectParamOffset(item, 4, 4);
if (paramOffset == 0)
break;
if (gBattleMons[gActiveBattler].hp == 0)
break;
if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4
|| gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > itemEffects[paramOffset])
shouldUse = TRUE;
shouldUse = AI_ShouldHeal(itemEffects[GetItemEffectParamOffset(item, 4, 4)]);
break;
case AI_ITEM_CURE_CONDITION:
*(gBattleStruct->AI_itemFlags + gActiveBattler / 2) = 0;
@ -948,3 +960,32 @@ static bool8 ShouldUseItem(void)
return FALSE;
}
static bool32 AI_ShouldHeal(u32 healAmount)
{
bool32 shouldHeal = FALSE;
if (gBattleMons[gActiveBattler].hp < gBattleMons[gActiveBattler].maxHP / 4
|| gBattleMons[gActiveBattler].hp == 0
|| (healAmount != 0 && gBattleMons[gActiveBattler].maxHP - gBattleMons[gActiveBattler].hp > healAmount)) {
// We have low enough HP to consider healing
shouldHeal = !AI_OpponentCanFaintAiWithMod(healAmount); // if target can kill us even after we heal, why bother
}
return shouldHeal;
}
static bool32 AI_OpponentCanFaintAiWithMod(u32 healAmount)
{
u32 i;
// Check special cases to NOT heal
for (i = 0; i < gBattlersCount; i++) {
if (GetBattlerSide(i) == B_SIDE_PLAYER) {
if (CanTargetFaintAiWithMod(i, gActiveBattler, healAmount, 0)) {
// Target is expected to faint us
return TRUE;
}
}
}
return FALSE;
}

View File

@ -21,6 +21,8 @@
#include "constants/moves.h"
#include "constants/items.h"
static u32 AI_GetEffectiveness(u16 multiplier);
// Const Data
static const s8 sAiAbilityRatings[ABILITIES_COUNT] =
{
@ -439,9 +441,14 @@ static const u16 sOtherMoveCallingMoves[] =
};
// Functions
u16 GetAIChosenMove(u8 battlerId)
{
return (gBattleMons[battlerId].moves[gBattleStruct->aiMoveOrAction[battlerId]]);
}
bool32 WillAIStrikeFirst(void)
{
return (AI_WhoStrikesFirst(sBattler_AI, gBattlerTarget) == AI_IS_FASTER);
return (AI_WhoStrikesFirst(sBattler_AI, gBattlerTarget, AI_THINKING_STRUCT->moveConsidered) == AI_IS_FASTER);
}
bool32 AI_RandLessThan(u8 val)
@ -591,14 +598,14 @@ u32 GetHealthPercentage(u8 battlerId)
bool32 AtMaxHp(u8 battlerId)
{
if (GetHealthPercentage(battlerId) == 100)
if (AI_DATA->hpPercents[battlerId] == 100)
return TRUE;
return FALSE;
}
bool32 IsBattlerTrapped(u8 battler, bool8 checkSwitch)
{
u8 holdEffect = AI_GetHoldEffect(battler);
u8 holdEffect = AI_DATA->holdEffects[battler];
if (IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)
|| (checkSwitch && holdEffect == HOLD_EFFECT_SHED_SHELL)
|| (!checkSwitch && GetBattlerAbility(battler) == ABILITY_RUN_AWAY)
@ -637,7 +644,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler)
u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i];
if (gBattleMoves[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE)
return TRUE;
if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler) == AI_IS_SLOWER)
if (gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)) == AI_IS_SLOWER)
return TRUE;
}
return FALSE;
@ -659,7 +666,7 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split)
{
s32 i, moveType;
u32 usable = 0;
u32 unusable = CheckMoveLimitations(attacker, 0, MOVE_LIMITATIONS_ALL);
u32 unusable = AI_DATA->moveLimitations[attacker];
u16 *moves = GetMovesArray(attacker);
for (i = 0; i < MAX_MON_MOVES; i++)
@ -714,15 +721,17 @@ static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef)
return isCrit;
}
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, bool32 considerZPower)
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness, bool32 considerZPower)
{
s32 dmg, moveType, critDmg, normalDmg;
s8 critChance;
u16 effectivenessMultiplier;
if (considerZPower && IsViableZMove(battlerAtk, move))
{
//temporarily enable z moves for damage calcs
gBattleStruct->zmove.baseMoves[battlerAtk] = move;
gBattleStruct->zmove.active = TRUE; //temporarily enable z moves for damage calcs
gBattleStruct->zmove.active = TRUE;
}
SaveBattlerData(battlerAtk);
@ -735,56 +744,69 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, bool32 considerZPower)
SetTypeBeforeUsingMove(move, battlerAtk);
GET_MOVE_TYPE(move, moveType);
critChance = GetInverseCritChance(battlerAtk, battlerDef, move);
normalDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, FALSE, FALSE, FALSE);
critDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, TRUE, FALSE, FALSE);
if(critChance == -1)
dmg = normalDmg;
else
dmg = (critDmg + normalDmg * (critChance - 1)) / critChance;
// Handle dynamic move damage
switch (gBattleMoves[move].effect)
if (gBattleMoves[move].power)
{
case EFFECT_LEVEL_DAMAGE:
case EFFECT_PSYWAVE:
dmg = gBattleMons[battlerAtk].level * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1);
break;
case EFFECT_DRAGON_RAGE:
dmg = 40 * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1);
break;
case EFFECT_SONICBOOM:
dmg = 20 * (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND ? 2 : 1);
break;
case EFFECT_MULTI_HIT:
dmg *= (AI_DATA->atkAbility == ABILITY_SKILL_LINK ? 5 : 3);
break;
case EFFECT_TRIPLE_KICK:
dmg *= (AI_DATA->atkAbility == ABILITY_SKILL_LINK ? 6 : 5);
break;
case EFFECT_ENDEAVOR:
// If target has less HP than user, Endeavor does no damage
dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp);
break;
case EFFECT_SUPER_FANG:
dmg = (AI_DATA->atkAbility == ABILITY_PARENTAL_BOND
? max(2, gBattleMons[battlerDef].hp * 3 / 4)
: max(1, gBattleMons[battlerDef].hp / 2));
break;
case EFFECT_FINAL_GAMBIT:
dmg = gBattleMons[battlerAtk].hp;
break;
}
critChance = GetInverseCritChance(battlerAtk, battlerDef, move);
normalDmg = CalculateMoveDamageAndEffectiveness(move, battlerAtk, battlerDef, moveType, &effectivenessMultiplier);
critDmg = CalculateMoveDamage(move, battlerAtk, battlerDef, moveType, 0, TRUE, FALSE, FALSE);
// Handle other multi-strike moves
if (gBattleMoves[move].flags & FLAG_TWO_STRIKES)
dmg *= 2;
else if (move == MOVE_SURGING_STRIKES || (move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH))
dmg *= 3;
if (critChance == -1)
dmg = normalDmg;
else
dmg = (critDmg + normalDmg * (critChance - 1)) / critChance;
// Handle dynamic move damage
switch (gBattleMoves[move].effect)
{
case EFFECT_LEVEL_DAMAGE:
case EFFECT_PSYWAVE:
dmg = gBattleMons[battlerAtk].level * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1);
break;
case EFFECT_DRAGON_RAGE:
dmg = 40 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1);
break;
case EFFECT_SONICBOOM:
dmg = 20 * (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND ? 2 : 1);
break;
case EFFECT_MULTI_HIT:
dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 5 : 3);
break;
case EFFECT_TRIPLE_KICK:
dmg *= (AI_DATA->abilities[battlerAtk] == ABILITY_SKILL_LINK ? 6 : 5);
break;
case EFFECT_ENDEAVOR:
// If target has less HP than user, Endeavor does no damage
dmg = max(0, gBattleMons[battlerDef].hp - gBattleMons[battlerAtk].hp);
break;
case EFFECT_SUPER_FANG:
dmg = (AI_DATA->abilities[battlerAtk] == ABILITY_PARENTAL_BOND
? max(2, gBattleMons[battlerDef].hp * 3 / 4)
: max(1, gBattleMons[battlerDef].hp / 2));
break;
case EFFECT_FINAL_GAMBIT:
dmg = gBattleMons[battlerAtk].hp;
break;
}
// Handle other multi-strike moves
if (gBattleMoves[move].flags & FLAG_TWO_STRIKES)
dmg *= 2;
else if (move == MOVE_SURGING_STRIKES || (move == MOVE_WATER_SHURIKEN && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_ASH))
dmg *= 3;
if (dmg == 0)
dmg = 1;
}
else
{
dmg = 0;
}
RestoreBattlerData(battlerAtk);
RestoreBattlerData(battlerDef);
// convert multiper to AI_EFFECTIVENESS_xX
*typeEffectiveness = AI_GetEffectiveness(effectivenessMultiplier);
gBattleStruct->zmove.active = FALSE;
gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE;
@ -794,10 +816,10 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, bool32 considerZPower)
// Checks if one of the moves has side effects or perks
static u32 WhichMoveBetter(u32 move1, u32 move2)
{
s32 defAbility = AI_GetAbility(gBattlerTarget);
s32 defAbility = AI_DATA->abilities[gBattlerTarget];
// Check if physical moves hurt.
if (AI_GetHoldEffect(sBattler_AI) != HOLD_EFFECT_PROTECTIVE_PADS
if (AI_DATA->holdEffects[sBattler_AI] != HOLD_EFFECT_PROTECTIVE_PADS
&& (BATTLE_HISTORY->itemEffects[gBattlerTarget] == HOLD_EFFECT_ROCKY_HELMET
|| defAbility == ABILITY_IRON_BARBS || defAbility == ABILITY_ROUGH_SKIN))
{
@ -877,7 +899,7 @@ u8 GetMoveDamageResult(u16 move)
&& sIgnoredPowerfulMoveEffects[i] == IGNORED_MOVES_END
&& gBattleMoves[gBattleMons[sBattler_AI].moves[checkedMove]].power != 0)
{
moveDmgs[checkedMove] = AI_THINKING_STRUCT->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove];
moveDmgs[checkedMove] = AI_DATA->simulatedDmg[sBattler_AI][gBattlerTarget][checkedMove];
}
else
{
@ -933,7 +955,7 @@ u8 GetMoveDamageResult(u16 move)
u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef)
{
int bestDmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
int bestDmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
return (bestDmg * 100) / gBattleMons[battlerDef].maxHP;
}
@ -959,39 +981,34 @@ 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;
gMoveResultFlags = 0;
gCurrentMove = move;
effectivenessMultiplier = AI_GetTypeEffectiveness(gCurrentMove, battlerAtk, battlerDef);
return AI_GetEffectiveness(AI_GetTypeEffectiveness(move, battlerAtk, battlerDef));
}
switch (effectivenessMultiplier)
static u32 AI_GetEffectiveness(u16 multiplier)
{
switch (multiplier)
{
case UQ_4_12(0.0):
default:
damageVar = AI_EFFECTIVENESS_x0;
break;
return AI_EFFECTIVENESS_x0;
case UQ_4_12(0.125):
return AI_EFFECTIVENESS_x0_125;
case UQ_4_12(0.25):
damageVar = AI_EFFECTIVENESS_x0_25;
break;
return AI_EFFECTIVENESS_x0_25;
case UQ_4_12(0.5):
damageVar = AI_EFFECTIVENESS_x0_5;
break;
return AI_EFFECTIVENESS_x0_5;
case UQ_4_12(1.0):
damageVar = AI_EFFECTIVENESS_x1;
break;
default:
return AI_EFFECTIVENESS_x1;
case UQ_4_12(2.0):
damageVar = AI_EFFECTIVENESS_x2;
break;
return AI_EFFECTIVENESS_x2;
case UQ_4_12(4.0):
damageVar = AI_EFFECTIVENESS_x4;
break;
return AI_EFFECTIVENESS_x4;
case UQ_4_12(8.0):
return AI_EFFECTIVENESS_x8;
}
return damageVar;
}
/* Checks to see if AI will move ahead of another battler
@ -999,23 +1016,25 @@ u8 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
* AI_IS_FASTER: is user(ai) faster
* AI_IS_SLOWER: is target faster
*/
u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2)
u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2, u16 moveConsidered)
{
u32 fasterAI = 0, fasterPlayer = 0, i;
s8 prioAI = 0;
s8 prioPlayer = 0;
s8 prioBattler2 = 0;
u16 *battler2Moves = GetMovesArray(battler2);
// Check move priorities first.
prioAI = GetMovePriority(battlerAI, AI_THINKING_STRUCT->moveConsidered);
prioAI = GetMovePriority(battlerAI, moveConsidered);
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (gBattleMons[battler2].moves[i] == 0 || gBattleMons[battler2].moves[i] == 0xFFFF)
if (battler2Moves[i] == 0 || battler2Moves[i] == 0xFFFF)
continue;
prioPlayer = GetMovePriority(battler2, gBattleMons[battler2].moves[i]);
if (prioAI > prioPlayer)
prioBattler2 = GetMovePriority(battler2, battler2Moves[i]);
if (prioAI > prioBattler2)
fasterAI++;
else if (prioPlayer > prioAI)
else if (prioBattler2 > prioAI)
fasterPlayer++;
}
@ -1029,6 +1048,8 @@ u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2)
}
else
{
if (prioAI > prioBattler2)
return AI_IS_FASTER; // if we didn't know any of battler 2's moves to compare priorities, assume they don't have a prio+ move
// Priorities are the same(at least comparing to moves the AI is aware of), decide by speed.
if (GetWhoStrikesFirst(battlerAI, battler2, TRUE) == 0)
return AI_IS_FASTER;
@ -1041,13 +1062,13 @@ u8 AI_WhoStrikesFirst(u8 battlerAI, u8 battler2)
bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk)
{
s32 i, dmg;
u32 unusable = CheckMoveLimitations(battlerDef, 0, MOVE_LIMITATIONS_ALL);
u32 unusable = AI_DATA->moveLimitations[battlerDef];
u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef];
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i])
&& AI_CalcDamage(moves[i], battlerDef, battlerAtk, FALSE) >= gBattleMons[battlerAtk].hp)
&& AI_DATA->simulatedDmg[battlerDef][battlerAtk][moves[i]] >= gBattleMons[battlerAtk].hp)
{
return TRUE;
}
@ -1061,7 +1082,7 @@ bool32 CanTargetFaintAi(u8 battlerDef, u8 battlerAtk)
bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits)
{
s32 i, dmg;
u32 moveLimitations = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL);
u32 moveLimitations = AI_DATA->moveLimitations[battlerAtk];
u16 *moves = gBattleMons[battlerAtk].moves;
for (i = 0; i < MAX_MON_MOVES; i++)
@ -1069,7 +1090,7 @@ bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits)
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(moveLimitations & gBitTable[i]))
{
// Use the pre-calculated value in simulatedDmg instead of re-calculating it
dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i];
dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i];
if (numHits)
dmg *= numHits;
@ -1085,9 +1106,13 @@ bool32 CanAIFaintTarget(u8 battlerAtk, u8 battlerDef, u8 numHits)
bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits)
{
s32 i, dmg;
u32 unusable = CheckMoveLimitations(battlerDef, 0, MOVE_LIMITATIONS_ALL);
u8 effectiveness;
u32 unusable = AI_DATA->moveLimitations[battlerDef];
if (move != MOVE_NONE && move != 0xFFFF && !(unusable & gBitTable[i]) && AI_CalcDamage(move, battlerDef, battlerAtk, FALSE) >= gBattleMons[battlerAtk].hp)
if (move != MOVE_NONE
&& move != 0xFFFF
&& !(unusable & gBitTable[i])
&& AI_CalcDamage(move, battlerDef, battlerAtk, &effectiveness, FALSE) >= gBattleMons[battlerAtk].hp)
return TRUE;
return FALSE;
@ -1097,7 +1122,7 @@ bool32 CanMoveFaintBattler(u16 move, u8 battlerDef, u8 battlerAtk, u8 nHits)
bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgMod)
{
u32 i;
u32 unusable = CheckMoveLimitations(battlerDef, 0, MOVE_LIMITATIONS_ALL);
u32 unusable = AI_DATA->moveLimitations[battlerDef];
s32 dmg;
u16 *moves = gBattleResources->battleHistory->usedMoves[battlerDef];
u32 hpCheck = gBattleMons[battlerAtk].hp + hpMod;
@ -1107,7 +1132,7 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM
for (i = 0; i < MAX_MON_MOVES; i++)
{
dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][i];
dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][i];
if (dmgMod)
dmg *= dmgMod;
@ -1122,9 +1147,9 @@ bool32 CanTargetFaintAiWithMod(u8 battlerDef, u8 battlerAtk, s32 hpMod, s32 dmgM
bool32 AI_IsAbilityOnSide(u32 battlerId, u32 ability)
{
if (IsBattlerAlive(battlerId) && AI_GetAbility(battlerId) == ability)
if (IsBattlerAlive(battlerId) && AI_DATA->abilities[battlerId] == ability)
return TRUE;
else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_GetAbility(BATTLE_PARTNER(battlerId)) == ability)
else if (IsBattlerAlive(BATTLE_PARTNER(battlerId)) && AI_DATA->abilities[BATTLE_PARTNER(battlerId)] == ability)
return TRUE;
else
return FALSE;
@ -1181,7 +1206,7 @@ u16 AI_GetHoldEffect(u32 battlerId)
return HOLD_EFFECT_NONE;
if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)
return HOLD_EFFECT_NONE;
if (AI_GetAbility(battlerId) == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID))
if (AI_DATA->abilities[battlerId] == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID))
return HOLD_EFFECT_NONE;
return holdEffect;
@ -1199,7 +1224,7 @@ bool32 AI_IsTerrainAffected(u8 battlerId, u32 flags)
// different from IsBattlerGrounded in that we don't always know battler's hold effect or ability
bool32 AI_IsBattlerGrounded(u8 battlerId)
{
u32 holdEffect = AI_GetHoldEffect(battlerId);
u32 holdEffect = AI_DATA->holdEffects[battlerId];
if (holdEffect == HOLD_EFFECT_IRON_BALL)
return TRUE;
@ -1215,7 +1240,7 @@ bool32 AI_IsBattlerGrounded(u8 battlerId)
return FALSE;
else if (holdEffect == HOLD_EFFECT_AIR_BALLOON)
return FALSE;
else if (AI_GetAbility(battlerId) == ABILITY_LEVITATE)
else if (AI_DATA->abilities[battlerId] == ABILITY_LEVITATE)
return FALSE;
else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING))
return FALSE;
@ -1250,14 +1275,17 @@ bool32 AI_WeatherHasEffect(void)
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_NEGATE_UNAWARE)
return TRUE; // AI doesn't understand weather supression (handicap)
// need to manually check since we don't necessarily know opponent ability
for (i = 0; i < gBattlersCount; i++)
{
if (IsBattlerAlive(i)
&& (AI_GetAbility(i) == ABILITY_AIR_LOCK || AI_GetAbility(i) == ABILITY_CLOUD_NINE))
return FALSE;
}
return TRUE;
return WEATHER_HAS_EFFECT; // weather damping abilities are announced
}
u32 AI_GetBattlerMoveTargetType(u8 battlerId, u16 move)
{
u32 target;
if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE && AI_IsTerrainAffected(battlerId, STATUS_FIELD_PSYCHIC_TERRAIN))
return MOVE_TARGET_BOTH;
else
return gBattleMoves[move].target;
}
bool32 IsAromaVeilProtectedMove(u16 move)
@ -1359,70 +1387,10 @@ bool32 IsMoveRedirectionPrevented(u16 move, u16 atkAbility)
return FALSE;
}
// differs from GetTotalAccuracy in that we need to check AI history for item, ability, etc
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u8 atkHoldEffect, u8 defHoldEffect, u16 move)
u32 AI_GetMoveAccuracy(u8 battlerAtk, u8 battlerDef, u16 move)
{
u32 calc, moveAcc, atkParam, defParam;
s8 buff, accStage, evasionStage;
gPotentialItemEffectBattler = battlerDef;
accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION];
if (atkAbility == ABILITY_UNAWARE)
evasionStage = DEFAULT_STAT_STAGE;
if (gBattleMoves[move].flags & FLAG_STAT_STAGES_IGNORED)
evasionStage = DEFAULT_STAT_STAGE;
if (defAbility == ABILITY_UNAWARE)
accStage = DEFAULT_STAT_STAGE;
if (gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT || gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED)
buff = accStage;
else
buff = accStage + DEFAULT_STAT_STAGE - evasionStage;
if (buff < MIN_STAT_STAGE)
buff = MIN_STAT_STAGE;
if (buff > MAX_STAT_STAGE)
buff = MAX_STAT_STAGE;
moveAcc = gBattleMoves[move].accuracy;
// Check Thunder and Hurricane on sunny weather.
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SUN
&& (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE))
moveAcc = 50;
// Check Wonder Skin.
if (defAbility == ABILITY_WONDER_SKIN && gBattleMoves[move].power == 0)
moveAcc = 50;
calc = gAccuracyStageRatios[buff].dividend * moveAcc;
calc /= gAccuracyStageRatios[buff].divisor;
if (atkAbility == ABILITY_COMPOUND_EYES)
calc = (calc * 130) / 100; // 1.3 compound eyes boost
else if (atkAbility == ABILITY_VICTORY_STAR)
calc = (calc * 110) / 100; // 1.1 victory star boost
if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) && GetBattlerAbility(BATTLE_PARTNER(battlerAtk)) == ABILITY_VICTORY_STAR)
calc = (calc * 110) / 100; // 1.1 ally's victory star boost
if (defAbility == ABILITY_SAND_VEIL && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM)
calc = (calc * 80) / 100; // 1.2 sand veil loss
else if (defAbility == ABILITY_SNOW_CLOAK && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_HAIL)
calc = (calc * 80) / 100; // 1.2 snow cloak loss
else if (defAbility == ABILITY_TANGLED_FEET && gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
calc = (calc * 50) / 100; // 1.5 tangled feet loss
if (atkAbility == ABILITY_HUSTLE && IS_MOVE_PHYSICAL(move))
calc = (calc * 80) / 100; // 1.2 hustle loss
if (defHoldEffect == HOLD_EFFECT_EVASION_UP)
calc = (calc * (100 - defParam)) / 100;
if (atkHoldEffect == HOLD_EFFECT_WIDE_LENS)
calc = (calc * (100 + atkParam)) / 100;
else if (atkHoldEffect == HOLD_EFFECT_ZOOM_LENS && GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef));
calc = (calc * (100 + atkParam)) / 100;
return calc;
return GetTotalAccuracy(battlerAtk, battlerDef, move, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef],
AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]);
}
bool32 IsSemiInvulnerable(u8 battlerDef, u16 move)
@ -1450,7 +1418,7 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move)
if (gStatuses3[battlerDef] & STATUS3_ALWAYS_HITS || gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
return TRUE;
if (AI_GetAbility(battlerDef) == ABILITY_NO_GUARD || AI_GetAbility(battlerAtk) == ABILITY_NO_GUARD)
if (AI_DATA->abilities[battlerDef] == ABILITY_NO_GUARD || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD)
return TRUE;
if (B_TOXIC_NEVER_MISS >= GEN_6 && gBattleMoves[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
@ -1475,12 +1443,13 @@ bool32 IsMoveEncouragedToHit(u8 battlerAtk, u8 battlerDef, u16 move)
return FALSE;
}
bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u32 accuracy, u16 move)
bool32 ShouldTryOHKO(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbility, u16 move)
{
u32 holdEffect = AI_GetHoldEffect(battlerDef);
u32 holdEffect = AI_DATA->holdEffects[battlerDef];
u32 accuracy = AI_GetMoveAccuracy(battlerAtk, battlerDef, move);
gPotentialItemEffectBattler = battlerDef;
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < GetBattlerHoldEffectParam(battlerDef))
if (holdEffect == HOLD_EFFECT_FOCUS_BAND && (Random() % 100) < AI_DATA->holdEffectParams[battlerDef])
return FALSE; //probabilistically speaking, focus band should activate so dont OHKO
else if (holdEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef))
return FALSE;
@ -1498,6 +1467,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;
}
@ -1514,7 +1487,6 @@ bool32 ShouldSetSandstorm(u8 battler, u16 ability, u16 holdEffect)
if (ability == ABILITY_SAND_VEIL
|| ability == ABILITY_SAND_RUSH
|| ability == ABILITY_SAND_FORCE
|| ability == ABILITY_SAND_FORCE
|| ability == ABILITY_OVERCOAT
|| ability == ABILITY_MAGIC_GUARD
|| holdEffect == HOLD_EFFECT_SAFETY_GOGGLES
@ -1608,7 +1580,7 @@ void ProtectChecks(u8 battlerAtk, u8 battlerDef, u16 move, u16 predictedMove, s1
{
// TODO more sophisticated logic
u16 predictedEffect = gBattleMoves[predictedMove].effect;
u8 defAbility = AI_GetAbility(battlerDef);
u8 defAbility = AI_DATA->abilities[battlerDef];
u32 uses = gDisableStructs[battlerAtk].protectUses;
/*if (GetMoveResultFlags(predictedMove) & (MOVE_RESULT_NO_EFFECT | MOVE_RESULT_MISSED))
@ -1823,7 +1795,7 @@ bool32 ShouldLowerEvasion(u8 battlerAtk, u8 battlerDef, u16 defAbility)
bool32 CanIndexMoveFaintTarget(u8 battlerAtk, u8 battlerDef, u8 index, u8 numHits)
{
s32 dmg = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][index];
s32 dmg = AI_DATA->simulatedDmg[battlerAtk][battlerDef][index];
if (numHits)
dmg *= numHits;
@ -1917,7 +1889,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32
{
s32 i;
u16 *moves = GetMovesArray(battlerAtk);
u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL);
u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk];
for (i = 0; i < MAX_MON_MOVES; i++)
{
@ -1929,10 +1901,10 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32
if (ignoreStatus && IS_MOVE_STATUS(moves[i]))
continue;
else if ((!IS_MOVE_STATUS(moves[i]) && gBattleMoves[moves[i]].accuracy == 0)
|| gBattleMoves[moves[i]].target & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD))
|| AI_GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD))
continue;
if (AI_GetMoveAccuracy(battlerAtk, battlerDef, atkAbility, defAbility, atkHoldEffect, defHoldEffect, moves[i]) <= accCheck)
if (AI_GetMoveAccuracy(battlerAtk, battlerDef, moves[i]) <= accCheck)
return TRUE;
}
}
@ -1942,7 +1914,7 @@ bool32 HasMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef, u8 accCheck, bool32
bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef)
{
u8 moveLimitations = CheckMoveLimitations(battlerAtk, 0, MOVE_LIMITATIONS_ALL);
u8 moveLimitations = AI_DATA->moveLimitations[battlerAtk];
u32 i;
u16 *moves = GetMovesArray(battlerAtk);
@ -1953,7 +1925,7 @@ bool32 HasSleepMoveWithLowAccuracy(u8 battlerAtk, u8 battlerDef)
if (!(gBitTable[i] & moveLimitations))
{
if (gBattleMoves[moves[i]].effect == EFFECT_SLEEP
&& AI_GetMoveAccuracy(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect, moves[i]) < 85)
&& AI_GetMoveAccuracy(battlerAtk, battlerDef, moves[i]) < 85)
return TRUE;
}
}
@ -2268,7 +2240,7 @@ static u32 GetTrapDamage(u8 battlerId)
{
// ai has no knowledge about turns remaining
u32 damage = 0;
u32 holdEffect = AI_GetHoldEffect(gBattleStruct->wrappedBy[battlerId]);
u32 holdEffect = AI_DATA->holdEffects[gBattleStruct->wrappedBy[battlerId]];
if (gBattleMons[battlerId].status2 & STATUS2_WRAPPED)
{
if (holdEffect == HOLD_EFFECT_BINDING_BAND)
@ -2286,7 +2258,7 @@ static u32 GetPoisonDamage(u8 battlerId)
{
u32 damage = 0;
if (AI_GetAbility(battlerId) == ABILITY_POISON_HEAL)
if (AI_DATA->abilities[battlerId] == ABILITY_POISON_HEAL)
return damage;
if (gBattleMons[battlerId].status1 & STATUS1_POISON)
@ -2332,8 +2304,8 @@ static bool32 BattlerAffectedByHail(u8 battlerId, u16 ability)
static u32 GetWeatherDamage(u8 battlerId)
{
u32 ability = AI_GetAbility(battlerId);
u32 holdEffect = AI_GetHoldEffect(battlerId);
u32 ability = AI_DATA->abilities[battlerId];
u32 holdEffect = AI_DATA->holdEffects[battlerId];
u32 damage = 0;
if (!AI_WeatherHasEffect())
return 0;
@ -2367,7 +2339,7 @@ u32 GetBattlerSecondaryDamage(u8 battlerId)
{
u32 secondaryDamage;
if (AI_GetAbility(battlerId) == ABILITY_MAGIC_GUARD)
if (AI_DATA->abilities[battlerId] == ABILITY_MAGIC_GUARD)
return FALSE;
secondaryDamage = GetLeechSeedDamage(battlerId)
@ -2483,7 +2455,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
/*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost)
return PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/
if (AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER) // Attacker goes first
if (AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) // Attacker goes first
{
if (!CanAIFaintTarget(battlerAtk, battlerDef, 0)) // Can't KO foe otherwise
{
@ -2494,13 +2466,13 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
return PIVOT; // Won't get the two turns, pivot
if (!IS_MOVE_STATUS(move) && (shouldSwitch
|| (AtMaxHp(battlerDef) && (AI_DATA->defHoldEffect == HOLD_EFFECT_FOCUS_SASH
|| (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| defAbility == ABILITY_STURDY || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD))))
return PIVOT; // pivot to break sash/sturdy/multiscale
}
else if (!hasStatBoost)
{
if (!IS_MOVE_STATUS(move) && (AtMaxHp(battlerDef) && (AI_DATA->defHoldEffect == HOLD_EFFECT_FOCUS_SASH
if (!IS_MOVE_STATUS(move) && (AtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|| defAbility == ABILITY_STURDY || defAbility == ABILITY_MULTISCALE || defAbility == ABILITY_SHADOW_SHIELD)))
return PIVOT; // pivot to break sash/sturdy/multiscale
@ -2511,7 +2483,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
if (gSideStatuses[battlerAtk] & SIDE_STATUS_SPIKES && switchScore >= SWITCHING_INCREASE_CAN_REMOVE_HAZARDS)
return PIVOT;*/
/*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) && switchScore >= SWITCHING_INCREASE_WALLS_FOE)
/*if (BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) && switchScore >= SWITCHING_INCREASE_WALLS_FOE)
return PIVOT;*/
/*if (IsClassDamager(class) && switchScore >= SWITCHING_INCREASE_HAS_SUPER_EFFECTIVE_MOVE)
@ -2554,7 +2526,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
{
if (CanAIFaintTarget(battlerAtk, battlerDef, 0))
{
if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility))
if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]))
return CAN_TRY_PIVOT; // Use this move to KO if you must
}
else // Can't KO the foe
@ -2566,7 +2538,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
{
if (CanAIFaintTarget(battlerAtk, battlerDef, 0))
{
if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility) // This is the only move that can KO
if (!BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk]) // This is the only move that can KO
&& !hasStatBoost) //You're not wasting a valuable stat boost
{
return CAN_TRY_PIVOT;
@ -2577,7 +2549,7 @@ bool32 ShouldPivot(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u8 mo
// can knock out foe in 2 hits
if (IS_MOVE_STATUS(move) && (shouldSwitch //Damaging move
//&& (switchScore >= SWITCHING_INCREASE_RESIST_ALL_MOVES + SWITCHING_INCREASE_KO_FOE //remove hazards
|| (AI_DATA->defHoldEffect == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef))))
|| (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AtMaxHp(battlerDef))))
return DONT_PIVOT; // Pivot to break the sash
else
return CAN_TRY_PIVOT;
@ -2646,7 +2618,7 @@ bool32 CanKnockOffItem(u8 battler, u16 item)
)) && GetBattlerSide(battler) == B_SIDE_PLAYER)
return FALSE;
if (AI_GetAbility(battler) == ABILITY_STICKY_HOLD)
if (AI_DATA->abilities[battler] == ABILITY_STICKY_HOLD)
return FALSE;
if (!CanBattlerGetOrLoseItem(battler, item))
@ -2693,13 +2665,13 @@ bool32 AI_CanPutToSleep(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move,
static bool32 AI_CanPoisonType(u8 battlerAttacker, u8 battlerTarget)
{
return ((AI_GetAbility(battlerAttacker) == ABILITY_CORROSION && gBattleMoves[gCurrentMove].split == SPLIT_STATUS)
return ((AI_DATA->abilities[battlerAttacker] == ABILITY_CORROSION && gBattleMoves[gCurrentMove].split == SPLIT_STATUS)
|| !(IS_BATTLER_OF_TYPE(battlerTarget, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerTarget, TYPE_STEEL)));
}
static bool32 AI_CanBePoisoned(u8 battlerAtk, u8 battlerDef)
{
u16 ability = AI_GetAbility(battlerDef);
u16 ability = AI_DATA->abilities[battlerDef];
if (!(AI_CanPoisonType(battlerAtk, battlerDef))
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
@ -2738,7 +2710,7 @@ bool32 AI_CanPoison(u8 battlerAtk, u8 battlerDef, u16 defAbility, u16 move, u16
return FALSE;
else if (defAbility != ABILITY_CORROSION && (IS_BATTLER_OF_TYPE(battlerDef, TYPE_POISON) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL)))
return FALSE;
else if (IsValidDoubleBattle(battlerAtk) && AI_GetAbility(BATTLE_PARTNER(battlerDef)) == ABILITY_PASTEL_VEIL)
else if (IsValidDoubleBattle(battlerAtk) && AI_DATA->abilities[BATTLE_PARTNER(battlerDef)] == ABILITY_PASTEL_VEIL)
return FALSE;
return TRUE;
@ -2843,7 +2815,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili
{
if (defAbility == ABILITY_INNER_FOCUS
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move)
|| AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_SLOWER) // Opponent goes first
|| AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_SLOWER) // Opponent goes first
{
return 0; // don't try to flinch
}
@ -2863,7 +2835,7 @@ u32 ShouldTryToFlinch(u8 battlerAtk, u8 battlerDef, u16 atkAbility, u16 defAbili
bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move)
{
if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->defAbility))
if (BattlerWillFaintFromSecondaryDamage(battlerDef, AI_DATA->abilities[battlerDef]))
return TRUE; // battler is taking secondary damage with low HP
if (AI_THINKING_STRUCT->aiFlags & AI_FLAG_STALL)
@ -2877,11 +2849,11 @@ bool32 ShouldTrap(u8 battlerAtk, u8 battlerDef, u16 move)
bool32 ShouldFakeOut(u8 battlerAtk, u8 battlerDef, u16 move)
{
if (AI_DATA->atkHoldEffect == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0)
if (AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_CHOICE_BAND && CountUsablePartyMons(battlerAtk) == 0)
return FALSE; // don't lock attacker into fake out if can't switch out
if (gDisableStructs[battlerAtk].isFirstTurn
&& ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->atkAbility, AI_DATA->defAbility, move)
&& ShouldTryToFlinch(battlerAtk, battlerDef, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], move)
&& !DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
return TRUE;
@ -2967,7 +2939,7 @@ bool32 ShouldUseRecoilMove(u8 battlerAtk, u8 battlerDef, u32 recoilDmg, u8 moveI
bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage)
{
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER)
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
{
// using item or user goes first
u8 healPercent = (gBattleMoves[move].argument == 0) ? 50 : gBattleMoves[move].argument;
@ -2979,7 +2951,7 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage)
if (CanTargetFaintAi(battlerDef, battlerAtk)
&& !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healDmg, 0))
return TRUE; // target can faint attacker unless they heal
else if (!CanTargetFaintAi(battlerDef, battlerAtk) && GetHealthPercentage(battlerAtk) < 60 && (Random() % 3))
else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3))
return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing
}
else
@ -2994,10 +2966,10 @@ bool32 ShouldAbsorb(u8 battlerAtk, u8 battlerDef, u16 move, s32 damage)
bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent)
{
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef) == AI_IS_FASTER)
if (move == 0xFFFF || AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER)
{
// using item or user going first
s32 damage = AI_THINKING_STRUCT->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
s32 damage = AI_DATA->simulatedDmg[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex];
s32 healAmount = (healPercent * damage) / 100;
if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK)
healAmount = 0;
@ -3005,7 +2977,7 @@ bool32 ShouldRecover(u8 battlerAtk, u8 battlerDef, u16 move, u8 healPercent)
if (CanTargetFaintAi(battlerDef, battlerAtk)
&& !CanTargetFaintAiWithMod(battlerDef, battlerAtk, healAmount, 0))
return TRUE; // target can faint attacker unless they heal
else if (!CanTargetFaintAi(battlerDef, battlerAtk) && GetHealthPercentage(battlerAtk) < 60 && (Random() % 3))
else if (!CanTargetFaintAi(battlerDef, battlerAtk) && AI_DATA->hpPercents[battlerAtk] < 60 && (Random() % 3))
return TRUE; // target can't faint attacker at all, attacker health is about half, 2/3rds rate of encouraging healing
}
return FALSE;
@ -3048,14 +3020,14 @@ bool32 IsValidDoubleBattle(u8 battlerAtk)
return FALSE;
}
u16 GetAllyChosenMove(void)
u16 GetAllyChosenMove(u8 battlerId)
{
u8 partnerBattler = BATTLE_PARTNER(sBattler_AI);
u8 partnerBattler = BATTLE_PARTNER(battlerId);
if (!IsBattlerAlive(partnerBattler) || !IsBattlerAIControlled(partnerBattler))
return MOVE_NONE; // TODO: prediction?
else if (partnerBattler > sBattler_AI) // Battler with the lower id chooses the move first.
return MOVE_NONE;
else if (partnerBattler > battlerId) // Battler with the lower id chooses the move first.
return gLastMoves[partnerBattler];
else
return gBattleMons[partnerBattler].moves[gBattleStruct->chosenMovePositions[partnerBattler]];
}
@ -3193,7 +3165,7 @@ bool32 ShouldUseWishAromatherapy(u8 battlerAtk, u8 battlerDef, u16 move)
party = gEnemyParty;
if (CountUsablePartyMons(battlerAtk) == 0
&& (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->atkAbility)))
&& (CanTargetFaintAi(battlerDef, battlerAtk) || BattlerWillFaintFromSecondaryDamage(battlerAtk, AI_DATA->abilities[battlerAtk])))
return FALSE; // Don't heal if last mon and will faint
for (i = 0; i < PARTY_SIZE; i++)
@ -3250,13 +3222,14 @@ s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon
{
s32 dmg;
u32 i;
u8 effectiveness;
struct BattlePokemon *battleMons = Alloc(sizeof(struct BattlePokemon) * MAX_BATTLERS_COUNT);
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
battleMons[i] = gBattleMons[i];
PokemonToBattleMon(mon, &gBattleMons[battlerAtk]);
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, FALSE);
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, FALSE);
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
gBattleMons[i] = battleMons[i];
@ -3451,10 +3424,10 @@ bool32 IsRecycleEncouragedItem(u16 item)
#define STAT_UP_STAGE 10
void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
{
if (AI_DATA->atkAbility == ABILITY_CONTRARY)
if (AI_DATA->abilities[battlerAtk] == ABILITY_CONTRARY)
return;
if (GetHealthPercentage(battlerAtk) < 80 && AI_RandLessThan(128))
if (AI_DATA->hpPercents[battlerAtk] < 80 && AI_RandLessThan(128))
return;
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
@ -3463,7 +3436,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
switch (statId)
{
case STAT_ATK:
if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && GetHealthPercentage(battlerAtk) > 40)
if (HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL) && AI_DATA->hpPercents[battlerAtk] > 40)
{
if (gBattleMons[battlerAtk].statStages[STAT_ATK] < STAT_UP_2_STAGE)
*score += 2;
@ -3475,7 +3448,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
break;
case STAT_DEF:
if ((HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL)|| IS_MOVE_PHYSICAL(gLastMoves[battlerDef]))
&& GetHealthPercentage(battlerAtk) > 70)
&& AI_DATA->hpPercents[battlerAtk] > 70)
{
if (gBattleMons[battlerAtk].statStages[STAT_DEF] < STAT_UP_2_STAGE)
*score += 2; // seems better to raise def at higher HP
@ -3493,7 +3466,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
}
break;
case STAT_SPATK:
if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && GetHealthPercentage(battlerAtk) > 40)
if (HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL) && AI_DATA->hpPercents[battlerAtk] > 40)
{
if (gBattleMons[battlerAtk].statStages[STAT_SPATK] < STAT_UP_2_STAGE)
*score += 2;
@ -3503,7 +3476,7 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
break;
case STAT_SPDEF:
if ((HasMoveWithSplit(battlerDef, SPLIT_SPECIAL) || IS_MOVE_SPECIAL(gLastMoves[battlerDef]))
&& GetHealthPercentage(battlerAtk) > 70)
&& AI_DATA->hpPercents[battlerAtk] > 70)
{
if (gBattleMons[battlerAtk].statStages[STAT_SPDEF] < STAT_UP_2_STAGE)
*score += 2; // seems better to raise spdef at higher HP
@ -3512,13 +3485,13 @@ void IncreaseStatUpScore(u8 battlerAtk, u8 battlerDef, u8 statId, s16 *score)
}
break;
case STAT_ACC:
if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect))
if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 80, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]))
*score += 2; // has moves with less than 80% accuracy
else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->atkAbility, AI_DATA->defAbility, AI_DATA->atkHoldEffect, AI_DATA->defHoldEffect))
else if (HasMoveWithLowAccuracy(battlerAtk, battlerDef, 90, TRUE, AI_DATA->abilities[battlerAtk], AI_DATA->abilities[battlerDef], AI_DATA->holdEffects[battlerAtk], AI_DATA->holdEffects[battlerDef]))
*(score)++;
break;
case STAT_EVASION:
if (!BattlerWillFaintFromWeather(battlerAtk, AI_DATA->atkAbility))
if (!BattlerWillFaintFromWeather(battlerAtk, AI_DATA->abilities[battlerAtk]))
{
if (!GetBattlerSecondaryDamage(battlerAtk) && !(gStatuses3[battlerAtk] & STATUS3_ROOTED))
*score += 2;
@ -3534,7 +3507,7 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove) && GetHealthPercentage(battlerDef) > 20)
if (AI_CanPoison(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove) && AI_DATA->hpPercents[battlerDef] > 20)
{
if (!HasDamagingMove(battlerDef))
*score += 2;
@ -3545,7 +3518,7 @@ void IncreasePoisonScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
if (HasMoveEffect(battlerAtk, EFFECT_VENOSHOCK)
|| HasMoveEffect(battlerAtk, EFFECT_HEX)
|| HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH)
|| AI_DATA->atkAbility == ABILITY_MERCILESS)
|| AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS)
*(score) += 2;
else
*(score)++;
@ -3557,7 +3530,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove))
if (AI_CanBurn(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove))
{
(*score)++; // burning is good
if (HasMoveWithSplit(battlerDef, SPLIT_PHYSICAL))
@ -3566,7 +3539,7 @@ void IncreaseBurnScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
*score += 2; // burning the target to stay alive is cool
}
if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX))
if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_HEX))
(*score)++;
}
}
@ -3576,7 +3549,7 @@ void IncreaseParalyzeScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove))
if (AI_CanParalyze(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove))
{
u8 atkSpeed = GetBattlerTotalSpeedStat(battlerAtk);
u8 defSpeed = GetBattlerTotalSpeedStat(battlerDef);
@ -3597,7 +3570,7 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->defAbility, move, AI_DATA->partnerMove))
if (AI_CanPutToSleep(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_DATA->partnerMove))
*score += 2;
else
return;
@ -3606,7 +3579,7 @@ void IncreaseSleepScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
&& !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK)))
(*score)++;
if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(AI_DATA->battlerAtkPartner, EFFECT_HEX))
if (HasMoveEffect(battlerAtk, EFFECT_HEX) || HasMoveEffect(BATTLE_PARTNER(battlerAtk), EFFECT_HEX))
(*score)++;
}
@ -3615,13 +3588,13 @@ void IncreaseConfusionScore(u8 battlerAtk, u8 battlerDef, u16 move, s16 *score)
if ((AI_THINKING_STRUCT->aiFlags & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0))
return;
if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->defAbility, AI_DATA->battlerAtkPartner, move, AI_DATA->partnerMove)
&& AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_CONFUSION
&& AI_DATA->defHoldEffect != HOLD_EFFECT_CURE_STATUS)
if (AI_CanConfuse(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], BATTLE_PARTNER(battlerAtk), move, AI_DATA->partnerMove)
&& AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_CONFUSION
&& AI_DATA->holdEffects[battlerDef] != HOLD_EFFECT_CURE_STATUS)
{
if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|| (AI_DATA->atkAbility == ABILITY_SERENE_GRACE && HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT)))
|| (AI_DATA->abilities[battlerAtk] == ABILITY_SERENE_GRACE && HasMoveEffect(battlerAtk, EFFECT_FLINCH_HIT)))
*score += 3;
else
*score += 2;
@ -3648,6 +3621,8 @@ bool32 ShouldUseZMove(u8 battlerAtk, u8 battlerDef, u16 chosenMove)
if (IsViableZMove(battlerAtk, chosenMove))
{
u8 effectiveness;
#ifdef POKEMON_EXPANSION
if (gBattleMons[battlerDef].ability == ABILITY_DISGUISE && gBattleMons[battlerDef].species == SPECIES_MIMIKYU)
return FALSE; // Don't waste a Z-Move busting disguise
@ -3660,7 +3635,7 @@ bool32 ShouldUseZMove(u8 battlerAtk, u8 battlerDef, u16 chosenMove)
else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove))
return FALSE;
if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamage(chosenMove, battlerAtk, battlerDef, FALSE) >= gBattleMons[battlerDef].hp)
if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamage(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE) >= gBattleMons[battlerDef].hp)
return FALSE; // don't waste damaging z move if can otherwise faint target
return TRUE;

View File

@ -204,7 +204,7 @@ void DoMoveAnim(u16 move)
gBattleAnimAttacker = gBattlerAttacker;
gBattleAnimTarget = gBattlerTarget;
// Make sure the anim target of moves hitting everyone is at the opposite side.
if (gBattleMoves[move].target & MOVE_TARGET_FOES_AND_ALLY && IsDoubleBattle())
if (GetBattlerMoveTargetType(gBattlerAttacker, move) & MOVE_TARGET_FOES_AND_ALLY && IsDoubleBattle())
{
while (GET_BATTLER_SIDE(gBattleAnimAttacker) == GET_BATTLER_SIDE(gBattleAnimTarget))
{

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
@ -1396,6 +1410,39 @@ static void AnimMonMoveCircular_Step(struct Sprite *sprite)
}
}
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);
}
//pulverizing pancake - destiny bond shadow from attacker to target
void AnimTask_PulverizingPancakeWhiteShadow(u8 taskId)
{

View File

@ -2500,6 +2500,8 @@ void AnimTask_GetTrappedMoveAnimId(u8 taskId)
gBattleAnimArgs[0] = TRAP_ANIM_MAGMA_STORM;
else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_INFESTATION)
gBattleAnimArgs[0] = TRAP_ANIM_INFESTATION;
else if (gBattleSpritesDataPtr->animationData->animArg == MOVE_SNAP_TRAP)
gBattleAnimArgs[0] = TRAP_ANIM_SNAP_TRAP;
else
gBattleAnimArgs[0] = TRAP_ANIM_BIND;

View File

@ -741,7 +741,7 @@ void BattleArena_AddSkillPoints(u8 battler)
}
}
void BattleArena_DeductMindPoints(u8 battler, u16 stringId)
void BattleArena_DeductSkillPoints(u8 battler, u16 stringId)
{
s8 *skillPoints = gBattleStruct->arenaSkillPoints;

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

@ -1463,15 +1463,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;
}
}
@ -1534,7 +1527,7 @@ static void OpponentHandlePrintString(void)
BufferStringBattle(*stringId);
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter;
BattleArena_DeductMindPoints(gActiveBattler, *stringId);
BattleArena_DeductSkillPoints(gActiveBattler, *stringId);
}
static void OpponentHandlePrintSelectionString(void)
@ -1544,7 +1537,7 @@ static void OpponentHandlePrintSelectionString(void)
static void OpponentHandleChooseAction(void)
{
AI_TrySwitchOrUseItem(); // TODO consider move choice first
AI_TrySwitchOrUseItem();
OpponentBufferExecCompleted();
}
@ -1568,9 +1561,8 @@ static void OpponentHandleChooseMove(void)
if (gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_FIRST_BATTLE | BATTLE_TYPE_SAFARI | BATTLE_TYPE_ROAMER)
|| IsWildMonSmart())
{
BattleAI_SetupAIData(0xF);
chosenMoveId = BattleAI_ChooseMoveOrAction();
chosenMoveId = gBattleStruct->aiMoveOrAction[gActiveBattler];
gBattlerTarget = gBattleStruct->aiChosenTarget[gActiveBattler];
switch (chosenMoveId)
{
case AI_CHOICE_WATCH:
@ -1586,6 +1578,9 @@ static void OpponentHandleChooseMove(void)
BtlController_EmitTwoReturnValues(BUFFER_B, 15, gBattlerTarget);
break;
default:
if (GetBattlerMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
gBattlerTarget = gActiveBattler;
if (GetBattlerMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]) & MOVE_TARGET_BOTH)
{
u16 chosenMove = moveInfo->moves[chosenMoveId];
@ -1599,7 +1594,7 @@ static void OpponentHandleChooseMove(void)
}
if (ShouldUseZMove(gActiveBattler, gBattlerTarget, chosenMove))
QueueZMove(gActiveBattler, moveInfo->moves[chosenMoveId]);
QueueZMove(gActiveBattler, chosenMove);
if (CanMegaEvolve(gActiveBattler)) // If opponent can mega evolve, do it.
BtlController_EmitTwoReturnValues(BUFFER_B, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8));
@ -1613,16 +1608,21 @@ static void OpponentHandleChooseMove(void)
else // Wild pokemon - use random move
{
u16 move;
u8 target;
do
{
chosenMoveId = Random() & 3;
move = moveInfo->moves[chosenMoveId];
} while (move == MOVE_NONE);
if (gBattleMoves[move].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
if (GetBattlerMoveTargetType(gActiveBattler, move) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
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))
@ -1649,14 +1649,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

@ -358,6 +358,7 @@ static void HandleInputChooseTarget(void)
s32 i;
static const u8 identities[MAX_BATTLERS_COUNT] = {B_POSITION_PLAYER_LEFT, B_POSITION_PLAYER_RIGHT, B_POSITION_OPPONENT_RIGHT, B_POSITION_OPPONENT_LEFT};
u16 move = GetMonData(&gPlayerParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_MOVE1 + gMoveSelectionCursor[gActiveBattler]);
u16 moveTarget = GetBattlerMoveTargetType(gActiveBattler, move);
DoBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX, 15, 1);
for (i = 0; i < gBattlersCount; i++)
@ -398,7 +399,7 @@ static void HandleInputChooseTarget(void)
PlaySE(SE_SELECT);
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCb_HideAsMoveTarget;
if (gBattleMoves[move].target == (MOVE_TARGET_USER | MOVE_TARGET_ALLY))
if (moveTarget == (MOVE_TARGET_USER | MOVE_TARGET_ALLY))
{
gMultiUsePlayerCursor ^= BIT_FLANK;
}
@ -427,7 +428,7 @@ static void HandleInputChooseTarget(void)
case B_POSITION_PLAYER_RIGHT:
if (gActiveBattler != gMultiUsePlayerCursor)
i++;
else if (gBattleMoves[move].target & MOVE_TARGET_USER_OR_SELECTED)
else if (moveTarget & MOVE_TARGET_USER_OR_SELECTED)
i++;
break;
case B_POSITION_OPPONENT_LEFT:
@ -436,7 +437,8 @@ static void HandleInputChooseTarget(void)
break;
}
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor])
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor]
|| !CanTargetBattler(gActiveBattler, gMultiUsePlayerCursor, move))
i = 0;
} while (i == 0);
}
@ -447,7 +449,7 @@ static void HandleInputChooseTarget(void)
PlaySE(SE_SELECT);
gSprites[gBattlerSpriteIds[gMultiUsePlayerCursor]].callback = SpriteCb_HideAsMoveTarget;
if (gBattleMoves[move].target == (MOVE_TARGET_USER | MOVE_TARGET_ALLY))
if (moveTarget == (MOVE_TARGET_USER | MOVE_TARGET_ALLY))
{
gMultiUsePlayerCursor ^= BIT_FLANK;
}
@ -476,7 +478,7 @@ static void HandleInputChooseTarget(void)
case B_POSITION_PLAYER_RIGHT:
if (gActiveBattler != gMultiUsePlayerCursor)
i++;
else if (gBattleMoves[move].target & MOVE_TARGET_USER_OR_SELECTED)
else if (moveTarget & MOVE_TARGET_USER_OR_SELECTED)
i++;
break;
case B_POSITION_OPPONENT_LEFT:
@ -485,7 +487,8 @@ static void HandleInputChooseTarget(void)
break;
}
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor])
if (gAbsentBattlerFlags & gBitTable[gMultiUsePlayerCursor]
|| !CanTargetBattler(gActiveBattler, gMultiUsePlayerCursor, move))
i = 0;
} while (i == 0);
}
@ -609,7 +612,7 @@ static void HandleInputChooseMove(void)
}
else
{
moveTarget = gBattleMoves[moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]].target;
moveTarget = GetBattlerMoveTargetType(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]);
}
if (gBattleStruct->zmove.viewing)
@ -2703,16 +2706,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);
}
}
@ -2776,7 +2772,7 @@ static void PlayerHandlePrintString(void)
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MSG);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnInactiveTextPrinter2;
BattleTv_SetDataBasedOnString(*stringId);
BattleArena_DeductMindPoints(gActiveBattler, *stringId);
BattleArena_DeductSkillPoints(gActiveBattler, *stringId);
}
static void PlayerHandlePrintSelectionString(void)

View File

@ -1430,15 +1430,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;
}
}
@ -1524,8 +1517,8 @@ static void PlayerPartnerHandleChooseMove(void)
u8 chosenMoveId;
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[gActiveBattler][4]);
BattleAI_SetupAIData(0xF);
chosenMoveId = BattleAI_ChooseMoveOrAction();
chosenMoveId = gBattleStruct->aiMoveOrAction[gActiveBattler];
gBattlerTarget = gBattleStruct->aiChosenTarget[gActiveBattler];
if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED))
gBattlerTarget = gActiveBattler;

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

@ -714,7 +714,7 @@ void CB2_BattleDebugMenu(void)
static void PutMovesPointsText(struct BattleDebugMenu *data)
{
u32 i, j, count;
u32 i, j, count, battlerDef;
u8 *text = malloc(0x50);
FillWindowPixelBuffer(data->aiMovesWindowId, 0x11);
@ -727,13 +727,14 @@ static void PutMovesPointsText(struct BattleDebugMenu *data)
{
if (data->aiIconSpriteIds[j] == 0xFF)
continue;
battlerDef = gSprites[data->aiIconSpriteIds[j]].data[0];
ConvertIntToDecimalStringN(text,
gBattleStruct->aiFinalScore[data->aiBattlerId][gSprites[data->aiIconSpriteIds[j]].data[0]][i],
gBattleStruct->aiFinalScore[data->aiBattlerId][battlerDef][i],
STR_CONV_MODE_RIGHT_ALIGN, 3);
AddTextPrinterParameterized(data->aiMovesWindowId, 1, text, 83 + count * 54, i * 15, 0, NULL);
ConvertIntToDecimalStringN(text,
gBattleStruct->aiSimulatedDamage[data->aiBattlerId][gSprites[data->aiIconSpriteIds[j]].data[0]][i],
AI_DATA->simulatedDmg[data->aiBattlerId][battlerDef][i],
STR_CONV_MODE_RIGHT_ALIGN, 3);
AddTextPrinterParameterized(data->aiMovesWindowId, 1, text, 110 + count * 54, i * 15, 0, NULL);

View File

@ -720,17 +720,25 @@ static void RestorePlayerPartyHeldItems(void)
}
}
u8 GetFactoryMonFixedIV(u8 arg0, u8 arg1)
// Get the IV to use for the opponent's pokémon.
// The IVs get higher for each subsequent challenge and for
// the last trainer in each challenge. Noland is an exception
// to this, as he uses the IVs that would be used by the regular
// trainers 2 challenges ahead of the current one.
// Due to a mistake in FillFactoryFrontierTrainerParty, the
// challenge number used to determine the IVs for regular trainers
// is Battle Tower's instead of Battle Factory's.
u8 GetFactoryMonFixedIV(u8 challengeNum, bool8 isLastBattle)
{
u8 a1;
u8 a2 = (arg1 != 0) ? 1 : 0;
u8 ivSet;
bool8 useHigherIV = isLastBattle ? TRUE : FALSE;
if (arg0 > 8)
a1 = 7;
if (challengeNum > 8)
ivSet = 7;
else
a1 = arg0;
ivSet = challengeNum;
return sFixedIVTable[a1][a2];
return sFixedIVTable[ivSet][useHigherIV];
}
void FillFactoryBrainParty(void)
@ -746,7 +754,7 @@ void FillFactoryBrainParty(void)
u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE);
u8 challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7;
fixedIV = GetFactoryMonFixedIV(challengeNum + 2, 0);
fixedIV = GetFactoryMonFixedIV(challengeNum + 2, FALSE);
monLevel = SetFacilityPtrsGetLevel();
i = 0;
otId = T1_READ_32(gSaveBlock2Ptr->playerTrainerId);

View File

@ -34,7 +34,7 @@ extern const struct CompressedSpriteSheet gSpriteSheet_EnemyShadow;
extern const struct SpriteTemplate gSpriteTemplate_EnemyShadow;
// this file's functions
static u8 GetBattlePalaceMoveGroup(u16 move);
static u8 GetBattlePalaceMoveGroup(u8 battlerId, u16 move);
static u16 GetBattlePalaceTarget(void);
static void SpriteCB_TrainerSlideVertical(struct Sprite *sprite);
static bool8 ShouldAnimBeDoneRegardlessOfSubstitute(u8 animId);
@ -151,7 +151,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void)
{
if (moveInfo->moves[i] == MOVE_NONE)
break;
if (selectedGroup == GetBattlePalaceMoveGroup(moveInfo->moves[i]) && moveInfo->currentPp[i] != 0)
if (selectedGroup == GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) && moveInfo->currentPp[i] != 0)
selectedMoves |= gBitTable[i];
}
@ -177,11 +177,11 @@ u16 ChooseMoveAndTargetInBattlePalace(void)
{
// validMoveFlags is used here as a bitfield for which moves can be used for each move group type
// first 4 bits are for attack (1 for each move), then 4 bits for defense, and 4 for support
if (GetBattlePalaceMoveGroup(moveInfo->moves[i]) == PALACE_MOVE_GROUP_ATTACK && !(gBitTable[i] & unusableMovesBits))
if (GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) == PALACE_MOVE_GROUP_ATTACK && !(gBitTable[i] & unusableMovesBits))
validMoveFlags += (1 << 0);
if (GetBattlePalaceMoveGroup(moveInfo->moves[i]) == PALACE_MOVE_GROUP_DEFENSE && !(gBitTable[i] & unusableMovesBits))
if (GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) == PALACE_MOVE_GROUP_DEFENSE && !(gBitTable[i] & unusableMovesBits))
validMoveFlags += (1 << 4);
if (GetBattlePalaceMoveGroup(moveInfo->moves[i]) == PALACE_MOVE_GROUP_SUPPORT && !(gBitTable[i] & unusableMovesBits))
if (GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]) == PALACE_MOVE_GROUP_SUPPORT && !(gBitTable[i] & unusableMovesBits))
validMoveFlags += (1 << 8);
}
@ -218,7 +218,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void)
do
{
i = Random() % MAX_MON_MOVES;
if (!(gBitTable[i] & unusableMovesBits) && validMoveGroup == GetBattlePalaceMoveGroup(moveInfo->moves[i]))
if (!(gBitTable[i] & unusableMovesBits) && validMoveGroup == GetBattlePalaceMoveGroup(gActiveBattler, moveInfo->moves[i]))
chosenMoveId = i;
} while (chosenMoveId == -1);
}
@ -247,7 +247,7 @@ u16 ChooseMoveAndTargetInBattlePalace(void)
}
else
{
moveTarget = gBattleMoves[moveInfo->moves[chosenMoveId]].target;
moveTarget = GetBattlerMoveTargetType(gActiveBattler, moveInfo->moves[chosenMoveId]);
}
if (moveTarget & MOVE_TARGET_USER)
@ -269,9 +269,9 @@ u16 ChooseMoveAndTargetInBattlePalace(void)
#undef numValidMoveGroups
#undef validMoveGroup
static u8 GetBattlePalaceMoveGroup(u16 move)
static u8 GetBattlePalaceMoveGroup(u8 battlerId, u16 move)
{
switch (gBattleMoves[move].target)
switch (GetBattlerMoveTargetType(battlerId, move))
{
case MOVE_TARGET_SELECTED:
case MOVE_TARGET_USER_OR_SELECTED:
@ -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_Z - 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

@ -3316,7 +3316,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;
}
}
}
}
@ -3698,6 +3710,8 @@ static void TryDoEventsBeforeFirstTurn(void)
gMoveResultFlags = 0;
gRandomTurnNumber = Random();
GetAiLogicData(); // get assumed abilities, hold effects, etc of all battlers
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
{
@ -3786,6 +3800,7 @@ void BattleTurnPassed(void)
*(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags;
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
GetAiLogicData(); // get assumed abilities, hold effects, etc of all battlers
gBattleMainFunc = HandleTurnActionSelectionState;
gRandomTurnNumber = Random();
@ -3903,6 +3918,11 @@ static void HandleTurnActionSelectionState(void)
case STATE_TURN_START_RECORD: // Recorded battle related action on start of every turn.
RecordedBattle_CopyBattlerMoves();
gBattleCommunication[gActiveBattler] = STATE_BEFORE_ACTION_CHOSEN;
// Do AI score computations here so we can use them in AI_TrySwitchOrUseItem
if ((gBattleTypeFlags & BATTLE_TYPE_HAS_AI || IsWildMonSmart()) && IsBattlerAIControlled(gActiveBattler)) {
gBattleStruct->aiMoveOrAction[gActiveBattler] = ComputeBattleAiScores(gActiveBattler);
}
break;
case STATE_BEFORE_ACTION_CHOSEN: // Choose an action.
*(gBattleStruct->monToSwitchIntoId + gActiveBattler) = PARTY_SIZE;
@ -4021,7 +4041,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]);
}
@ -4822,13 +4843,19 @@ static void CheckFocusPunch_ClearVarsBeforeTurnStarts(void)
{
gActiveBattler = gBattlerAttacker = gBattleStruct->focusPunchBattlerId;
gBattleStruct->focusPunchBattlerId++;
if (gChosenMoveByBattler[gActiveBattler] == MOVE_FOCUS_PUNCH
&& !(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
if (!(gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
&& !(gDisableStructs[gBattlerAttacker].truantCounter)
&& !(gProtectStructs[gActiveBattler].noValidMoves))
{
BattleScriptExecute(BattleScript_FocusPunchSetUp);
return;
switch(gChosenMoveByBattler[gActiveBattler])
{
case MOVE_FOCUS_PUNCH:
BattleScriptExecute(BattleScript_FocusPunchSetUp);
return;
case MOVE_BEAK_BLAST:
BattleScriptExecute(BattleScript_BeakBlastSetUp);
return;
}
}
}
}
@ -5150,9 +5177,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
{
@ -5170,6 +5204,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;
@ -5204,7 +5262,7 @@ static void TryEvolvePokemon(void)
static void WaitForEvoSceneToFinish(void)
{
if (gMain.callback2 == BattleMainCB2)
gBattleMainFunc = TryEvolvePokemon;
gBattleMainFunc = TrySpecialEvolution;
}
static void ReturnFromBattleToOverworld(void)

File diff suppressed because it is too large Load Diff

View File

@ -282,11 +282,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, 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
@ -1299,12 +1306,12 @@ static const u8 sBattlePalaceNatureToFlavorTextId[NUM_NATURES] =
[NATURE_QUIRKY] = B_MSG_EAGER_FOR_MORE,
};
static bool32 NoTargetPresent(u32 move)
static bool32 NoTargetPresent(u8 battlerId, u32 move)
{
if (!IsBattlerAlive(gBattlerTarget))
gBattlerTarget = GetMoveTarget(move, NO_TARGET_OVERRIDE);
switch (gBattleMoves[move].target)
switch (GetBattlerMoveTargetType(battlerId, move))
{
case MOVE_TARGET_SELECTED:
case MOVE_TARGET_DEPENDS:
@ -1360,24 +1367,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)
@ -1449,7 +1452,7 @@ static void Cmd_attackcanceler(void)
}
gHitMarker |= HITMARKER_OBEYS;
if (NoTargetPresent(gCurrentMove) && (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
if (NoTargetPresent(gBattlerAttacker, gCurrentMove) && (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
{
gBattlescriptCurrInstr = BattleScript_ButItFailedAtkStringPpReduce;
if (!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
@ -1533,6 +1536,11 @@ static void Cmd_attackcanceler(void)
gBattleCommunication[MISS_TYPE] = B_MSG_PROTECTED;
gBattlescriptCurrInstr++;
}
else if (gProtectStructs[gBattlerTarget].beakBlastCharge && IsMoveMakingContact(gCurrentMove, gBattlerAttacker))
{
gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE;
gBattlescriptCurrInstr++;
}
else
{
gBattlescriptCurrInstr++;
@ -1645,20 +1653,14 @@ static bool32 AccuracyCalcHelper(u16 move)
return FALSE;
}
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move)
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect)
{
u32 calc, moveAcc, atkHoldEffect, atkParam, defHoldEffect, defParam, atkAbility, defAbility;
u32 calc, moveAcc;
s8 buff, accStage, evasionStage;
u8 atkParam = GetBattlerHoldEffectParam(battlerAtk);
u8 defParam = GetBattlerHoldEffectParam(battlerDef);
atkAbility = GetBattlerAbility(battlerAtk);
atkHoldEffect = GetBattlerHoldEffect(battlerAtk, TRUE);
atkParam = GetBattlerHoldEffectParam(battlerAtk);
defAbility = GetBattlerAbility(battlerDef);
defHoldEffect = GetBattlerHoldEffect(battlerDef, TRUE);
defParam = GetBattlerHoldEffectParam(battlerDef);
gPotentialItemEffectBattler = battlerDef;
accStage = gBattleMons[battlerAtk].statStages[STAT_ACC];
evasionStage = gBattleMons[battlerDef].statStages[STAT_EVASION];
if (atkAbility == ABILITY_UNAWARE || atkAbility == ABILITY_KEEN_EYE)
@ -1733,6 +1735,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move)
static void Cmd_accuracycheck(void)
{
u16 type, move = T2_READ_16(gBattlescriptCurrInstr + 5);
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
if (move == ACC_CURR_MOVE)
move = gCurrentMove;
@ -1755,14 +1758,15 @@ static void Cmd_accuracycheck(void)
return;
// final calculation
if ((Random() % 100 + 1) > GetTotalAccuracy(gBattlerAttacker, gBattlerTarget, move))
if ((Random() % 100 + 1) > GetTotalAccuracy(gBattlerAttacker, gBattlerTarget, move, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(gBattlerTarget),
GetBattlerHoldEffect(gBattlerAttacker, TRUE), GetBattlerHoldEffect(gBattlerTarget, TRUE)))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
(gBattleMoves[move].target == MOVE_TARGET_BOTH || gBattleMoves[move].target == MOVE_TARGET_FOES_AND_ALLY))
(moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY))
gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK;
else
gBattleCommunication[MISS_TYPE] = B_MSG_MISSED;
@ -1796,7 +1800,7 @@ static void Cmd_ppreduce(void)
if (!gSpecialStatuses[gBattlerAttacker].ppNotAffectedByPressure)
{
switch (gBattleMoves[gCurrentMove].target)
switch (GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove))
{
case MOVE_TARGET_FOES_AND_ALLY:
for (i = 0; i < gBattlersCount; i++)
@ -1881,11 +1885,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;
}
@ -1917,6 +1917,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;
@ -1931,6 +1932,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++;
}
@ -2096,6 +2103,8 @@ static void Cmd_multihitresultmessage(void)
static void Cmd_attackanimation(void)
{
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
if (gBattleControllerExecFlags)
return;
@ -2112,9 +2121,9 @@ static void Cmd_attackanimation(void)
}
else
{
if ((gBattleMoves[gCurrentMove].target & MOVE_TARGET_BOTH
|| gBattleMoves[gCurrentMove].target & MOVE_TARGET_FOES_AND_ALLY
|| gBattleMoves[gCurrentMove].target & MOVE_TARGET_DEPENDS)
if ((moveTarget & MOVE_TARGET_BOTH
|| moveTarget & MOVE_TARGET_FOES_AND_ALLY
|| moveTarget & MOVE_TARGET_DEPENDS)
&& gBattleScripting.animTargetsHit)
{
gBattlescriptCurrInstr++;
@ -2950,7 +2959,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
{
@ -3029,10 +3048,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;
}
@ -3168,7 +3185,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
| BATTLE_TYPE_LINK
| BATTLE_TYPE_RECORDED_LINK
| BATTLE_TYPE_SECRET_BASE))
&& (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]))
&& (gWishFutureKnock.knockedOffMons[side] & gBitTable[gBattlerPartyIndexes[gBattlerAttacker]]))
{
gBattlescriptCurrInstr++;
}
@ -3504,6 +3521,13 @@ void SetMoveEffect(bool32 primary, u32 certain)
gBattleMons[gBattlerTarget].status2 |= STATUS2_ESCAPE_PREVENTION;
gBattleMons[gBattlerAttacker].status2 |= STATUS2_ESCAPE_PREVENTION;
break;
case MOVE_EFFECT_SCALE_SHOT:
if (!NoAliveMonsForEitherParty())
{
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_DefDownSpeedUp;
}
break;
}
}
}
@ -5023,7 +5047,7 @@ static void Cmd_moveend(void)
}
else if (gProtectStructs[gBattlerTarget].obstructed && gCurrentMove != MOVE_SUCKER_PUNCH)
{
gProtectStructs[gBattlerAttacker].touchedProtectLike = 0;
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
i = gBattlerAttacker;
gBattlerAttacker = gBattlerTarget;
gBattlerTarget = i; // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable
@ -5032,6 +5056,17 @@ static void Cmd_moveend(void)
gBattlescriptCurrInstr = BattleScript_KingsShieldEffect;
effect = 1;
}
// Not strictly a protect effect, but works the same way
else if (gProtectStructs[gBattlerTarget].beakBlastCharge
&& CanBeBurned(gBattlerAttacker)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
{
gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE;
gBattleMons[gBattlerAttacker].status1 = STATUS1_BURN;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BeakBlastBurn;
effect = 1;
}
}
gBattleScripting.moveendState++;
break;
@ -5327,6 +5362,8 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++;
break;
case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon.
{
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
// Set a flag if move hits either target (for throat spray that can't check damage)
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
@ -5335,12 +5372,13 @@ static void Cmd_moveend(void)
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& !gProtectStructs[gBattlerAttacker].chargingTurn
&& (gBattleMoves[gCurrentMove].target == MOVE_TARGET_BOTH || gBattleMoves[gCurrentMove].target == MOVE_TARGET_FOES_AND_ALLY)
&& (moveTarget == MOVE_TARGET_BOTH
|| moveTarget == MOVE_TARGET_FOES_AND_ALLY)
&& !(gHitMarker & HITMARKER_NO_ATTACKSTRING))
{
u8 battlerId;
if (gBattleMoves[gCurrentMove].target == MOVE_TARGET_FOES_AND_ALLY)
if (moveTarget == MOVE_TARGET_FOES_AND_ALLY)
{
gHitMarker |= HITMARKER_NO_PPDEDUCT;
for (battlerId = gBattlerTarget + 1; battlerId < gBattlersCount; battlerId++)
@ -5376,6 +5414,7 @@ static void Cmd_moveend(void)
RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove);
gBattleScripting.moveendState++;
break;
}
case MOVEEND_EJECT_BUTTON:
if (gCurrentMove != MOVE_DRAGON_TAIL
&& gCurrentMove != MOVE_CIRCLE_THROW
@ -6380,7 +6419,7 @@ static void Cmd_switchineffects(void)
gBattleMoveDamage = -1 * (gBattleMons[gActiveBattler].maxHP);
gBattleScripting.battler = gActiveBattler;
BattleScriptPushCursor();
gBattleCommunication[MULTISTRING_CHOOSER] = MULTISTRING_Z_HP_TRAP;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_HP_TRAP;
gBattlescriptCurrInstr = BattleScript_HealReplacementZMove;
return;
}
@ -6766,13 +6805,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++;
}
@ -7669,6 +7733,66 @@ static bool32 IsRototillerAffected(u32 battlerId)
return TRUE;
}
#define COURTCHANGE_SWAP(status, structField, temp) \
{ \
temp = gSideStatuses[B_SIDE_PLAYER]; \
if (gSideStatuses[B_SIDE_OPPONENT] & status) \
gSideStatuses[B_SIDE_PLAYER] |= status; \
else \
gSideStatuses[B_SIDE_PLAYER] &= ~(status); \
if (temp & status) \
gSideStatuses[B_SIDE_OPPONENT] |= status; \
else \
gSideStatuses[B_SIDE_OPPONENT] &= ~(status); \
SWAP(sideTimerPlayer->structField, sideTimerOpp->structField, temp);\
} \
#define UPDATE_COURTCHANGED_BATTLER(structField)\
{ \
sideTimerPlayer->structField ^= BIT_SIDE; \
sideTimerOpp->structField ^= BIT_SIDE; \
} \
static bool32 CourtChangeSwapSideStatuses(void)
{
struct SideTimer *sideTimerPlayer = &gSideTimers[B_SIDE_PLAYER];
struct SideTimer *sideTimerOpp = &gSideTimers[B_SIDE_OPPONENT];
u32 temp;
// TODO: add Pledge-related effects
// TODO: add Gigantamax-related effects
// Swap timers and statuses
COURTCHANGE_SWAP(SIDE_STATUS_REFLECT, reflectTimer, temp)
COURTCHANGE_SWAP(SIDE_STATUS_LIGHTSCREEN, lightscreenTimer, temp)
COURTCHANGE_SWAP(SIDE_STATUS_MIST, mistTimer, temp);
COURTCHANGE_SWAP(SIDE_STATUS_SAFEGUARD, safeguardTimer, temp);
COURTCHANGE_SWAP(SIDE_STATUS_AURORA_VEIL, auroraVeilTimer, temp);
COURTCHANGE_SWAP(SIDE_STATUS_TAILWIND, tailwindTimer, temp);
// Lucky Chant doesn't exist in gen 8, but seems like it should be affected by Court Change
COURTCHANGE_SWAP(SIDE_STATUS_LUCKY_CHANT, luckyChantTimer, temp);
COURTCHANGE_SWAP(SIDE_STATUS_SPIKES, spikesAmount, temp);
COURTCHANGE_SWAP(SIDE_STATUS_STEALTH_ROCK, stealthRockAmount, temp);
COURTCHANGE_SWAP(SIDE_STATUS_TOXIC_SPIKES, toxicSpikesAmount, temp);
COURTCHANGE_SWAP(SIDE_STATUS_STICKY_WEB, stickyWebAmount, temp);
// Change battler IDs of swapped effects. Needed for the correct string when they expire
// E.g. "Foe's Reflect wore off!"
UPDATE_COURTCHANGED_BATTLER(reflectBattlerId);
UPDATE_COURTCHANGED_BATTLER(lightscreenBattlerId);
UPDATE_COURTCHANGED_BATTLER(mistBattlerId);
UPDATE_COURTCHANGED_BATTLER(safeguardBattlerId);
UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId);
UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId);
UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId);
// For Mirror Armor only
gBattleStruct->stickyWebUser = gBattlerAttacker;
// Track which side originally set the Sticky Web
SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp);
}
static void Cmd_various(void)
{
struct Pokemon *mon;
@ -7830,7 +7954,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)))
@ -8370,6 +8494,7 @@ static void Cmd_various(void)
case MOVE_MIRROR_COAT:
case MOVE_METAL_BURST:
case MOVE_ME_FIRST:
case MOVE_BEAK_BLAST:
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
break;
default:
@ -8504,7 +8629,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);
@ -9399,6 +9524,7 @@ static void Cmd_various(void)
else
{
PREPARE_ITEM_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].item);
gLastUsedItem = gBattleMons[gActiveBattler].item;
gBattlescriptCurrInstr += 7;
}
return;
@ -9448,6 +9574,89 @@ static void Cmd_various(void)
gBattlescriptCurrInstr += 7;
return;
}
case VARIOUS_JUMP_IF_CANT_FLING:
if (!CanFling(gActiveBattler))
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else
gBattlescriptCurrInstr += 7;
return;
case VARIOUS_CURE_CERTAIN_STATUSES:
// Check infatuation
if (gBattleMons[gActiveBattler].status2 & STATUS2_INFATUATION)
{
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_INFATUATION);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_INFATUATION; // STRINGID_TARGETGOTOVERINFATUATION
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
}
// Check taunt
if (gDisableStructs[gActiveBattler].tauntTimer != 0)
{
gDisableStructs[gActiveBattler].tauntTimer = gDisableStructs[gActiveBattler].tauntTimer2 = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TAUNT;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_TAUNT);
}
// Check encore
if (gDisableStructs[gActiveBattler].encoreTimer != 0)
{
gDisableStructs[gActiveBattler].encoredMove = 0;
gDisableStructs[gActiveBattler].encoreTimerStartValue = gDisableStructs[gActiveBattler].encoreTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_ENCORE; // STRINGID_PKMNENCOREENDED
}
// Check torment
if (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT)
{
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_TORMENT);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_TORMENT;
}
// Check heal block
if (gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK)
{
gStatuses3[gActiveBattler] &= ~(STATUS3_HEAL_BLOCK);
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_HEALBLOCK;
}
// Check disable
if (gDisableStructs[gActiveBattler].disableTimer != 0)
{
gDisableStructs[gActiveBattler].disableTimer = gDisableStructs[gActiveBattler].disableTimerStartValue = 0;
gDisableStructs[gActiveBattler].disabledMove = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_MENTALHERBCURE_DISABLE;
}
gBattlescriptCurrInstr += 3;
return;
case VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES:
gActiveBattler = gBattlerTarget;
for (i = 0; i < NUM_BATTLE_STATS; i++)
if (gBattleMons[gActiveBattler].statStages[i] < DEFAULT_STAT_STAGE)
gBattleMons[gActiveBattler].statStages[i] = DEFAULT_STAT_STAGE;
gBattlescriptCurrInstr += 3;
return;
case VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY:
if (ItemId_GetPocket(gLastUsedItem) == POCKET_BERRIES)
gBattlescriptCurrInstr += 7;
else
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
return;
case VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT:
if (ItemId_GetHoldEffect(gLastUsedItem) == gBattlescriptCurrInstr[3])
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 4);
else
gBattlescriptCurrInstr += 8;
return;
case VARIOUS_SAVE_BATTLER_ITEM:
gBattleResources->battleHistory->heldItems[gActiveBattler] = gBattleMons[gActiveBattler].item;
break;
case VARIOUS_RESTORE_BATTLER_ITEM:
gBattleMons[gActiveBattler].item = gBattleResources->battleHistory->heldItems[gActiveBattler];
break;
case VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM:
gBattleMons[gActiveBattler].item = gLastUsedItem;
break;
case VARIOUS_SET_BEAK_BLAST:
gProtectStructs[gBattlerAttacker].beakBlastCharge = TRUE;
break;
case VARIOUS_SWAP_SIDE_STATUSES:
CourtChangeSwapSideStatuses();
break;
} // End of switch (gBattlescriptCurrInstr[2])
gBattlescriptCurrInstr += 3;
@ -9592,7 +9801,7 @@ static void Cmd_jumpifnexttargetvalid(void)
for (gBattlerTarget++; gBattlerTarget < gBattlersCount; gBattlerTarget++)
{
if (gBattlerTarget == gBattlerAttacker && !(gBattleMoves[gCurrentMove].target & MOVE_TARGET_USER))
if (gBattlerTarget == gBattlerAttacker && !(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER))
continue;
if (IsBattlerAlive(gBattlerTarget))
break;
@ -9759,7 +9968,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;
@ -10779,6 +10988,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;
}
@ -11403,7 +11616,8 @@ static bool8 IsTwoTurnsMove(u16 move)
|| gBattleMoves[move].effect == EFFECT_TWO_TURNS_ATTACK
|| gBattleMoves[move].effect == EFFECT_SOLAR_BEAM
|| gBattleMoves[move].effect == EFFECT_SEMI_INVULNERABLE
|| gBattleMoves[move].effect == EFFECT_BIDE)
|| gBattleMoves[move].effect == EFFECT_BIDE
|| gBattleMoves[move].effect == EFFECT_METEOR_BEAM)
return TRUE;
else
return FALSE;
@ -12097,6 +12311,7 @@ static void Cmd_recoverbasedonsunlight(void)
static void Cmd_setstickyweb(void)
{
u8 targetSide = GetBattlerSide(gBattlerTarget);
if (gSideStatuses[targetSide] & SIDE_STATUS_STICKY_WEB)
{
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
@ -12104,6 +12319,7 @@ static void Cmd_setstickyweb(void)
else
{
gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB;
gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side
gSideTimers[targetSide].stickyWebAmount = 1;
gBattleStruct->stickyWebUser = gBattlerAttacker; // For Mirror Armor
gBattlescriptCurrInstr += 5;
@ -12114,7 +12330,7 @@ static void Cmd_selectfirstvalidtarget(void)
{
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
{
if (gBattlerTarget == gBattlerAttacker && !(gBattleMoves[gCurrentMove].target & MOVE_TARGET_USER))
if (gBattlerTarget == gBattlerAttacker && !(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove) & MOVE_TARGET_USER))
continue;
if (IsBattlerAlive(gBattlerTarget))
break;
@ -12271,9 +12487,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++;
}
@ -12348,13 +12564,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;
@ -12415,7 +12634,7 @@ static void Cmd_tryswapitems(void) // trick
u8 sideAttacker = GetBattlerSide(gBattlerAttacker);
u8 sideTarget = GetBattlerSide(gBattlerTarget);
// you can't swap items if they were knocked off in regular battles
// You can't swap items if they were knocked off in regular battles
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
| BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
@ -13418,7 +13637,7 @@ static void Cmd_handleballthrow(void)
else
catchRate = gBaseStats[gBattleMons[gBattlerTarget].species].catchRate;
#ifdef POKEMON_EXPANSION
#if defined POKEMON_EXPANSION && defined ITEM_EXPANSION
if (gBaseStats[gBattleMons[gBattlerTarget].species].flags & FLAG_ULTRA_BEAST)
{
if (gLastUsedItem == ITEM_BEAST_BALL)
@ -13596,7 +13815,7 @@ static void Cmd_handleballthrow(void)
#endif
}
#ifdef POKEMON_EXPANSION
#if defined POKEMON_EXPANSION && defined ITEM_EXPANSION
}
#endif

View File

@ -1836,13 +1836,18 @@ static void FillFactoryFrontierTrainerParty(u16 trainerId, u8 firstMonId)
if (trainerId < FRONTIER_TRAINERS_COUNT)
{
u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode; // Unused variable.
u8 lvlMode = gSaveBlock2Ptr->frontier.lvlMode;
u8 battleMode = VarGet(VAR_FRONTIER_BATTLE_MODE);
// By mistake Battle Tower's Level 50 challenge number is used to determine the IVs for Battle Factory.
#ifdef BUGFIX
u8 challengeNum = gSaveBlock2Ptr->frontier.factoryWinStreaks[battleMode][lvlMode] / 7;
#else
u8 challengeNum = gSaveBlock2Ptr->frontier.towerWinStreaks[battleMode][FRONTIER_LVL_50] / 7;
#endif
if (gSaveBlock2Ptr->frontier.curChallengeBattleNum < 6)
fixedIV = GetFactoryMonFixedIV(challengeNum, 0);
fixedIV = GetFactoryMonFixedIV(challengeNum, FALSE);
else
fixedIV = GetFactoryMonFixedIV(challengeNum, 1);
fixedIV = GetFactoryMonFixedIV(challengeNum, TRUE); // Last trainer in challenge uses higher IVs
}
else if (trainerId == TRAINER_EREADER)
{

View File

@ -570,7 +570,7 @@ void BattleTv_SetDataBasedOnString(u16 stringId)
moveSlot = GetBattlerMoveSlotId(gBattlerAttacker, gBattleMsgDataPtr->currentMove);
if (moveSlot >= MAX_MON_MOVES && IsNotSpecialBattleString(stringId) && stringId > BATTLESTRINGS_ID_ADDER)
if (moveSlot >= MAX_MON_MOVES && IsNotSpecialBattleString(stringId) && stringId > BATTLESTRINGS_TABLE_START)
{
tvPtr->side[atkSide].faintCause = FNT_OTHER;
return;

View File

@ -238,6 +238,7 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move)
void HandleAction_UseMove(void)
{
u32 i, side, moveType, var = 4;
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber];
if (gBattleStruct->absentBattlerFlags & gBitTable[gBattlerAttacker] || !IsBattlerAlive(gBattlerAttacker))
@ -316,14 +317,14 @@ void HandleAction_UseMove(void)
// choose target
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove)
&& gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED
&& moveTarget == MOVE_TARGET_SELECTED
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget))
{
gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = gSideTimers[side].followmeTarget; // follow me moxie fix
}
else if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
&& gSideTimers[side].followmeTimer == 0
&& (gBattleMoves[gCurrentMove].power != 0 || gBattleMoves[gCurrentMove].target != MOVE_TARGET_USER)
&& (gBattleMoves[gCurrentMove].power != 0 || moveTarget != MOVE_TARGET_USER)
&& ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|| (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER)))
{
@ -344,7 +345,7 @@ void HandleAction_UseMove(void)
}
if (var == 4)
{
if (gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM)
if (moveTarget & MOVE_TARGET_RANDOM)
{
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
{
@ -361,7 +362,7 @@ void HandleAction_UseMove(void)
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
}
}
else if (gBattleMoves[gChosenMove].target & MOVE_TARGET_FOES_AND_ALLY)
else if (moveTarget & MOVE_TARGET_FOES_AND_ALLY)
{
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
{
@ -405,7 +406,7 @@ void HandleAction_UseMove(void)
}
}
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleMoves[gChosenMove].target & MOVE_TARGET_RANDOM)
&& moveTarget & MOVE_TARGET_RANDOM)
{
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
{
@ -428,7 +429,7 @@ void HandleAction_UseMove(void)
gBattlerTarget = GetBattlerAtPosition(GetBattlerPosition(gBattlerTarget) ^ BIT_FLANK);
}
}
else if (gBattleMoves[gChosenMove].target == MOVE_TARGET_ALLY)
else if (moveTarget == MOVE_TARGET_ALLY)
{
if (IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)))
gBattlerTarget = BATTLE_PARTNER(gBattlerAttacker);
@ -436,7 +437,7 @@ void HandleAction_UseMove(void)
gBattlerTarget = gBattlerAttacker;
}
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& gBattleMoves[gChosenMove].target == MOVE_TARGET_FOES_AND_ALLY)
&& moveTarget == MOVE_TARGET_FOES_AND_ALLY)
{
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++)
{
@ -1553,6 +1554,7 @@ bool8 WasUnableToUseMove(u8 battler)
void PrepareStringBattle(u16 stringId, u8 battler)
{
u32 targetSide = GetBattlerSide(gBattlerTarget);
u16 battlerAbility = GetBattlerAbility(battler);
u16 targetAbility = GetBattlerAbility(gBattlerTarget);
// Support for Contrary ability.
@ -1573,16 +1575,28 @@ void PrepareStringBattle(u16 stringId, u8 battler)
&& ((targetAbility == ABILITY_DEFIANT && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|| (targetAbility == ABILITY_COMPETITIVE && CompareStat(gBattlerTarget, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)))
&& gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != BATTLE_PARTNER(gBattlerTarget)
&& gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget)
&& ((gSpecialStatuses[gBattlerTarget].changedStatsBattlerId != gBattlerTarget) || gBattleScripting.stickyWebStatDrop == 1)
&& !(gBattleScripting.stickyWebStatDrop == 1 && gSideTimers[targetSide].stickyWebBattlerSide == targetSide)) // Sticky Web must have been set by the foe
{
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);
@ -1682,15 +1696,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;
@ -4477,7 +4497,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates);
effect++;
}
else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone)
else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone)
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3);
@ -4490,7 +4510,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates);
effect++;
}
else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone)
else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone)
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3);
@ -4503,7 +4523,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates);
effect++;
}
else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone)
else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone)
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3);
@ -4516,7 +4536,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivates);
effect++;
}
else if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY && !gSpecialStatuses[battler].switchInAbilityDone)
else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT && !gSpecialStatuses[battler].switchInAbilityDone)
{
gSpecialStatuses[battler].switchInAbilityDone = TRUE;
BattleScriptPushCursorAndCallback(BattleScript_BlockedByPrimalWeatherEnd3);
@ -4842,7 +4862,10 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
}
break;
case ABILITYEFFECT_MOVES_BLOCK: // 2
if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gBattleMoves[move].flags & FLAG_SOUND && !(gBattleMoves[move].target & MOVE_TARGET_USER))
{
u16 moveTarget = GetBattlerMoveTargetType(battler, move);
if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gBattleMoves[move].flags & FLAG_SOUND && !(moveTarget & MOVE_TARGET_USER))
|| (gLastUsedAbility == ABILITY_BULLETPROOF && gBattleMoves[move].flags & FLAG_BALLISTIC))
{
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
@ -4865,14 +4888,14 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
else if (BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE)
&& !(IS_MOVE_STATUS(move) && GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE))
{
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || !(moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
CancelMultiTurnMoves(gBattlerAttacker); // Don't cancel moves that can hit two targets bc one target might not be protected
gBattleScripting.battler = gBattlerAbility = gBattlerTarget;
gBattlescriptCurrInstr = BattleScript_DarkTypePreventsPrankster;
effect = 1;
}
break;
}
case ABILITYEFFECT_ABSORBING: // 3
if (move != MOVE_NONE)
{
@ -4934,7 +4957,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;
@ -5394,9 +5421,9 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& !(WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM))
&& !(gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT))
{
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_PRIMAL_ANY)
if (gBattleWeather & B_WEATHER_PRIMAL_ANY && WEATHER_HAS_EFFECT)
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_BlockedByPrimalWeatherRet;
@ -6107,9 +6134,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);
@ -6145,6 +6182,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))
@ -6295,7 +6334,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)
@ -6734,7 +6777,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)
@ -7164,7 +7211,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;
@ -7458,7 +7509,7 @@ u32 GetMoveTarget(u16 move, u8 setTarget)
if (setTarget != NO_TARGET_OVERRIDE)
moveTarget = setTarget - 1;
else
moveTarget = gBattleMoves[move].target;
moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move);
// Special cases
if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST))
@ -7731,7 +7782,7 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move)
else if (gProtectStructs[battlerId].protected)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_WIDE_GUARD
&& gBattleMoves[move].target & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))
&& GetBattlerMoveTargetType(gBattlerAttacker, move) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))
return TRUE;
else if (gProtectStructs[battlerId].banefulBunkered)
return TRUE;
@ -7754,31 +7805,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)
@ -7857,7 +7912,7 @@ u32 CountBattlerStatIncreases(u8 battlerId, bool32 countEvasionAcc)
u32 GetMoveTargetCount(u16 move, u8 battlerAtk, u8 battlerDef)
{
switch (gBattleMoves[move].target)
switch (GetBattlerMoveTargetType(gBattlerAttacker, move))
{
case MOVE_TARGET_BOTH:
return IsBattlerAlive(battlerDef)
@ -8001,7 +8056,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef)
// todo
break;
case EFFECT_FLING:
// todo: program Fling + Unburden interaction
basePower = ItemId_GetFlingPower(gBattleMons[battlerAtk].item);
break;
case EFFECT_ERUPTION:
basePower = gBattleMons[battlerAtk].hp * basePower / gBattleMons[battlerAtk].maxHP;
@ -8051,7 +8106,7 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef)
basePower *= 2;
break;
case EFFECT_WEATHER_BALL:
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_ANY)
if (gBattleWeather & B_WEATHER_ANY && WEATHER_HAS_EFFECT)
basePower *= 2;
break;
case EFFECT_PURSUIT:
@ -8149,7 +8204,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:
@ -8199,9 +8255,17 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef)
&& IsBattlerGrounded(gBattlerAttacker))
basePower *= 2;
break;
case EFFECT_EXPANDING_FORCE:
if (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN))
MulModifier(&basePower, UQ_4_12(1.5));
break;
case EFFECT_RISING_VOLTAGE:
if (IsBattlerTerrainAffected(gBattlerTarget, STATUS_FIELD_ELECTRIC_TERRAIN))
basePower *= 2;
break;
}
// move-specific base power changes
// Move-specific base power changes
switch (move)
{
case MOVE_WATER_SHURIKEN:
@ -8253,7 +8317,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe
break;
case ABILITY_SAND_FORCE:
if ((moveType == TYPE_STEEL || moveType == TYPE_ROCK || moveType == TYPE_GROUND)
&& WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM)
&& gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT)
MulModifier(&modifier, UQ_4_12(1.3));
break;
case ABILITY_RIVALRY:
@ -8862,7 +8926,7 @@ static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType,
}
// sandstorm sp.def boost for rock types
if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_SANDSTORM && !usesDefStat)
if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_ROCK) && gBattleWeather & B_WEATHER_SANDSTORM && WEATHER_HAS_EFFECT && !usesDefStat)
MulModifier(&modifier, UQ_4_12(1.5));
// The defensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the 5th badge and 7th badges.
@ -8897,7 +8961,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
@ -8917,7 +8982,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));
@ -9034,13 +9099,11 @@ static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 move
return dmg;
}
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags)
static s32 DoMoveDamageCalc(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower,
bool32 isCrit, bool32 randomFactor, bool32 updateFlags, u16 typeEffectivenessModifier)
{
s32 dmg;
u16 typeEffectivenessModifier;
typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags);
// Don't calculate damage if the move has no effect on target.
if (typeEffectivenessModifier == UQ_4_12(0))
return 0;
@ -9073,6 +9136,19 @@ s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32
return dmg;
}
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor, bool32 updateFlags)
{
return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, fixedBasePower, isCrit, randomFactor,
updateFlags, CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, updateFlags));
}
// for AI - get move damage and effectiveness with one function call
s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, u16 *typeEffectivenessModifier)
{
*typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, FALSE);
return DoMoveDamageCalc(move, battlerAtk, battlerDef, moveType, 0, FALSE, FALSE, FALSE, *typeEffectivenessModifier);
}
static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 battlerDef, u8 defType, u8 battlerAtk, bool32 recordAbilities)
{
u16 mod = GetTypeModifier(moveType, defType);
@ -9104,7 +9180,7 @@ static void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 batt
mod = UQ_4_12(2.0);
// B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon
if (WEATHER_HAS_EFFECT && gBattleWeather & B_WEATHER_STRONG_WINDS)
if (gBattleWeather & B_WEATHER_STRONG_WINDS && WEATHER_HAS_EFFECT)
{
if (defType == TYPE_FLYING && mod >= UQ_4_12(2.0))
mod = UQ_4_12(1.0);
@ -9147,7 +9223,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)
@ -9303,8 +9379,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;
}
@ -9345,15 +9433,15 @@ bool32 CanMegaEvolve(u8 battlerId)
// Check if trainer already mega evolved a pokemon.
if (mega->alreadyEvolved[battlerPosition])
return FALSE;
// Cannot use z move and mega evolve on same turn
if (gBattleStruct->zmove.toBeUsed[battlerId])
return FALSE; // cannot use z move and mega evolve on same turn
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)
@ -9389,14 +9477,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.
@ -9501,9 +9581,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))
@ -9697,17 +9776,13 @@ bool32 CanFling(u8 battlerId)
u16 itemEffect = ItemId_GetHoldEffect(item);
if (item == ITEM_NONE
#if B_KLUTZ_FLING_INTERACTION >= GEN_5
|| GetBattlerAbility(battlerId) == ABILITY_KLUTZ
#endif
|| gFieldStatuses & STATUS_FIELD_MAGIC_ROOM
|| gDisableStructs[battlerId].embargoTimer != 0
|| !CanBattlerGetOrLoseItem(battlerId, item)
//|| itemEffect == HOLD_EFFECT_PRIMAL_ORB
|| itemEffect == HOLD_EFFECT_GEMS
#ifdef ITEM_ABILITY_CAPSULE
|| item == ITEM_ABILITY_CAPSULE
#endif
|| (ItemId_GetPocket(item) == POCKET_BERRIES && IsAbilityOnSide(battlerId, ABILITY_UNNERVE))
|| GetPocketByItemId(item) == POCKET_POKE_BALLS)
|| ItemId_GetFlingPower(item) != 0
|| !CanBattlerGetOrLoseItem(battlerId, item))
return FALSE;
return TRUE;
@ -10068,7 +10143,7 @@ bool32 BlocksPrankster(u16 move, u8 battlerPrankster, u8 battlerDef, bool32 chec
return FALSE;
if (GetBattlerSide(battlerPrankster) == GetBattlerSide(battlerDef))
return FALSE;
if (checkTarget && (gBattleMoves[move].target & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS)))
if (checkTarget && (GetBattlerMoveTargetType(battlerPrankster, move) & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_DEPENDS)))
return FALSE;
if (!IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK))
return FALSE;
@ -10087,10 +10162,7 @@ u16 GetUsedHeldItem(u8 battler)
bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags)
{
if (!WEATHER_HAS_EFFECT)
return FALSE;
if (gBattleWeather & weatherFlags)
if (gBattleWeather & weatherFlags && WEATHER_HAS_EFFECT)
{
// given weather is active -> check if its sun, rain against utility umbrella ( since only 1 weather can be active at once)
if (gBattleWeather & (B_WEATHER_SUN | B_WEATHER_RAIN) && GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_UTILITY_UMBRELLA)
@ -10100,3 +10172,25 @@ bool32 IsBattlerWeatherAffected(u8 battlerId, u32 weatherFlags)
}
return FALSE;
}
// Gets move target before redirection effects etc. are applied
// Possible return values are defined in battle.h following MOVE_TARGET_SELECTED
u32 GetBattlerMoveTargetType(u8 battlerId, u16 move)
{
u32 target;
if (gBattleMoves[move].effect == EFFECT_EXPANDING_FORCE
&& IsBattlerTerrainAffected(battlerId, STATUS_FIELD_PSYCHIC_TERRAIN))
return MOVE_TARGET_BOTH;
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

@ -26,6 +26,7 @@ void AllocateBattleResources(void)
gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack));
gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp));
gBattleResources->ai = AllocZeroed(sizeof(*gBattleResources->ai));
gBattleResources->aiData = AllocZeroed(sizeof(*gBattleResources->aiData));
gBattleResources->battleHistory = AllocZeroed(sizeof(*gBattleResources->battleHistory));
gLinkBattleSendBuffer = AllocZeroed(BATTLE_BUFFER_LINK_SIZE);
@ -57,6 +58,7 @@ void FreeBattleResources(void)
FREE_AND_SET_NULL(gBattleResources->battleCallbackStack);
FREE_AND_SET_NULL(gBattleResources->beforeLvlUp);
FREE_AND_SET_NULL(gBattleResources->ai);
FREE_AND_SET_NULL(gBattleResources->aiData);
FREE_AND_SET_NULL(gBattleResources->battleHistory);
FREE_AND_SET_NULL(gBattleResources);

Some files were not shown because too many files have changed in this diff Show More