Merge branch '_RHH/upcoming' into _RHH/pr/upcoming/lighting-expansion-v2
@ -23,9 +23,10 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using as a base?
|
||||
options:
|
||||
- 1.10.0 (Latest release)
|
||||
- 1.10.1 (Latest release)
|
||||
- master (default, unreleased bugfixes)
|
||||
- upcoming (Edge)
|
||||
- 1.10.0
|
||||
- 1.9.4
|
||||
- 1.9.3
|
||||
- 1.9.2
|
||||
|
||||
@ -23,9 +23,10 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using as a base?
|
||||
options:
|
||||
- 1.10.0 (Latest release)
|
||||
- 1.10.1 (Latest release)
|
||||
- master (default, unreleased bugfixes)
|
||||
- upcoming (Edge)
|
||||
- 1.10.0
|
||||
- 1.9.4
|
||||
- 1.9.3
|
||||
- 1.9.2
|
||||
|
||||
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
@ -23,9 +23,10 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using as a base?
|
||||
options:
|
||||
- 1.10.0 (Latest release)
|
||||
- 1.10.1 (Latest release)
|
||||
- master (default, unreleased bugfixes)
|
||||
- upcoming (Edge)
|
||||
- 1.10.0
|
||||
- 1.9.4
|
||||
- 1.9.3
|
||||
- 1.9.2
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# Pokeemerald-Expansion Changelogs
|
||||
|
||||
## 1.10.x
|
||||
- **[Version 1.10.1](docs/changelogs/1.10.x/1.10.1.md) - 🧹 Bugfix Release**
|
||||
- **[Version 1.10.0](docs/changelogs/1.10.x/1.10.0.md) - ✨ Feature Release**
|
||||
|
||||
## 1.9.x
|
||||
|
||||
@ -110,9 +110,9 @@ To compile the `modern` target with this toolchain, the subdirectories `lib`, `i
|
||||
|
||||
### Building with debug info
|
||||
|
||||
To build **pokeemerald.elf** with debug symbols under a modern toolchain:
|
||||
To build **pokeemerald.elf** with debug symbols and debug-compatible optimization under a modern toolchain:
|
||||
```bash
|
||||
make DINFO=1
|
||||
make debug
|
||||
```
|
||||
|
||||
# Useful additional tools
|
||||
|
||||
5
Makefile
@ -121,7 +121,7 @@ CPPFLAGS := $(INCLUDE_CPP_ARGS) -Wno-trigraphs -DMODERN=1 -DTESTING=$(TEST)
|
||||
ARMCC := $(PREFIX)gcc
|
||||
PATH_ARMCC := PATH="$(PATH)" $(ARMCC)
|
||||
CC1 := $(shell $(PATH_ARMCC) --print-prog-name=cc1) -quiet
|
||||
override CFLAGS += -mthumb -mthumb-interwork -O$(O_LEVEL) -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init
|
||||
override CFLAGS += -mthumb -mthumb-interwork -O$(O_LEVEL) -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init
|
||||
ifeq ($(ANALYZE),1)
|
||||
override CFLAGS += -fanalyzer
|
||||
endif
|
||||
@ -346,10 +346,13 @@ endif
|
||||
|
||||
$(C_BUILDDIR)/librfu_intr.o: CFLAGS := -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -fno-toplevel-reorder -Wno-pointer-to-int-cast
|
||||
$(C_BUILDDIR)/berry_crush.o: override CFLAGS += -Wno-address-of-packed-member
|
||||
$(C_BUILDDIR)/agb_flash.o: override CFLAGS += -fno-toplevel-reorder
|
||||
$(C_BUILDDIR)/pokedex_plus_hgss.o: CFLAGS := -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -std=gnu17 -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init
|
||||
# Annoyingly we can't turn this on just for src/data/trainers.h
|
||||
$(C_BUILDDIR)/data.o: CFLAGS += -fno-show-column -fno-diagnostics-show-caret
|
||||
|
||||
$(TEST_BUILDDIR)/%.o: CFLAGS := -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi -march=armv4t -Wno-pointer-to-int-cast -Werror -Wall -Wno-strict-aliasing -Wno-attribute-alias -Woverride-init
|
||||
|
||||
# Dependency rules (for the *.c & *.s sources to .o files)
|
||||
# Have to be explicit or else missing files won't be reported.
|
||||
|
||||
|
||||
91
README.md
@ -1,21 +1,58 @@
|
||||
# pokeemerald-expansion
|
||||
|
||||
### Important: DO NOT use GitHub's "Download Zip" option. Using this option will not download the commit history required to update your expansion version or merge other feature branches. Instead, please read [this guide](https://github.com/Pawkkie/Team-Aquas-Asset-Repo/wiki/The-Basics-of-GitHub) to learn how to fork the repository and clone locally from there.
|
||||
pokeemerald-expansion is ***a romhack base*** based off pret's [pokeemerald](https://github.com/pret/pokeemerald) decompilation project. ***It is NOT a playable romhack,*** but it has multiple features available to romhackers so that they can create their own games, so it's not meant to be played on its own.
|
||||
|
||||
## What is pokeemerald-expansion?
|
||||
|
||||
pokeemerald-expansion is a decomp hack base project based off pret's [pokeemerald](https://github.com/pret/pokeemerald) decompilation project. It's recommended that any new projects that plan on using it, to clone this repository instead of pret's vanilla repository, as we regurlarly incorporate pret's documentation changes. This is ***NOT*** a standalone romhack, and as such, most features will be unavailable and/or unbalanced if played as is.
|
||||
## Should I use this or vanilla pokeemerald for my hack?
|
||||
The main advantage of using vanilla pokeemerald as a base is being able to link with other official GBA Pokémon games for battles and trading, pokeemerald-expansion can battle and trade with itself out of the box. If you don't mind losing full vanilla compatiblitity, we recommend using pokeemerald-expansion. Otherwise, use pret's pokeemerald. You'll still receive documentation improvements from pret, as we regurlarly incorporate pret's documentation changes.
|
||||
|
||||
## Using pokeemerald-expansion
|
||||
|
||||
If you use pokeemerald-expansion in your hack, please add RHH (Rom Hacking Hideout) to your credits list. Optionally, you can list the version used, so it can help players know what features to expect.
|
||||
You can phrase it as the following:
|
||||
```
|
||||
Based off RHH's pokeemerald-expansion 1.10.0 https://github.com/rh-hideout/pokeemerald-expansion/
|
||||
Based off RHH's pokeemerald-expansion 1.10.1 https://github.com/rh-hideout/pokeemerald-expansion/
|
||||
```
|
||||
|
||||
#### Important: DO NOT use GitHub's "Download Zip" option. Using this option will not download the commit history required to update your expansion version or merge other feature branches. Instead, please read [this guide](https://github.com/Pawkkie/Team-Aquas-Asset-Repo/wiki/The-Basics-of-GitHub) to learn how to fork the repository and clone locally from there.
|
||||
|
||||
Please follow the instructions in `INSTALL.md` to get pokeemerald-expansion set up on your machine.
|
||||
|
||||
### If I already have a project based on regular pokeemerald, can I use pokeemerald-expansion?
|
||||
Yes! Keep in mind that we keep up with pret's documentation of pokeemerald, which means that if your project a bit old, you might get merge conflicts that you need to solve manually.
|
||||
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
|
||||
- Once you have your remote set up, run the command `git pull RHH master`.
|
||||
|
||||
With this, you'll get the latest version of pokeemerald-expansion, plus a couple of bugfixes that haven't yet been released into the next patch version :)
|
||||
|
||||
## Documentation
|
||||
[Please click here to visit our documentation page.](https://rh-hideout.github.io/pokeemerald-expansion/)
|
||||
|
||||
## **How do I update my version of pokeemerald-expansion?**
|
||||
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
|
||||
- Check your current version.
|
||||
- You can check in the debug menu's `Utilities -> Expansion Version` option.
|
||||
- If the option is not available, you possibly have version 1.6.2 or older. In that case, please check the [changelogs](docs/CHANGELOG.md) to determine your version based on the features available on your repository.
|
||||
- ***Important:*** If you are several versions behind, we recommend updating one minor version at a time, skipping directly to the latest patch version (eg, 1.5.3 -> 1.6.2 -> 1.7.4 and so on. Check the [online documentation site](https://rh-hideout.github.io/pokeemerald-expansion/CHANGELOG.html) to see the latest versions of each step.)
|
||||
- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.9.3, use `git pull RHH expansion/1.9.3`).
|
||||
- ***Important:*** If you are several versions behind, we recommend updating one minor version at a time, skipping directly to the latest patch version (eg, 1.5.3 -> 1.6.2 -> 1.7.4 and so on)
|
||||
- Alternatively, you can update to unreleased versions of the expansion.
|
||||
- ***master (stable):*** It contains unreleased **bugfixes** that will come in the next patch version. To merge, use `git pull RHH master`.
|
||||
- ***upcoming (unstable, with potential bugs):*** It contains unreleased **features** that will come in the next minor version. To merge, use `git pull RHH upcoming`.
|
||||
|
||||
### Please consider crediting the entire [list of contributors](https://github.com/rh-hideout/pokeemerald-expansion/wiki/Credits) in your project, as they have all worked hard to develop this project :)
|
||||
|
||||
## Who maintains the project?
|
||||
The project was originally started by DizzyEgg alongside other contributors. Now it is maintained by a team in the ROM Hacking Hideout's community called the "Expansion Senate". ROM Hacking Hideout (RHH for short) is a Discord-based ROM hacking community specialized in Pokémon romhacks. A lot of the discussion in regards of the development of the project happens there.
|
||||
|
||||
[Click here to join the RHH Discord Server!](https://discord.gg/6CzjAG6GZk)
|
||||
|
||||
## There's a bug in the project. How do I let you guys know?
|
||||
Please submit any issues with the project [here](https://github.com/rh-hideout/pokeemerald-expansion/issues) and make sure that the issue wasn't reported by someone else by searching using the filters. You may also join the Discord server to try getting more in-depth support from the team and other members of the server.
|
||||
|
||||
## Can I contribute even if I'm not a member of ROM Hacking Hideout?
|
||||
Yes! Contributions are welcome via Pull Requests and they will be reviewed by maintainers in due time.
|
||||
Also, *please follow the Pull Request template and feel free to discuss how the reviews are being handled. **Communication is key!*** Don't feel discouraged if we take a bit to review your PR, we'll get to it.
|
||||
|
||||
## What features are included?
|
||||
- ***IMPORTANT*❗❗ Read through these to learn what features you can toggle**:
|
||||
- [Battle configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/battle.h)
|
||||
@ -160,46 +197,4 @@ Please follow the instructions in `INSTALL.md` to get pokeemerald-expansion set
|
||||
- All bugfixes from pret included.
|
||||
- Fixed overworld snow effect.
|
||||
|
||||
There are some mechanics, moves and abilities that are missing and being developed. Check [the project's milestones](https://github.com/rh-hideout/pokeemerald-expansion/milestones) to see which ones.
|
||||
|
||||
|
||||
### [Documentation on features can be found here](https://github.com/rh-hideout/pokeemerald-expansion/wiki)
|
||||
|
||||
## If I already have a project based on regular pokeemerald, can I use pokeemerald-expansion?
|
||||
Yes! Keep in mind that we keep up with pret's documentation of pokeemerald, which means that if your project a bit old, you might get merge conflicts that you need to solve manually.
|
||||
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
|
||||
- Once you have your remote set up, run the command `git pull RHH master`.
|
||||
|
||||
With this, you'll get the latest version of pokeemerald-expansion, plus a couple of bugfixes that haven't been released into the next patch version :)
|
||||
|
||||
## **How do I update my version of pokeemerald-expansion?**
|
||||
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
|
||||
- Check your current version.
|
||||
- You can check in the debug menu's `Utilities -> Expansion Version` option.
|
||||
- If the option is not available, you possibly have version 1.6.2 or older. In that case, please check the [changelogs](CHANGELOG.md) to determine your version based on the features available on your repository.
|
||||
- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.10.0, use `git pull RHH expansion/1.10.0`).
|
||||
- ***Important:*** If you are several versions behind, we recommend updating one minor version at a time, skipping directly to the latest patch version (eg, 1.5.3 -> 1.6.2 -> 1.7.4 and so on)
|
||||
- Alternatively, you can update to unreleased versions of the expansion.
|
||||
- ***master (stable):*** It contains unreleased **bugfixes** that will come in the next patch version. To merge, use `git pull RHH master`.
|
||||
- ***upcoming (unstable, with potential bugs):*** It contains unreleased **features** that will come in the next minor version. To merge, use `git pull RHH upcoming`.
|
||||
|
||||
### Please consider crediting the entire [list of contributors](https://github.com/rh-hideout/pokeemerald-expansion/wiki/Credits) in your project, as they have all worked hard to develop this project :)
|
||||
|
||||
## There's a bug in the project. How do I let you guys know?
|
||||
Please submit any issues with the project [here](https://github.com/rh-hideout/pokeemerald-expansion/issues). Make sure that the issue wasn't reported by someone else by searching using the filters.
|
||||
|
||||
## Can I contribute even if I'm not a member of ROM Hacking Hideout?
|
||||
|
||||
Yes! Contributions are welcome via Pull Requests and they will be reviewed by maintainers. Don't feel discouraged if we take a bit to review your PR, we'll get to it.
|
||||
|
||||
## Who maintains the project?
|
||||
|
||||
The project was originally started by DizzyEgg alongside other contributors.
|
||||
|
||||
The project has now gotten larger and DizzyEgg is now maintaining the project as part of the ROM Hacking Hideout community. Some members of this community are taking on larger roles to help maintain the project.
|
||||
|
||||
## What is the ROM Hacking Hideout?
|
||||
|
||||
A Discord-based ROM hacking community that has many members who hack using the disassembly and decompilation projects for Pokémon. Quite a few contributors to the original feature branches by DizzyEgg were members of ROM Hacking Hideout. You can call it RHH for short!
|
||||
|
||||
[Click here to join the RHH Discord Server!](https://discord.gg/6CzjAG6GZk)
|
||||
There are some mechanics, moves and abilities that are missing and being developed. Check [the project's milestones](https://github.com/rh-hideout/pokeemerald-expansion/milestones) and our [issues page](https://github.com/rh-hideout/pokeemerald-expansion/issues) to see which ones.
|
||||
|
||||
@ -1426,11 +1426,6 @@
|
||||
callnative BS_TryRevertWeatherForm
|
||||
.endm
|
||||
|
||||
.macro applysaltcure battler:req
|
||||
callnative BS_ApplySaltCure
|
||||
.byte \battler
|
||||
.endm
|
||||
|
||||
.macro trysetoctolock battler:req, failInstr:req
|
||||
callnative BS_TrySetOctolock
|
||||
.byte \battler
|
||||
@ -1525,8 +1520,8 @@
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifargument argument:req, jumpInstr:req
|
||||
callnative BS_JumpIfArgument
|
||||
.macro jumpifmovepropertyargument argument:req, jumpInstr:req
|
||||
callnative BS_JumpIfMovePropertyArgument
|
||||
.byte \argument
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
@ -2242,11 +2237,6 @@
|
||||
.4byte \jumpInstr
|
||||
.endm
|
||||
|
||||
.macro eeriespellppreduce failInstr:req
|
||||
various BS_TARGET, VARIOUS_EERIE_SPELL_PP_REDUCE
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro jumpifteamhealthy battler:req, jumpInstr:req
|
||||
various \battler, VARIOUS_JUMP_IF_TEAM_HEALTHY
|
||||
.4byte \jumpInstr
|
||||
|
||||
@ -350,34 +350,27 @@ gBattleAnimMove_MetalBurst::
|
||||
waitforvisualfinish
|
||||
end
|
||||
|
||||
@Credits: Skeli
|
||||
gBattleAnimMove_UTurn::
|
||||
loadspritegfx ANIM_TAG_ROUND_SHADOW
|
||||
loadspritegfx ANIM_TAG_SMALL_BUBBLES
|
||||
loadspritegfx ANIM_TAG_RAZOR_LEAF
|
||||
loadspritegfx ANIM_TAG_IMPACT
|
||||
monbg ANIM_DEF_PARTNER
|
||||
setalpha 12, 8
|
||||
playsewithpan SE_M_FLY, SOUND_PAN_ATTACKER
|
||||
createsprite gFlyBallUpSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 13, 336
|
||||
playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_ATTACKER
|
||||
createvisualtask AnimTask_CanBattlerSwitch, 1, ANIM_ATTACKER
|
||||
jumpretfalse UTurnVisible
|
||||
createsprite gFlyBallAttackSpriteTemplate, ANIM_ATTACKER, 2, 20, TRUE
|
||||
UTurnContinue:
|
||||
delay 20
|
||||
createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 1, 0
|
||||
createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 6, 0, 8, 1
|
||||
playsewithpan SE_M_RAZOR_WIND, SOUND_PAN_TARGET
|
||||
waitforvisualfinish
|
||||
clearmonbg ANIM_DEF_PARTNER
|
||||
createvisualtask AnimTask_CanBattlerSwitch, 1, ANIM_ATTACKER
|
||||
jumpretfalse UTurnLast
|
||||
splitbgprio ANIM_TARGET
|
||||
setalpha 8, 8
|
||||
invisible ANIM_ATTACKER
|
||||
UTurnLast:
|
||||
blendoff
|
||||
playsewithpan SE_M_JUMP_KICK, SOUND_PAN_ATTACKER
|
||||
createsprite gUTurnBallSpriteTemplate, ANIM_TARGET, 2, 0, 0, 21
|
||||
waitforvisualfinish
|
||||
playsewithpan SE_M_TAIL_WHIP, SOUND_PAN_ATTACKER
|
||||
createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 2, 0x0, 0x0, 1, 2
|
||||
createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 6, 1
|
||||
createsprite gUTurnBallBackSpriteTemplate, ANIM_ATTACKER, 3, 4, 0, -16, 36
|
||||
waitforvisualfinish
|
||||
visible ANIM_ATTACKER
|
||||
clearmonbg ANIM_TARGET
|
||||
blendoff
|
||||
end
|
||||
UTurnVisible:
|
||||
createsprite gFlyBallAttackSpriteTemplate, ANIM_ATTACKER, 2, 20, FALSE
|
||||
goto UTurnContinue
|
||||
|
||||
gBattleAnimMove_CloseCombat::
|
||||
loadspritegfx ANIM_TAG_IMPACT
|
||||
|
||||
@ -404,16 +404,10 @@ BattleScript_EffectHit_Pledge::
|
||||
tryfaintmon BS_TARGET
|
||||
return
|
||||
|
||||
BattleScript_EffectSaltCure::
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
jumpiffainted BS_TARGET, TRUE, BattleScript_EffectSaltCure_End
|
||||
jumpifsubstituteblocks BattleScript_EffectSaltCure_End
|
||||
applysaltcure BS_TARGET
|
||||
BattleScript_MoveEffectSaltCure::
|
||||
printstring STRINGID_TARGETISBEINGSALTCURED
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_EffectSaltCure_End:
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_SaltCureExtraDamage::
|
||||
playanimation BS_TARGET, B_ANIM_SALT_CURE_DAMAGE, NULL
|
||||
@ -421,13 +415,13 @@ BattleScript_SaltCureExtraDamage::
|
||||
call BattleScript_HurtTarget_NoString
|
||||
printstring STRINGID_TARGETISHURTBYSALTCURE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryfaintmon BS_TARGET
|
||||
end2
|
||||
|
||||
BattleScript_HurtTarget_NoString:
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE
|
||||
healthbarupdate BS_TARGET
|
||||
datahpupdate BS_TARGET
|
||||
tryfaintmon BS_TARGET
|
||||
return
|
||||
|
||||
BattleScript_EffectCorrosiveGas::
|
||||
@ -957,13 +951,10 @@ BattleScript_HyperspaceFuryRemoveProtect::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_EffectPlasmaFists::
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
orword gFieldStatuses, STATUS_FIELD_ION_DELUGE
|
||||
BattleScript_MoveEffectIonDeluge::
|
||||
printstring STRINGID_IONDELUGEON
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_EffectSparklySwirl::
|
||||
call BattleScript_EffectHit_Ret
|
||||
@ -974,41 +965,25 @@ BattleScript_EffectSparklySwirl::
|
||||
waitstate
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectFreezyFrost::
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
normalisebuffs
|
||||
BattleScript_MoveEffectHaze::
|
||||
printstring STRINGID_STATCHANGESGONE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_EffectSappySeed::
|
||||
jumpifstatus3 BS_TARGET, STATUS3_LEECHSEED, BattleScript_EffectHit
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
jumpifhasnohp BS_TARGET, BattleScript_MoveEnd
|
||||
setseeded
|
||||
printfromtable gLeechSeedStringIds
|
||||
BattleScript_MoveEffectLeechSeed::
|
||||
printstring STRINGID_PKMNSEEDED
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectBaddyBad::
|
||||
jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_REFLECT, BattleScript_EffectHit
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
setreflect
|
||||
BattleScript_MoveEffectReflect::
|
||||
printfromtable gReflectLightScreenSafeguardStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_EffectGlitzyGlow::
|
||||
jumpifsideaffecting BS_ATTACKER, SIDE_STATUS_LIGHTSCREEN, BattleScript_EffectHit
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
setlightscreen
|
||||
BattleScript_MoveEffectLightScreen::
|
||||
printfromtable gReflectLightScreenSafeguardStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_EffectStuffCheeks::
|
||||
attackcanceler
|
||||
@ -4087,13 +4062,10 @@ BattleScript_EffectDestinyBond::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectEerieSpell::
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
eeriespellppreduce BattleScript_MoveEnd
|
||||
BattleScript_MoveEffectEerieSpell::
|
||||
printstring STRINGID_PKMNREDUCEDPP
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_EffectSpite::
|
||||
attackcanceler
|
||||
@ -5927,8 +5899,7 @@ BattleScript_OverworldStatusStarts::
|
||||
|
||||
BattleScript_OverworldStatusStarts_TryActivations:
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SET_TRICK_ROOM, BattleScript_TryRoomServiceLoop
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SET_TAILWIND_PLAYER, BattleScript_TryTailwindAbilitiesLoop
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SET_TAILWIND_OPPONENT, BattleScript_TryTailwindAbilitiesLoop
|
||||
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_SET_TAILWIND, BattleScript_TryTailwindAbilitiesLoop
|
||||
return
|
||||
|
||||
BattleScript_OverworldWeatherStarts::
|
||||
@ -6747,7 +6718,7 @@ BattleScript_WishComesTrue::
|
||||
playanimation BS_TARGET, B_ANIM_WISH_HEAL
|
||||
printstring STRINGID_PKMNWISHCAMETRUE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
|
||||
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE
|
||||
healthbarupdate BS_TARGET
|
||||
datahpupdate BS_TARGET
|
||||
printstring STRINGID_PKMNREGAINEDHEALTH
|
||||
@ -7588,13 +7559,8 @@ BattleScript_AbilityPopUp:
|
||||
return
|
||||
|
||||
BattleScript_AbilityPopUpScripting:
|
||||
.if B_ABILITY_POP_UP == TRUE
|
||||
showabilitypopup BS_SCRIPTING
|
||||
pause 40
|
||||
.endif
|
||||
recordability BS_SCRIPTING
|
||||
sethword sABILITY_OVERWRITE, 0
|
||||
return
|
||||
copybyte gBattlerAbility, sBATTLER
|
||||
goto BattleScript_AbilityPopUp
|
||||
|
||||
BattleScript_AbilityPopUpOverwriteThenNormal:
|
||||
setbyte sFIXED_ABILITY_POPUP, TRUE
|
||||
@ -8366,7 +8332,6 @@ BattleScript_GrassyTerrainLoopIncrement::
|
||||
addbyte gBattleCommunication, 1
|
||||
jumpifbytenotequal gBattleCommunication, gBattlersCount, BattleScript_GrassyTerrainLoop
|
||||
bicword gHitMarker, HITMARKER_IGNORE_BIDE | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE
|
||||
jumpifword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_PERMANENT, BattleScript_GrassyTerrainHealEnd
|
||||
BattleScript_GrassyTerrainHealEnd:
|
||||
return
|
||||
|
||||
@ -9489,7 +9454,7 @@ BattleScript_EffectHitSetRemoveTerrain::
|
||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||
attackstring
|
||||
ppreduce
|
||||
jumpifargument ARG_TRY_REMOVE_TERRAIN_FAIL, BattleScript_RemoveTerrain
|
||||
jumpifmovepropertyargument ARG_TRY_REMOVE_TERRAIN_FAIL, BattleScript_RemoveTerrain
|
||||
critcalc
|
||||
damagecalc
|
||||
adjustdamage
|
||||
@ -9639,13 +9604,6 @@ BattleScript_EjectPackActivates::
|
||||
jumpifcantswitch BS_SCRIPTING, BattleScript_EjectButtonEnd
|
||||
goto BattleScript_EjectPackActivate_Ret
|
||||
|
||||
BattleScript_EjectPackMissesTiming::
|
||||
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT
|
||||
printstring STRINGID_EJECTBUTTONACTIVATE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
removeitem BS_SCRIPTING
|
||||
return
|
||||
|
||||
BattleScript_DarkTypePreventsPrankster::
|
||||
attackstring
|
||||
ppreduce
|
||||
|
||||
@ -1151,3 +1151,4 @@ EventScript_VsSeekerChargingDone::
|
||||
.include "data/scripts/follower.inc"
|
||||
.include "data/text/save.inc"
|
||||
.include "data/text/birch_speech.inc"
|
||||
.include "data/scripts/dexnav.inc"
|
||||
|
||||
@ -25,9 +25,9 @@ gFieldEffectScriptPointers::
|
||||
.4byte gFieldEffectScript_JumpSmallSplash @ FLDEFF_JUMP_SMALL_SPLASH
|
||||
.4byte gFieldEffectScript_LongGrass @ FLDEFF_LONG_GRASS
|
||||
.4byte gFieldEffectScript_JumpLongGrass @ FLDEFF_JUMP_LONG_GRASS
|
||||
.4byte gFieldEffectScript_UnusedGrass @ FLDEFF_UNUSED_GRASS
|
||||
.4byte gFieldEffectScript_UnusedGrass2 @ FLDEFF_UNUSED_GRASS_2
|
||||
.4byte gFieldEffectScript_UnusedSand @ FLDEFF_UNUSED_SAND
|
||||
.4byte gFieldEffectScript_ShakingGrass @ FLDEFF_SHAKING_GRASS
|
||||
.4byte gFieldEffectScript_ShakingGrass2 @ FLDEFF_SHAKING_LONG_GRASS
|
||||
.4byte gFieldEffectScript_UnusedSand @ FLDEFF_SAND_HOLE
|
||||
.4byte gFieldEffectScript_WaterSurfacing @ FLDEFF_WATER_SURFACING
|
||||
.4byte gFieldEffectScript_BerryTreeGrowthSparkle @ FLDEFF_BERRY_TREE_GROWTH_SPARKLE
|
||||
.4byte gFieldEffectScript_DeepSandFootprints @ FLDEFF_DEEP_SAND_FOOTPRINTS
|
||||
@ -79,7 +79,8 @@ gFieldEffectScriptPointers::
|
||||
.4byte gFieldEffectScript_TracksSlither @ FLDEFF_TRACKS_SLITHER
|
||||
.4byte gFieldEffectScript_TracksBug @ FLDEFF_TRACKS_BUG
|
||||
.4byte gFieldEffectScript_TracksSpot @ FLDEFF_TRACKS_SPOT
|
||||
|
||||
.4byte gFieldEffectScript_CaveDust @ FLDEFF_CAVE_DUST
|
||||
|
||||
gFieldEffectScript_ExclamationMarkIcon1::
|
||||
field_eff_callnative FldEff_ExclamationMarkIcon
|
||||
field_eff_end
|
||||
@ -156,12 +157,12 @@ gFieldEffectScript_JumpLongGrass::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_GeneralFieldEffect1, FldEff_JumpLongGrass
|
||||
field_eff_end
|
||||
|
||||
gFieldEffectScript_UnusedGrass::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_GeneralFieldEffect1, FldEff_UnusedGrass
|
||||
gFieldEffectScript_ShakingGrass::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_GeneralFieldEffect1, FldEff_ShakingGrass
|
||||
field_eff_end
|
||||
|
||||
gFieldEffectScript_UnusedGrass2::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_GeneralFieldEffect1, FldEff_UnusedGrass2
|
||||
gFieldEffectScript_ShakingGrass2::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_GeneralFieldEffect1, FldEff_ShakingGrass2
|
||||
field_eff_end
|
||||
|
||||
gFieldEffectScript_UnusedSand::
|
||||
@ -374,3 +375,7 @@ gFieldEffectScript_TracksSpot::
|
||||
gFieldEffectScript_TracksSlither::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_GeneralFieldEffect0, FldEff_TracksSlither
|
||||
field_eff_end
|
||||
|
||||
gFieldEffectScript_CaveDust::
|
||||
field_eff_loadfadedpal_callnative gSpritePalette_CaveDust FldEff_CaveDust
|
||||
field_eff_end
|
||||
|
||||
47
data/scripts/dexnav.inc
Normal file
@ -0,0 +1,47 @@
|
||||
EventScript_StartDexNavBattle::
|
||||
lock
|
||||
playse SE_PIN
|
||||
applymovement OBJ_EVENT_ID_PLAYER Common_Movement_ExclamationMark
|
||||
waitmovement 0
|
||||
waitse
|
||||
dowildbattle
|
||||
release
|
||||
end
|
||||
|
||||
EventScript_NotFoundNearby::
|
||||
msgbox sText_NotFoundNearby, MSGBOX_SIGN
|
||||
end
|
||||
|
||||
EventScript_MovedTooFast::
|
||||
msgbox sText_TryMovingSlower, MSGBOX_SIGN
|
||||
end
|
||||
|
||||
EventScript_PokemonGotAway::
|
||||
msgbox sText_PokemonGotAway, MSGBOX_SIGN
|
||||
end
|
||||
|
||||
EventScript_LostSignal::
|
||||
msgbox sText_LostSignal, MSGBOX_SIGN
|
||||
end
|
||||
|
||||
EventScript_TooDark::
|
||||
msgbox sText_TooDark, MSGBOX_SIGN
|
||||
end
|
||||
|
||||
sText_NotFoundNearby:
|
||||
.string "It couldn't be found nearby.\n"
|
||||
.string "Try looking in a different area!$"
|
||||
|
||||
sText_TryMovingSlower:
|
||||
.string "The Pokémon got away!\n"
|
||||
.string "Try moving more slowly.$"
|
||||
|
||||
sText_PokemonGotAway:
|
||||
.string "The Pokémon got away!$"
|
||||
|
||||
sText_LostSignal:
|
||||
.string "There is no reaction.\n"
|
||||
.string "The signal was lost!$"
|
||||
|
||||
sText_TooDark:
|
||||
.string "It's too dark to search\nfor a Pokémon!$"
|
||||
@ -21,6 +21,7 @@
|
||||
- [Day/Night System FAQ](tutorials/dns.md)
|
||||
- [Changelog](./CHANGELOG.md)
|
||||
- [1.10.x]()
|
||||
- [Version 1.10.1](changelogs/1.10.x/1.10.1.md)
|
||||
- [Version 1.10.0](changelogs/1.10.x/1.10.0.md)
|
||||
- [1.9.x]()
|
||||
- [Version 1.9.4](changelogs/1.9.x/1.9.4.md)
|
||||
|
||||
140
docs/changelogs/1.10.x/1.10.1.md
Normal file
@ -0,0 +1,140 @@
|
||||
# Version 1.10.1
|
||||
|
||||
```md
|
||||
## How to update
|
||||
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
|
||||
- Once you have your remote set up, run the command `git pull RHH expansion/1.10.1`.
|
||||
```
|
||||
|
||||
## 🧬 General 🧬
|
||||
### Added
|
||||
* Added `FONT_SHORT_NARROWER` by @AsparagusEduardo (commit originally by @agsmgmaster64) in [#5101](https://github.com/rh-hideout/pokeemerald-expansion/pull/5101)
|
||||
* Narrower font tweaks and font fitting fixes by @kittenchilly in [#5782](https://github.com/rh-hideout/pokeemerald-expansion/pull/5782)
|
||||
|
||||
### Changed
|
||||
* Adds Thief/Covet config to send stolen item to bag and Pickup config to pickup user's item in wild battles by @PhallenTree in [#5829](https://github.com/rh-hideout/pokeemerald-expansion/pull/5829)
|
||||
|
||||
### Fixed
|
||||
* trainerproc: Fix showing incorrect error context by @mrgriffin in [#5769](https://github.com/rh-hideout/pokeemerald-expansion/pull/5769)
|
||||
* Fixes UB in caps.c by @AlexOn1ine in [#5878](https://github.com/rh-hideout/pokeemerald-expansion/pull/5878)
|
||||
|
||||
## 🗺️ Overworld 🗺️
|
||||
### Fixed
|
||||
* Fix Off-by-One Error in Move Relearner by @iriv24 and @luckytyphlosion in [#5778](https://github.com/rh-hideout/pokeemerald-expansion/pull/5778)
|
||||
* Fix HGSS dex sort orders working incorrectly by @ravepossum in [#5790](https://github.com/rh-hideout/pokeemerald-expansion/pull/5790)
|
||||
* Egg cycle length fix by @hedara90 and @/BolaDeQueijo on discord discovered the issue. in [#5828](https://github.com/rh-hideout/pokeemerald-expansion/pull/5828)
|
||||
* Fixed givemon not respecting perfect IVs for species by @AsparagusEduardo in [#5873](https://github.com/rh-hideout/pokeemerald-expansion/pull/5873)
|
||||
- Also removed redundant `RemoveIVIndexFromList` function in `src/daycare.c`, so it uses `src/pokemon.c`'s instead
|
||||
* Fix Script Scrollable Multichoice Arrow Positions by @ghoulslash in [#5884](https://github.com/rh-hideout/pokeemerald-expansion/pull/5884)
|
||||
|
||||
## 🐉 Pokémon 🐉
|
||||
### Changed
|
||||
* Updated Ogerpon, Enamorus and Sinistcha sprites by @kittenchilly in [#5793](https://github.com/rh-hideout/pokeemerald-expansion/pull/5793)
|
||||
* New Enamorus-Incarnate sprite by @kittenchilly in [#5797](https://github.com/rh-hideout/pokeemerald-expansion/pull/5797)
|
||||
|
||||
### Fixed
|
||||
* Fixes Wormadam define for teachable learnset script by @AlexOn1ine in [#5783](https://github.com/rh-hideout/pokeemerald-expansion/pull/5783)
|
||||
* Fix "PlantCloak" references by @AsparagusEduardo in [#5821](https://github.com/rh-hideout/pokeemerald-expansion/pull/5821)
|
||||
* Misc pokemon sprite fixes by @Cafeei in [#5846](https://github.com/rh-hideout/pokeemerald-expansion/pull/5846)
|
||||
|
||||
## ⚔️ Battle General ⚔️
|
||||
### Changed
|
||||
* Adds Thief/Covet config to send stolen item to bag and Pickup config to pickup user's item in wild battles by @PhallenTree in [#5829](https://github.com/rh-hideout/pokeemerald-expansion/pull/5829)
|
||||
|
||||
### Fixed
|
||||
* Fixes items preventing other switch in effects by @AlexOn1ine in [#5732](https://github.com/rh-hideout/pokeemerald-expansion/pull/5732)
|
||||
* Fix Pokemon with No Guard failing OHKO Moves into Semi-Invulnerable Pokemon by @iriv24 and @Cafeei in [#5779](https://github.com/rh-hideout/pokeemerald-expansion/pull/5779)
|
||||
* Fix move category and category icon when PSS is off by @ravepossum in [#5786](https://github.com/rh-hideout/pokeemerald-expansion/pull/5786)
|
||||
* Added the missing config to use new terrains by @hedara90 in [#5792](https://github.com/rh-hideout/pokeemerald-expansion/pull/5792)
|
||||
* Fixes Shed Tail substitute health by @AlexOn1ine in [#5826](https://github.com/rh-hideout/pokeemerald-expansion/pull/5826)
|
||||
* `B_LAST_USED_BALL` and `.importance` by @AERDU in [#5834](https://github.com/rh-hideout/pokeemerald-expansion/pull/5834)
|
||||
- prevents `B_LAST_USED_BALL` from removing balls with `.importance = 1`
|
||||
* Fixes Quash-affected battlers having the wrong order for End Turn effects by @PhallenTree in [#5838](https://github.com/rh-hideout/pokeemerald-expansion/pull/5838)
|
||||
* Fixes Cotton Down and Gulp Missile not interacting correctly with stat reduction prevention effects by @PhallenTree in [#5841](https://github.com/rh-hideout/pokeemerald-expansion/pull/5841)
|
||||
* Fix Hit Escape moves giving Exp to the mon that switches in by @kittenchilly in [#5844](https://github.com/rh-hideout/pokeemerald-expansion/pull/5844)
|
||||
* Fixed Wish triggering Disguise by @AsparagusEduardo in [#5860](https://github.com/rh-hideout/pokeemerald-expansion/pull/5860)
|
||||
* Fixed `MOVE_EFFECT_FREEZE_OR_FROSTBITE` not being usable in battle scripts by @AsparagusEduardo in [#5859](https://github.com/rh-hideout/pokeemerald-expansion/pull/5859)
|
||||
* Fixed Ally Switch breaking Illusion by @AsparagusEduardo in [#5879](https://github.com/rh-hideout/pokeemerald-expansion/pull/5879)
|
||||
* Fixes gen3 Style Shadows out of place by @AlexOn1ine in [#5880](https://github.com/rh-hideout/pokeemerald-expansion/pull/5880)
|
||||
* Fix Salt Cure script by @ghoulslash in [#5895](https://github.com/rh-hideout/pokeemerald-expansion/pull/5895)
|
||||
* Fixes Eject Pack / Intimidate issue by @AlexOn1ine in [#5902](https://github.com/rh-hideout/pokeemerald-expansion/pull/5902)
|
||||
* Adds Generational config for Magic Guard (Fix for Gen4+) by @AlexOn1ine in [#5893](https://github.com/rh-hideout/pokeemerald-expansion/pull/5893)
|
||||
* Fixes Stance Change, Sleep Talk interaction by @AlexOn1ine in [#5909](https://github.com/rh-hideout/pokeemerald-expansion/pull/5909)
|
||||
* Fixes Round doubling it's BP if previous Round failed by @AlexOn1ine in [#5907](https://github.com/rh-hideout/pokeemerald-expansion/pull/5907)
|
||||
|
||||
## 🤹 Moves 🤹
|
||||
### Fixed
|
||||
* Fixes absorb still draining HP when flinched by @AlexOn1ine in [#5814](https://github.com/rh-hideout/pokeemerald-expansion/pull/5814)
|
||||
* Fixes Tidy Up by @AlexOn1ine in [#5819](https://github.com/rh-hideout/pokeemerald-expansion/pull/5819)
|
||||
* Ally Switch extra battlerId tracking by @ghoulslash in [#5823](https://github.com/rh-hideout/pokeemerald-expansion/pull/5823)
|
||||
* Sheer Force fix and move effect cleanup by @AlexOn1ine in [#5812](https://github.com/rh-hideout/pokeemerald-expansion/pull/5812)
|
||||
* New U-turn animation to fix visibility by @AlexOn1ine in [#5910](https://github.com/rh-hideout/pokeemerald-expansion/pull/5910)
|
||||
|
||||
## 🧶 Items 🧶
|
||||
### Fixed
|
||||
* Prevent Key Items that open other menus from causing a crash if registered and used from the field by @iriv24 in [#5810](https://github.com/rh-hideout/pokeemerald-expansion/pull/5810)
|
||||
* Fixes Clear Amulet displaying the wrong battler and Starting Status displaying the wrong message by @PhallenTree in [#5831](https://github.com/rh-hideout/pokeemerald-expansion/pull/5831)
|
||||
* Fixes Room Service lowering the opposite mon in specific scenario by @AlexOn1ine in [#5827](https://github.com/rh-hideout/pokeemerald-expansion/pull/5827)
|
||||
|
||||
## 🤖 Battle AI 🤖
|
||||
### Fixed
|
||||
* Fixed ace switching bugs by @Pawkkie and @iriv24 for their diligent testing and debugging support in [#5922](https://github.com/rh-hideout/pokeemerald-expansion/pull/5922)
|
||||
|
||||
## 🧹 Other Cleanup 🧹
|
||||
* Converted Stance Change to proper Form Change + Tests by @AsparagusEduardo in [#5749](https://github.com/rh-hideout/pokeemerald-expansion/pull/5749)
|
||||
* Removed testing strings for automatic line breaks by @hedara90 in [#5757](https://github.com/rh-hideout/pokeemerald-expansion/pull/5757)
|
||||
* Added NBSP and up+down arrows to all fonts by @hedara90 in [#5767](https://github.com/rh-hideout/pokeemerald-expansion/pull/5767)
|
||||
- Use `~` or `{NBSP}` to insert a non-breaking space into a string.
|
||||
* Palette cleanup by @hedara90 in [#5661](https://github.com/rh-hideout/pokeemerald-expansion/pull/5661)
|
||||
- Resized some move anim palettes from 256 to 16
|
||||
* Replace power checks with IS_MOVE_STATUS by @Bassoonian and @AsparagusEduardo in [#5820](https://github.com/rh-hideout/pokeemerald-expansion/pull/5820)
|
||||
* Changes Various defines to an Enum by @AsparagusEduardo in [#5840](https://github.com/rh-hideout/pokeemerald-expansion/pull/5840)
|
||||
* Fix `IS_MOVE_STATUS` regression by @Bassoonian in [#5848](https://github.com/rh-hideout/pokeemerald-expansion/pull/5848)
|
||||
* Remove unused various by @Bassoonian in [#5851](https://github.com/rh-hideout/pokeemerald-expansion/pull/5851)
|
||||
* Removed redundant call to FillPalBufferBlack in FRLG whiteout sequence by @AsparagusEduardo in [#5854](https://github.com/rh-hideout/pokeemerald-expansion/pull/5854)
|
||||
* Improve README.md by @AsparagusEduardo in [#5640](https://github.com/rh-hideout/pokeemerald-expansion/pull/5640)
|
||||
* Fix wrong value for NUM_MOVE_EFFECTS by @Bassoonian in [#5913](https://github.com/rh-hideout/pokeemerald-expansion/pull/5913)
|
||||
* Renamed OW type effectiveness function for clarity by @AsparagusEduardo in [#5917](https://github.com/rh-hideout/pokeemerald-expansion/pull/5917)
|
||||
- Renamed `GetTypeEffectiveness` to `GetOverworldTypeEffectiveness`.
|
||||
|
||||
## 🧪 Test Runner 🧪
|
||||
### Changed
|
||||
* Gravity fix + Sky Drop Test by @ghoulslash in [#5780](https://github.com/rh-hideout/pokeemerald-expansion/pull/5780)
|
||||
* Added missing Belch tests by @AsparagusEduardo in [#5881](https://github.com/rh-hideout/pokeemerald-expansion/pull/5881)
|
||||
* Added missing Move Effect TODO tests - Volume D by @AsparagusEduardo in [#5887](https://github.com/rh-hideout/pokeemerald-expansion/pull/5887)
|
||||
* Comment out Ally Switch Illusion test by @AsparagusEduardo in [#5901](https://github.com/rh-hideout/pokeemerald-expansion/pull/5901)
|
||||
* Fixed leaking tasks not showing up in summary by @AsparagusEduardo in [#5890](https://github.com/rh-hideout/pokeemerald-expansion/pull/5890)
|
||||
* Setting Battle configs during tests by @AsparagusEduardo and @SBird1337, @mrgriffin in [#5803](https://github.com/rh-hideout/pokeemerald-expansion/pull/5803)
|
||||
* Speed up tests in headless mode by @AsparagusEduardo and @SBird1337 for the original fast intro code. in [#5889](https://github.com/rh-hideout/pokeemerald-expansion/pull/5889)
|
||||
- This introduced the config option `B_FAST_INTRO_NO_SLIDE` which removes the sliding into for battles.
|
||||
* Added missing Move Effect TODO tests - Volume E by @AsparagusEduardo in [#5915](https://github.com/rh-hideout/pokeemerald-expansion/pull/5915)
|
||||
|
||||
### Fixed
|
||||
* Fix test `TIMEOUT` messaging in summary by @AsparagusEduardo in [#5772](https://github.com/rh-hideout/pokeemerald-expansion/pull/5772)
|
||||
* Fix octolock + defiant by @ghoulslash in [#5781](https://github.com/rh-hideout/pokeemerald-expansion/pull/5781)
|
||||
* Added missing tests + Fix Coaching/Crafty Shield interaction by @AsparagusEduardo in [#5796](https://github.com/rh-hideout/pokeemerald-expansion/pull/5796)
|
||||
* Fixed TODO tests not showing up when filtering by name by @AsparagusEduardo in [#5894](https://github.com/rh-hideout/pokeemerald-expansion/pull/5894)
|
||||
|
||||
## 📚 Documentation 📚
|
||||
* Fixed changelog links to changelog 1.10 by @AsparagusEduardo in [#5758](https://github.com/rh-hideout/pokeemerald-expansion/pull/5758)
|
||||
* Added scope document and made changes to pull request template by @pkmnsnfrn and @Pawkkie and arguably the entire senate in [#5706](https://github.com/rh-hideout/pokeemerald-expansion/pull/5706)
|
||||
* Added instructions in PR template to make crediting people more clear by @pkmnsnfrn and @AsparagusEduardo made changes to my text in [#5755](https://github.com/rh-hideout/pokeemerald-expansion/pull/5755)
|
||||
* Fix website not showing the "How to add mon" 1.10 tutorial by @AsparagusEduardo in [#5813](https://github.com/rh-hideout/pokeemerald-expansion/pull/5813)
|
||||
* Install instructions by @hedara90 in [#5876](https://github.com/rh-hideout/pokeemerald-expansion/pull/5876)
|
||||
* Change install.md to mention make debug instead of DINFO=1 by @ravepossum in [#5882](https://github.com/rh-hideout/pokeemerald-expansion/pull/5882)
|
||||
* Backport changes from the wiki by @AsparagusEduardo in [#5900](https://github.com/rh-hideout/pokeemerald-expansion/pull/5900)
|
||||
* Improve README.md by @AsparagusEduardo in [#5640](https://github.com/rh-hideout/pokeemerald-expansion/pull/5640)
|
||||
|
||||
## 📦 Branch Synchronisation 📦
|
||||
### pret
|
||||
* 20th of December in [#5845](https://github.com/rh-hideout/pokeemerald-expansion/pull/5845)
|
||||
* Fix recorded battle link player loops by @AsparagusEduardo in [pret#2071](https://github.com/pret/pokeemerald/pull/2071)
|
||||
* Added `POKEMART_LIST_END` to avoid users accidentally removing it by @AsparagusEduardo in [pret#1947](https://github.com/pret/pokeemerald/pull/1947)
|
||||
* Fixed brace style inconsistencies by @AsparagusEduardo in [pret#2072](https://github.com/pret/pokeemerald/pull/2072)
|
||||
* remove `sBirchSpeechPlatformBlackPal` by @DizzyEggg in [pret#2075](https://github.com/pret/pokeemerald/pull/2075)
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.10.0...expansion/1.10.1
|
||||
|
||||
<!--Last PR: 5922-->
|
||||
<!--Used to keep track of the last PR merged in case new ones come in before the changelog is done.-->
|
||||
@ -858,6 +858,24 @@ static const u16 sPecharuntTeachableLearnset[] = {
|
||||
#endif
|
||||
```
|
||||
|
||||
_NOTE: At the top of this file, you will probably see this warning:_
|
||||
```
|
||||
//
|
||||
// DO NOT MODIFY THIS FILE! It is auto-generated from tools/learnset_helpers/teachable.py`
|
||||
//
|
||||
```
|
||||
The expansion includes a tool called the learnset helper, which aims to automate the generation of valid teachable moves. At the time of writing, this tool only supports generating TM and Tutor learnsets. However, in the future it may be expanded to deal with level up learnsets and egg moves.
|
||||
|
||||
Ignore the warning shown above the first time you're adding your teachable moves (as otherwise the compiler will complain about the array not existing), but in the future (if you're using the learnset helper) simply edit what teachable moves your Pokémon can learn in one of the JSON files found in `tools/learnset_helpers/porymoves_files`. It doesn't really matter which one you add your new Pokémon to, as the tool pulls from all of the files in this folder.
|
||||
|
||||
The learnset helper is useful if you plan on changing and/or increasing the available TMs and Tutor moves in your game. As an example, Bulbasaur learns Rage by TM in Red/Blue/Yellow, but in Emerald this TM does not exist. But since `tools/learnset_helpers/porymoves_files/rby.json` defines "MOVE_RAGE" as a TM move for Bulbasaur, that move would automatically be added to the `sBulbasaurTeachableLearnset` array if you were to add a Rage TM at any point.
|
||||
|
||||
The learnset helper can be toggled on/off in `include/config/pokemon.h`:
|
||||
```
|
||||
// Learnset helper toggles
|
||||
#define P_LEARNSET_HELPER_TEACHABLE TRUE // If TRUE, teachable_learnsets.h will be populated by tools/learnset_helpers/teachable.py using the included JSON files based on available TMs and tutors.
|
||||
```
|
||||
|
||||
Once more, we need to register the learnset in `gSpeciesInfo`:
|
||||
|
||||
```diff
|
||||
|
||||
@ -839,6 +839,24 @@ static const u16 sPecharuntTeachableLearnset[] = {
|
||||
#endif
|
||||
```
|
||||
|
||||
_NOTE: At the top of this file, you will probably see this warning:_
|
||||
```
|
||||
//
|
||||
// DO NOT MODIFY THIS FILE! It is auto-generated from tools/learnset_helpers/teachable.py`
|
||||
//
|
||||
```
|
||||
The expansion includes a tool called the learnset helper, which aims to automate the generation of valid teachable moves. At the time of writing, this tool only supports generating TM and Tutor learnsets. However, in the future it may be expanded to deal with level up learnsets and egg moves.
|
||||
|
||||
Ignore the warning shown above the first time you're adding your teachable moves (as otherwise the compiler will complain about the array not existing), but in the future (if you're using the learnset helper) simply edit what teachable moves your Pokémon can learn in one of the JSON files found in `tools/learnset_helpers/porymoves_files`. It doesn't really matter which one you add your new Pokémon to, as the tool pulls from all of the files in this folder.
|
||||
|
||||
The learnset helper is useful if you plan on changing and/or increasing the available TMs and Tutor moves in your game. As an example, Bulbasaur learns Rage by TM in Red/Blue/Yellow, but in Emerald this TM does not exist. But since `tools/learnset_helpers/porymoves_files/rby.json` defines "MOVE_RAGE" as a TM move for Bulbasaur, that move would automatically be added to the `sBulbasaurTeachableLearnset` array if you were to add a Rage TM at any point.
|
||||
|
||||
The learnset helper can be toggled on/off in `include/config/pokemon.h`:
|
||||
```
|
||||
// Learnset helper toggles
|
||||
#define P_LEARNSET_HELPER_TEACHABLE TRUE // If TRUE, teachable_learnsets.h will be populated by tools/learnset_helpers/teachable.py using the included JSON files based on available TMs and tutors.
|
||||
```
|
||||
|
||||
Once more, we need to register the learnset in `gSpeciesInfo`:
|
||||
|
||||
```diff
|
||||
|
||||
@ -32,7 +32,7 @@ This can be translated to an automated test as follows:
|
||||
```
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE);
|
||||
ASSUME(GetMoveEffect(MOVE_STUN_SPORE) == EFFECT_PARALYZE);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Stun Spore inflicts paralysis")
|
||||
@ -78,7 +78,7 @@ This can again be translated as follows:
|
||||
SINGLE_BATTLE_TEST("Stun Spore does not affect Grass-types")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove);
|
||||
ASSUME(IsPowderMove(MOVE_STUN_SPORE));
|
||||
ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS);
|
||||
PLAYER(SPECIES_ODDISH); // 1.
|
||||
OPPONENT(SPECIES_ODDISH); // 2.
|
||||
@ -111,7 +111,7 @@ SINGLE_BATTLE_TEST("Meditate raises Attack", s16 damage)
|
||||
PARAMETRIZE { raiseAttack = FALSE; }
|
||||
PARAMETRIZE { raiseAttack = TRUE; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
@ -146,7 +146,7 @@ The overworld is not available, so it is only possible to test commands which do
|
||||
### `ASSUME`
|
||||
`ASSUME(cond)`
|
||||
Causes the test to be skipped if `cond` is false. Used to document any prerequisites of the test, e.g. to test Burn reducing the Attack of a Pokémon we can observe the damage of a physical attack with and without the burn. To document that this test assumes the attack is physical we can use:
|
||||
`ASSUME(gMovesInfo[MOVE_WHATEVER].category == DAMAGE_CATEGORY_PHYSICAL);`
|
||||
`ASSUME(GetMoveCategory(MOVE_WHATEVER) == DAMAGE_CATEGORY_PHYSICAL);`
|
||||
|
||||
### `ASSUMPTIONS`
|
||||
```
|
||||
@ -159,7 +159,7 @@ Should be placed immediately after any `#includes` and contain any `ASSUME` stat
|
||||
```
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(gMovesInfo[MOVE_POISON_STING].effect == EFFECT_POISON_HIT);
|
||||
ASSUME(GetMoveEffect(MOVE_POISON_STING) == EFFECT_POISON_HIT);
|
||||
}
|
||||
```
|
||||
|
||||
@ -201,7 +201,7 @@ SINGLE_BATTLE_TEST("Blaze boosts Fire-type moves in a pinch", s16 damage)
|
||||
PARAMETRIZE { hp = 99; }
|
||||
PARAMETRIZE { hp = 33; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE);
|
||||
ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE);
|
||||
PLAYER(SPECIES_CHARMANDER) { Ability(ABILITY_BLAZE); MaxHP(99); HP(hp); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
@ -233,7 +233,7 @@ SINGLE_BATTLE_TEST("Paralysis has a 25% chance of skipping the turn")
|
||||
All `BattleRandom` calls involving tag will return the same number, so this cannot be used to have two moves independently hit or miss, for example.
|
||||
|
||||
If the tag is not provided, runs the test 50 times and computes an approximate pass ratio.
|
||||
`PASSES_RANDOMLY(gMovesInfo[move].accuracy, 100);`
|
||||
`PASSES_RANDOMLY(GetMoveAccuracy(move), 100);`
|
||||
Note that this mode of PASSES_RANDOMLY makes the tests run very slowly and should be avoided where possible. If the mechanic you are testing is missing its tag, you should add it.
|
||||
|
||||
### `GIVEN`
|
||||
|
||||
BIN
graphics/dexnav/captured_all.png
Normal file
|
After Width: | Height: | Size: 157 B |
BIN
graphics/dexnav/cursor.png
Normal file
|
After Width: | Height: | Size: 172 B |
19
graphics/dexnav/gui.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
0 0 0
|
||||
255 255 255
|
||||
217 73 73
|
||||
4 4 4
|
||||
1 81 113
|
||||
1 121 193
|
||||
119 177 75
|
||||
93 97 101
|
||||
91 179 211
|
||||
153 32 32
|
||||
111 141 81
|
||||
173 173 173
|
||||
187 217 167
|
||||
75 147 189
|
||||
177 219 235
|
||||
105 22 22
|
||||
BIN
graphics/dexnav/gui_tilemap.bin
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
graphics/dexnav/gui_tiles.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
graphics/dexnav/hidden.png
Normal file
|
After Width: | Height: | Size: 178 B |
BIN
graphics/dexnav/hidden_search.png
Normal file
|
After Width: | Height: | Size: 359 B |
BIN
graphics/dexnav/no_data.png
Normal file
|
After Width: | Height: | Size: 182 B |
BIN
graphics/dexnav/owned_icon.png
Normal file
|
After Width: | Height: | Size: 159 B |
BIN
graphics/dexnav/star.png
Normal file
|
After Width: | Height: | Size: 170 B |
BIN
graphics/dexnav/vision.png
Normal file
|
After Width: | Height: | Size: 242 B |
19
graphics/field_effects/palettes/cave_dust.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
255 1 255
|
||||
159 122 85
|
||||
207 189 157
|
||||
199 181 149
|
||||
114 88 61
|
||||
132 101 70
|
||||
199 173 141
|
||||
225 209 193
|
||||
189 165 133
|
||||
181 149 115
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
BIN
graphics/field_effects/pics/cave_dust.png
Normal file
|
After Width: | Height: | Size: 409 B |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 830 B After Width: | Height: | Size: 757 B |
@ -6,7 +6,7 @@ JASC-PAL
|
||||
120 120 112
|
||||
160 160 144
|
||||
8 8 8
|
||||
120 120 112
|
||||
84 84 78
|
||||
48 48 56
|
||||
232 232 232
|
||||
240 152 168
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 796 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 548 B After Width: | Height: | Size: 485 B |
@ -3,17 +3,17 @@ JASC-PAL
|
||||
16
|
||||
152 208 160
|
||||
8 48 56
|
||||
0 128 160
|
||||
36 103 149
|
||||
16 16 16
|
||||
80 64 40
|
||||
248 208 128
|
||||
176 152 88
|
||||
255 215 132
|
||||
181 158 90
|
||||
136 104 56
|
||||
152 232 248
|
||||
102 225 253
|
||||
96 192 216
|
||||
80 88 88
|
||||
168 168 168
|
||||
216 216 216
|
||||
48 56 40
|
||||
152 128 80
|
||||
136 88 56
|
||||
99 84 80
|
||||
201 185 131
|
||||
167 139 110
|
||||
|
||||
|
Before Width: | Height: | Size: 880 B After Width: | Height: | Size: 794 B |
|
Before Width: | Height: | Size: 481 B |
|
Before Width: | Height: | Size: 472 B After Width: | Height: | Size: 620 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.0 KiB |
19
graphics/text_window/dexnav_pal.pal
Normal file
@ -0,0 +1,19 @@
|
||||
JASC-PAL
|
||||
0100
|
||||
16
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 6
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
0 0 0
|
||||
46 46 46
|
||||
0 0 0
|
||||
255 255 255
|
||||
@ -17,6 +17,7 @@
|
||||
#include "battle_dynamax.h"
|
||||
#include "battle_terastal.h"
|
||||
#include "battle_gimmick.h"
|
||||
#include "move.h"
|
||||
#include "random.h" // for rng_value_t
|
||||
|
||||
// Helper for accessing command arguments and advancing gBattlescriptCurrInstr.
|
||||
@ -70,20 +71,6 @@
|
||||
// Special indicator value for shellBellDmg in SpecialStatus
|
||||
#define IGNORE_SHELL_BELL 0xFFFF
|
||||
|
||||
// For defining EFFECT_HIT etc. with battle TV scores and flags etc.
|
||||
struct __attribute__((packed, aligned(2))) BattleMoveEffect
|
||||
{
|
||||
const u8 *battleScript;
|
||||
u16 battleTvScore:3;
|
||||
u16 encourageEncore:1;
|
||||
u16 twoTurnEffect:1;
|
||||
u16 semiInvulnerableEffect:1;
|
||||
u16 usesProtectCounter:1;
|
||||
u16 padding:9;
|
||||
};
|
||||
|
||||
#define GET_MOVE_BATTLESCRIPT(move) gBattleMoveEffects[gMovesInfo[move].effect].battleScript
|
||||
|
||||
struct ResourceFlags
|
||||
{
|
||||
u32 flags[MAX_BATTLERS_COUNT];
|
||||
@ -864,11 +851,25 @@ STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLER
|
||||
#define F_DYNAMIC_TYPE_IGNORE_PHYSICALITY (1 << 6) // If set, the dynamic type's physicality won't be used for certain move effects.
|
||||
#define F_DYNAMIC_TYPE_SET (1 << 7) // Set for all dynamic types to distinguish a dynamic type of Normal (0) from no dynamic type.
|
||||
|
||||
#define IS_MOVE_PHYSICAL(move) (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL)
|
||||
#define IS_MOVE_SPECIAL(move) (GetBattleMoveCategory(move) == DAMAGE_CATEGORY_SPECIAL)
|
||||
#define IS_MOVE_STATUS(move) (gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS)
|
||||
static inline bool32 IsBattleMovePhysical(u32 move)
|
||||
{
|
||||
return GetBattleMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL;
|
||||
}
|
||||
|
||||
#define IS_MOVE_RECOIL(move)(gMovesInfo[move].recoil > 0 || gMovesInfo[move].effect == EFFECT_RECOIL_IF_MISS)
|
||||
static inline bool32 IsBattleMoveSpecial(u32 move)
|
||||
{
|
||||
return GetBattleMoveCategory(move) == DAMAGE_CATEGORY_SPECIAL;
|
||||
}
|
||||
|
||||
static inline bool32 IsBattleMoveStatus(u32 move)
|
||||
{
|
||||
return GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS;
|
||||
}
|
||||
|
||||
static inline bool32 IsBattleMoveRecoil(u32 move)
|
||||
{
|
||||
return GetMoveRecoil(move) > 0 || GetMoveEffect(move) == EFFECT_RECOIL_IF_MISS;
|
||||
}
|
||||
|
||||
/* Checks if 'battlerId' is any of the types.
|
||||
* Passing multiple types is more efficient than calling this multiple
|
||||
@ -1112,7 +1113,6 @@ extern u8 gChosenMovePos;
|
||||
extern u16 gCurrentMove;
|
||||
extern u16 gChosenMove;
|
||||
extern u16 gCalledMove;
|
||||
extern s32 gHpDealt;
|
||||
extern s32 gBideDmg[MAX_BATTLERS_COUNT];
|
||||
extern u16 gLastUsedItem;
|
||||
extern u16 gLastUsedAbility;
|
||||
@ -1176,7 +1176,6 @@ extern u32 gFieldStatuses;
|
||||
extern struct FieldTimer gFieldTimers;
|
||||
extern u8 gBattlerAbility;
|
||||
extern struct QueuedStatBoost gQueuedStatBoosts[MAX_BATTLERS_COUNT];
|
||||
extern const struct BattleMoveEffect gBattleMoveEffects[];
|
||||
|
||||
extern void (*gPreBattleCallback1)(void);
|
||||
extern void (*gBattleMainFunc)(void);
|
||||
|
||||
@ -116,7 +116,7 @@ bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensiv
|
||||
bool32 HasMoveWithCategory(u32 battler, u32 category);
|
||||
bool32 HasMoveWithType(u32 battler, u32 type);
|
||||
bool32 HasMoveEffect(u32 battlerId, u32 moveEffect);
|
||||
bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument);
|
||||
bool32 IsPowerBasedOnStatus(u32 battlerId, u32 effect, u32 argument);
|
||||
bool32 HasMoveWithAdditionalEffect(u32 battlerId, u32 moveEffect);
|
||||
bool32 HasMoveWithCriticalHitChance(u32 battlerId);
|
||||
bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception);
|
||||
|
||||
@ -6,6 +6,7 @@ void FreeBattleSpritesData(void);
|
||||
u16 ChooseMoveAndTargetInBattlePalace(u32 battler);
|
||||
void SpriteCB_WaitForBattlerBallReleaseAnim(struct Sprite *sprite);
|
||||
void SpriteCB_TrainerSlideIn(struct Sprite *sprite);
|
||||
void SpriteCB_TrainerSpawn(struct Sprite *sprite);
|
||||
void InitAndLaunchChosenStatusAnimation(u32 battler, bool32 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);
|
||||
|
||||
@ -72,7 +72,7 @@ void SwapTurnOrder(u8 id1, u8 id2);
|
||||
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
|
||||
u32 GetBattlerTotalSpeedStat(u32 battler);
|
||||
s8 GetChosenMovePriority(u32 battlerId);
|
||||
s8 GetMovePriority(u32 battlerId, u16 move);
|
||||
s8 GetBattleMovePriority(u32 battlerId, u16 move);
|
||||
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
|
||||
u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2);
|
||||
s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);
|
||||
|
||||
@ -422,7 +422,6 @@ extern const u8 BattleScript_EjectButtonActivates[];
|
||||
extern const u8 BattleScript_EjectPackActivate_Ret[];
|
||||
extern const u8 BattleScript_EjectPackActivate_End2[];
|
||||
extern const u8 BattleScript_EjectPackActivates[];
|
||||
extern const u8 BattleScript_EjectPackMissesTiming[];
|
||||
extern const u8 BattleScript_MentalHerbCureRet[];
|
||||
extern const u8 BattleScript_MentalHerbCureEnd2[];
|
||||
extern const u8 BattleScript_TerrainPreventsEnd2[];
|
||||
@ -809,18 +808,18 @@ extern const u8 BattleScript_EffectGeomancy[];
|
||||
extern const u8 BattleScript_EffectFairyLock[];
|
||||
extern const u8 BattleScript_EffectAllySwitch[];
|
||||
extern const u8 BattleScript_EffectRelicSong[];
|
||||
extern const u8 BattleScript_EffectEerieSpell[];
|
||||
extern const u8 BattleScript_MoveEffectEerieSpell[];
|
||||
extern const u8 BattleScript_EffectJungleHealing[];
|
||||
extern const u8 BattleScript_EffectCoaching[];
|
||||
extern const u8 BattleScript_EffectDecorate[];
|
||||
extern const u8 BattleScript_EffectRecoilHP25[];
|
||||
extern const u8 BattleScript_EffectStuffCheeks[];
|
||||
extern const u8 BattleScript_EffectGlitzyGlow[];
|
||||
extern const u8 BattleScript_EffectBaddyBad[];
|
||||
extern const u8 BattleScript_EffectSappySeed[];
|
||||
extern const u8 BattleScript_EffectFreezyFrost[];
|
||||
extern const u8 BattleScript_MoveEffectLightScreen[];
|
||||
extern const u8 BattleScript_MoveEffectReflect[];
|
||||
extern const u8 BattleScript_MoveEffectLeechSeed[];
|
||||
extern const u8 BattleScript_MoveEffectHaze[];
|
||||
extern const u8 BattleScript_EffectSparklySwirl[];
|
||||
extern const u8 BattleScript_EffectPlasmaFists[];
|
||||
extern const u8 BattleScript_MoveEffectIonDeluge[];
|
||||
extern const u8 BattleScript_EffectHyperspaceFury[];
|
||||
extern const u8 BattleScript_EffectAuraWheel[];
|
||||
extern const u8 BattleScript_EffectPhotonGeyser[];
|
||||
@ -843,7 +842,7 @@ extern const u8 BattleScript_EffectRevivalBlessing[];
|
||||
extern const u8 BattleScript_EffectSnow[];
|
||||
extern const u8 BattleScript_EffectTakeHeart[];
|
||||
extern const u8 BattleScript_EffectCorrosiveGas[];
|
||||
extern const u8 BattleScript_EffectSaltCure[];
|
||||
extern const u8 BattleScript_MoveEffectSaltCure[];
|
||||
extern const u8 BattleScript_EffectChillyReception[];
|
||||
extern const u8 BattleScript_EffectMaxMove[];
|
||||
extern const u8 BattleScript_EffectGlaiveRush[];
|
||||
|
||||
@ -11,6 +11,7 @@ void GetBg0TilesDst(u16 **tilemap, u16 **tileset);
|
||||
extern const struct SpritePalette gSpritePalette_Pokeball;
|
||||
|
||||
enum {
|
||||
MUGSHOT_COLOR_NONE,
|
||||
MUGSHOT_COLOR_PURPLE,
|
||||
MUGSHOT_COLOR_GREEN,
|
||||
MUGSHOT_COLOR_PINK,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#ifndef GUARD_BATTLE_UTIL_H
|
||||
#define GUARD_BATTLE_UTIL_H
|
||||
|
||||
#include "move.h"
|
||||
|
||||
#define MOVE_LIMITATION_ZEROMOVE (1 << 0)
|
||||
#define MOVE_LIMITATION_PP (1 << 1)
|
||||
#define MOVE_LIMITATION_DISABLED (1 << 2)
|
||||
@ -100,33 +102,37 @@ struct TypePower
|
||||
enum
|
||||
{
|
||||
CANCELLER_FLAGS,
|
||||
CANCELLER_STANCE_CHANGE_1,
|
||||
CANCELLER_SKY_DROP,
|
||||
CANCELLER_RECHARGE,
|
||||
CANCELLER_ASLEEP,
|
||||
CANCELLER_FROZEN,
|
||||
CANCELLER_OBEDIENCE,
|
||||
CANCELLER_TRUANT,
|
||||
CANCELLER_RECHARGE,
|
||||
CANCELLER_FLINCH,
|
||||
CANCELLER_IN_LOVE,
|
||||
CANCELLER_DISABLED,
|
||||
CANCELLER_GRAVITY,
|
||||
CANCELLER_HEAL_BLOCKED,
|
||||
CANCELLER_GRAVITY,
|
||||
CANCELLER_THROAT_CHOP,
|
||||
CANCELLER_TAUNTED,
|
||||
CANCELLER_IMPRISONED,
|
||||
CANCELLER_CONFUSED,
|
||||
CANCELLER_PARALYSED,
|
||||
CANCELLER_IN_LOVE,
|
||||
CANCELLER_BIDE,
|
||||
CANCELLER_THAW,
|
||||
CANCELLER_STANCE_CHANGE_2,
|
||||
CANCELLER_WEATHER_PRIMAL,
|
||||
CANCELLER_DYNAMAX_BLOCKED,
|
||||
CANCELLER_POWDER_MOVE,
|
||||
CANCELLER_POWDER_STATUS,
|
||||
CANCELLER_THROAT_CHOP,
|
||||
CANCELLER_PROTEAN,
|
||||
CANCELLER_PSYCHIC_TERRAIN,
|
||||
CANCELLER_EXPLODING_DAMP,
|
||||
CANCELLER_MULTIHIT_MOVES,
|
||||
CANCELLER_Z_MOVES,
|
||||
CANCELLER_MULTI_TARGET_MOVES,
|
||||
CANCELLER_END,
|
||||
CANCELLER_PSYCHIC_TERRAIN,
|
||||
CANCELLER_END2,
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -197,9 +203,8 @@ u8 DoBattlerEndTurnEffects(void);
|
||||
bool32 HandleWishPerishSongOnTurnEnd(void);
|
||||
bool32 HandleFaintedMonActions(void);
|
||||
void TryClearRageAndFuryCutter(void);
|
||||
u8 AtkCanceller_UnableToUseMove(u32 moveType);
|
||||
u32 AtkCanceller_MoveSuccessOrder(void);
|
||||
void SetAtkCancellerForCalledMove(void);
|
||||
u8 AtkCanceller_UnableToUseMove2(void);
|
||||
bool32 HasNoMonsToSwitch(u32 battler, u8 r1, u8 r2);
|
||||
bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility);
|
||||
u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef);
|
||||
@ -223,7 +228,7 @@ u32 ItemBattleEffects(enum ItemEffect, u32 battler, bool32 moveTurn);
|
||||
void ClearVariousBattlerFlags(u32 battler);
|
||||
void HandleAction_RunBattleScript(void);
|
||||
u32 SetRandomTarget(u32 battler);
|
||||
u32 GetMoveTarget(u16 move, u8 setTarget);
|
||||
u32 GetBattleMoveTarget(u16 move, u8 setTarget);
|
||||
u8 GetAttackerObedienceForAction();
|
||||
u32 GetBattlerHoldEffect(u32 battler, bool32 checkNegating);
|
||||
u32 GetBattlerHoldEffectIgnoreAbility(u32 battler, bool32 checkNegating);
|
||||
@ -242,7 +247,7 @@ s32 CalculateMoveDamageVars(struct DamageCalculationData *damageCalcData, u32 fi
|
||||
uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, u32 battlerDef, u32 defAbility, bool32 recordAbilities);
|
||||
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
|
||||
uq4_12_t GetTypeModifier(u32 atkType, u32 defType);
|
||||
uq4_12_t GetTypeEffectiveness(struct Pokemon *mon, u8 moveType);
|
||||
uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType);
|
||||
s32 GetStealthHazardDamage(u8 hazardType, u32 battler);
|
||||
s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp);
|
||||
bool32 CanMegaEvolve(u32 battler);
|
||||
@ -297,7 +302,7 @@ bool32 IsGen6ExpShareEnabled(void);
|
||||
bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect);
|
||||
bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance);
|
||||
bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect);
|
||||
bool32 MoveHasAdditionalEffectSelfArg(u32 move, u32 moveEffect, u32 argument);
|
||||
bool32 IsMoveEffectRemoveSpeciesType(u32 move, u32 moveEffect, u32 argument);
|
||||
bool32 MoveHasChargeTurnAdditionalEffect(u32 move);
|
||||
bool32 CanTargetPartner(u32 battlerAtk, u32 battlerDef);
|
||||
bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef);
|
||||
@ -325,12 +330,13 @@ u32 GetBattlerType(u32 battler, u32 typeIndex, bool32 ignoreTera);
|
||||
bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon);
|
||||
bool8 IsMonBannedFromSkyBattles(u16 species);
|
||||
void RemoveBattlerType(u32 battler, u8 type);
|
||||
u32 GetMoveType(u32 move);
|
||||
u32 GetBattleMoveType(u32 move);
|
||||
void TryActivateSleepClause(u32 battler, u32 indexInParty);
|
||||
void TryDeactivateSleepClause(u32 battlerSide, u32 indexInParty);
|
||||
bool32 IsSleepClauseActiveForSide(u32 battlerSide);
|
||||
bool32 IsSleepClauseEnabled();
|
||||
void ClearDamageCalcResults(void);
|
||||
u32 DoesDestinyBondFail(u32 battler);
|
||||
bool32 IsMoveEffectBlockedByTarget(u32 ability);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
||||
@ -157,6 +157,7 @@
|
||||
// In Gen3, Effect Spore has a 10% chance to sleep, poison or paralyze, with an equal chance.
|
||||
// In Gen4, it's 30%. In Gen5+ it has 11% to sleep, 9% chance to poison and 10% chance to paralyze.
|
||||
#define B_PICKUP_WILD GEN_LATEST // In Gen9+, Pickup allows its user to pickup its own used item at the end of the turn in wild battles.
|
||||
#define B_MAGIC_GUARD GEN_LATEST // In Gen4+, Magic Guard ignores immobilization caused by paralysis
|
||||
|
||||
// Item settings
|
||||
#define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore HP activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn.
|
||||
@ -229,7 +230,8 @@
|
||||
|
||||
// Interface settings
|
||||
#define B_ABILITY_POP_UP TRUE // In Gen5+, the Pokémon abilities are displayed in a pop-up, when they activate in battle.
|
||||
#define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end.
|
||||
#define B_FAST_INTRO_PKMN_TEXT TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end.
|
||||
#define B_FAST_INTRO_NO_SLIDE FALSE // If set to TRUE, the slide animation that happens at the beginning of the battle is skipped.
|
||||
#define B_FAST_HP_DRAIN TRUE // If set to TRUE, HP bars will move faster.
|
||||
#define B_FAST_EXP_GROW TRUE // If set to TRUE, EXP bars will move faster.
|
||||
#define B_SHOW_TARGETS TRUE // If set to TRUE, all available targets, for moves hitting 2 or 3 Pokémon, will be shown before selecting a move.
|
||||
|
||||
72
include/config/dexnav.h
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef GUARD_CONFIG_DEXNAV_H
|
||||
#define GUARD_CONFIG_DEXNAV_H
|
||||
|
||||
#define DEXNAV_ENABLED FALSE // Whether or not DexNav is enabled. If TRUE, flags/vars below must all be non-zero
|
||||
#define USE_DEXNAV_SEARCH_LEVELS FALSE /* WARNING: POSSIBLY EXCEEDS SAVEBLOCK SPACE! REQUIRES 1 BYTE PER SPECIES */
|
||||
|
||||
// Flag/var defines
|
||||
#define FLAG_SYS_DEXNAV_SEARCH 0 // Searching for mon
|
||||
#define FLAG_SYS_DEXNAV_GET 0 // DexNav shows in start menu
|
||||
#define FLAG_SYS_DETECTOR_MODE 0 // Allow player to find hidden mons
|
||||
#define VAR_DEXNAV_SPECIES 0 // Registered DexNav species
|
||||
#define VAR_DEXNAV_STEP_COUNTER 0 // Steps for finding hidden pokemon
|
||||
|
||||
// Search parameters
|
||||
#define DEXNAV_TIMEOUT 15 // 15 seconds is the time out. Max of 1092 seconds allowed
|
||||
#define SNEAKING_PROXIMITY 4 // Tile amount
|
||||
#define CREEPING_PROXIMITY 2
|
||||
#define MAX_PROXIMITY 20
|
||||
|
||||
#define DEXNAV_CHAIN_MAX 100 // maximum chain value
|
||||
|
||||
// hidden pokemon options - an approximation of values to due to lack of available data
|
||||
#define HIDDEN_MON_STEP_COUNT 100 // Look for hidden pokemon every x steps
|
||||
#define HIDDEN_MON_SEARCH_RATE 25 // x% chance of finding hidden pokemon every x steps
|
||||
#define HIDDEN_MON_PROBABILTY 15 // x% chance of finding hidden mon compared to regular encounter data
|
||||
|
||||
//// SEARCH PROBABILITIES
|
||||
// See https://bulbapedia.bulbagarden.net/wiki/DexNav#Benefits
|
||||
// Chance of encountering egg move at search levels
|
||||
#define SEARCHLEVEL0_MOVECHANCE 0
|
||||
#define SEARCHLEVEL5_MOVECHANCE 21
|
||||
#define SEARCHLEVEL10_MOVECHANCE 46
|
||||
#define SEARCHLEVEL25_MOVECHANCE 58
|
||||
#define SEARCHLEVEL50_MOVECHANCE 63
|
||||
#define SEARCHLEVEL100_MOVECHANCE 83
|
||||
// Chance of encountering Hidden Abilities at search levels
|
||||
#define SEARCHLEVEL0_ABILITYCHANCE 0
|
||||
#define SEARCHLEVEL5_ABILITYCHANCE 0
|
||||
#define SEARCHLEVEL10_ABILITYCHANCE 5
|
||||
#define SEARCHLEVEL25_ABILITYCHANCE 15
|
||||
#define SEARCHLEVEL50_ABILITYCHANCE 20
|
||||
#define SEARCHLEVEL100_ABILITYCHANCE 23
|
||||
// Chance of encountering held item
|
||||
#define SEARCHLEVEL0_ITEM 0
|
||||
#define SEARCHLEVEL5_ITEM 0
|
||||
#define SEARCHLEVEL10_ITEM 1
|
||||
#define SEARCHLEVEL25_ITEM 7
|
||||
#define SEARCHLEVEL50_ITEM 6
|
||||
#define SEARCHLEVEL100_ITEM 12
|
||||
// Chance of encountering one star potential
|
||||
#define SEARCHLEVEL0_ONESTAR 0
|
||||
#define SEARCHLEVEL5_ONESTAR 14
|
||||
#define SEARCHLEVEL10_ONESTAR 17
|
||||
#define SEARCHLEVEL25_ONESTAR 17
|
||||
#define SEARCHLEVEL50_ONESTAR 15
|
||||
#define SEARCHLEVEL100_ONESTAR 8
|
||||
// Chance of encountering two star potential
|
||||
#define SEARCHLEVEL0_TWOSTAR 0
|
||||
#define SEARCHLEVEL5_TWOSTAR 1
|
||||
#define SEARCHLEVEL10_TWOSTAR 9
|
||||
#define SEARCHLEVEL25_TWOSTAR 16
|
||||
#define SEARCHLEVEL50_TWOSTAR 17
|
||||
#define SEARCHLEVEL100_TWOSTAR 24
|
||||
// Chance of encountering three star potential
|
||||
#define SEARCHLEVEL0_THREESTAR 0
|
||||
#define SEARCHLEVEL5_THREESTAR 0
|
||||
#define SEARCHLEVEL10_THREESTAR 1
|
||||
#define SEARCHLEVEL25_THREESTAR 7
|
||||
#define SEARCHLEVEL50_THREESTAR 6
|
||||
#define SEARCHLEVEL100_THREESTAR 12
|
||||
|
||||
#endif // GUARD_CONFIG_DEXNAV_H
|
||||
@ -266,7 +266,6 @@
|
||||
#define STATUS_FIELD_PSYCHIC_TERRAIN (1 << 9)
|
||||
#define STATUS_FIELD_ION_DELUGE (1 << 10)
|
||||
#define STATUS_FIELD_FAIRY_LOCK (1 << 11)
|
||||
#define STATUS_FIELD_TERRAIN_PERMANENT (1 << 12) // Overworld thunderstorm generates electric terrain
|
||||
|
||||
#define STATUS_FIELD_TERRAIN_ANY (STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN)
|
||||
|
||||
@ -331,7 +330,11 @@
|
||||
#define MOVE_EFFECT_TOXIC 6
|
||||
#define MOVE_EFFECT_FROSTBITE 7
|
||||
#define PRIMARY_STATUS_MOVE_EFFECT MOVE_EFFECT_FROSTBITE // All above move effects apply primary status
|
||||
#define MOVE_EFFECT_FREEZE_OR_FROSTBITE (B_USE_FROSTBITE == TRUE ? MOVE_EFFECT_FROSTBITE : MOVE_EFFECT_FREEZE)
|
||||
#if B_USE_FROSTBITE == TRUE
|
||||
#define MOVE_EFFECT_FREEZE_OR_FROSTBITE MOVE_EFFECT_FROSTBITE
|
||||
#else
|
||||
#define MOVE_EFFECT_FREEZE_OR_FROSTBITE MOVE_EFFECT_FREEZE
|
||||
#endif
|
||||
#define MOVE_EFFECT_CONFUSION 8
|
||||
#define MOVE_EFFECT_FLINCH 9
|
||||
#define MOVE_EFFECT_TRI_ATTACK 10
|
||||
@ -405,8 +408,16 @@
|
||||
#define MOVE_EFFECT_PSYCHIC_NOISE 78
|
||||
#define MOVE_EFFECT_TERA_BLAST 79
|
||||
#define MOVE_EFFECT_ORDER_UP 80
|
||||
#define MOVE_EFFECT_ION_DELUGE 81
|
||||
#define MOVE_EFFECT_AROMATHERAPY 82 // No functionality yet
|
||||
#define MOVE_EFFECT_HAZE 83
|
||||
#define MOVE_EFFECT_LEECH_SEED 84
|
||||
#define MOVE_EFFECT_REFLECT 85
|
||||
#define MOVE_EFFECT_LIGHT_SCREEN 86
|
||||
#define MOVE_EFFECT_SALT_CURE 87
|
||||
#define MOVE_EFFECT_EERIE_SPELL 88
|
||||
|
||||
#define NUM_MOVE_EFFECTS 81
|
||||
#define NUM_MOVE_EFFECTS 89
|
||||
|
||||
#define MOVE_EFFECT_AFFECTS_USER 0x2000
|
||||
#define MOVE_EFFECT_CERTAIN 0x4000
|
||||
@ -509,7 +520,7 @@
|
||||
#define MOVE_TARGET_ALLY (1 << 7)
|
||||
#define MOVE_TARGET_ALL_BATTLERS ((1 << 8) | MOVE_TARGET_USER) // No functionality for status moves
|
||||
|
||||
// For the second argument of GetMoveTarget, when no target override is needed
|
||||
// For the second argument of GetBattleMoveTarget, when no target override is needed
|
||||
#define NO_TARGET_OVERRIDE 0
|
||||
|
||||
// Constants for Parental Bond
|
||||
@ -527,15 +538,24 @@
|
||||
|
||||
// Constants for B_VAR_STARTING_STATUS
|
||||
// Timer value controlled by B_VAR_STARTING_STATUS_TIMER
|
||||
#define STARTING_STATUS_NONE 0
|
||||
#define STARTING_STATUS_ELECTRIC_TERRAIN 1
|
||||
#define STARTING_STATUS_MISTY_TERRAIN 2
|
||||
#define STARTING_STATUS_GRASSY_TERRAIN 3
|
||||
#define STARTING_STATUS_PSYCHIC_TERRAIN 4
|
||||
#define STARTING_STATUS_TRICK_ROOM 5
|
||||
#define STARTING_STATUS_MAGIC_ROOM 6
|
||||
#define STARTING_STATUS_WONDER_ROOM 7
|
||||
#define STARTING_STATUS_TAILWIND_PLAYER 8
|
||||
#define STARTING_STATUS_TAILWIND_OPPONENT 9
|
||||
enum StartingStatus
|
||||
{
|
||||
STARTING_STATUS_NONE,
|
||||
STARTING_STATUS_ELECTRIC_TERRAIN,
|
||||
STARTING_STATUS_MISTY_TERRAIN,
|
||||
STARTING_STATUS_GRASSY_TERRAIN,
|
||||
STARTING_STATUS_PSYCHIC_TERRAIN,
|
||||
STARTING_STATUS_TRICK_ROOM,
|
||||
STARTING_STATUS_MAGIC_ROOM,
|
||||
STARTING_STATUS_WONDER_ROOM,
|
||||
STARTING_STATUS_TAILWIND_PLAYER,
|
||||
STARTING_STATUS_TAILWIND_OPPONENT,
|
||||
STARTING_STATUS_RAINBOW_PLAYER,
|
||||
STARTING_STATUS_RAINBOW_OPPONENT,
|
||||
STARTING_STATUS_SEA_OF_FIRE_PLAYER,
|
||||
STARTING_STATUS_SEA_OF_FIRE_OPPONENT,
|
||||
STARTING_STATUS_SWAMP_PLAYER,
|
||||
STARTING_STATUS_SWAMP_OPPONENT,
|
||||
};
|
||||
|
||||
#endif // GUARD_CONSTANTS_BATTLE_H
|
||||
|
||||
@ -285,7 +285,6 @@ enum {
|
||||
EFFECT_ALLY_SWITCH,
|
||||
EFFECT_RELIC_SONG,
|
||||
EFFECT_BODY_PRESS,
|
||||
EFFECT_EERIE_SPELL,
|
||||
EFFECT_JUNGLE_HEALING,
|
||||
EFFECT_COACHING,
|
||||
EFFECT_LASH_OUT,
|
||||
@ -296,12 +295,7 @@ enum {
|
||||
EFFECT_RECOIL_HP_25,
|
||||
EFFECT_STUFF_CHEEKS,
|
||||
EFFECT_GRAV_APPLE,
|
||||
EFFECT_GLITZY_GLOW,
|
||||
EFFECT_BADDY_BAD,
|
||||
EFFECT_SAPPY_SEED,
|
||||
EFFECT_FREEZY_FROST,
|
||||
EFFECT_SPARKLY_SWIRL,
|
||||
EFFECT_PLASMA_FISTS,
|
||||
EFFECT_HYPERSPACE_FURY,
|
||||
EFFECT_AURA_WHEEL,
|
||||
EFFECT_PHOTON_GEYSER,
|
||||
@ -334,7 +328,6 @@ enum {
|
||||
EFFECT_COLLISION_COURSE,
|
||||
EFFECT_CORROSIVE_GAS,
|
||||
EFFECT_POPULATION_BOMB,
|
||||
EFFECT_SALT_CURE,
|
||||
EFFECT_CHILLY_RECEPTION,
|
||||
EFFECT_MAX_MOVE,
|
||||
EFFECT_GLAIVE_RUSH,
|
||||
|
||||
@ -187,7 +187,6 @@ enum CmdVarious
|
||||
VARIOUS_TERRAIN_SEED,
|
||||
VARIOUS_MAKE_INVISIBLE,
|
||||
VARIOUS_ROOM_SERVICE,
|
||||
VARIOUS_EERIE_SPELL_PP_REDUCE,
|
||||
VARIOUS_JUMP_IF_TEAM_HEALTHY,
|
||||
VARIOUS_TRY_HEAL_QUARTER_HP,
|
||||
VARIOUS_JUMP_IF_PRANKSTER_BLOCKED,
|
||||
|
||||
@ -1010,9 +1010,11 @@
|
||||
#define B_MSG_SET_TRICK_ROOM 4
|
||||
#define B_MSG_SET_MAGIC_ROOM 5
|
||||
#define B_MSG_SET_WONDER_ROOM 6
|
||||
#define B_MSG_SET_TAILWIND_PLAYER 7
|
||||
#define B_MSG_SET_TAILWIND_OPPONENT 8
|
||||
#define B_MSG_STARTING_STATUS_COUNT 9
|
||||
#define B_MSG_SET_TAILWIND 7
|
||||
#define B_MSG_SET_RAINBOW 8
|
||||
#define B_MSG_SET_SEA_OF_FIRE 9
|
||||
#define B_MSG_SET_SWAMP 10
|
||||
#define B_MSG_STARTING_STATUS_COUNT 11
|
||||
|
||||
|
||||
// gWrappedStringIds
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#ifndef GUARD_CONSTANTS_EXPANSION_H
|
||||
#define GUARD_CONSTANTS_EXPANSION_H
|
||||
|
||||
// Last version: 1.10.0
|
||||
// Last version: 1.10.1
|
||||
#define EXPANSION_VERSION_MAJOR 1
|
||||
#define EXPANSION_VERSION_MINOR 11
|
||||
#define EXPANSION_VERSION_PATCH 0
|
||||
|
||||
@ -20,9 +20,9 @@
|
||||
#define FLDEFF_JUMP_SMALL_SPLASH 16
|
||||
#define FLDEFF_LONG_GRASS 17
|
||||
#define FLDEFF_JUMP_LONG_GRASS 18
|
||||
#define FLDEFF_UNUSED_GRASS 19
|
||||
#define FLDEFF_UNUSED_GRASS_2 20
|
||||
#define FLDEFF_UNUSED_SAND 21
|
||||
#define FLDEFF_SHAKING_GRASS 19
|
||||
#define FLDEFF_SHAKING_LONG_GRASS 20
|
||||
#define FLDEFF_SAND_HOLE 21
|
||||
#define FLDEFF_WATER_SURFACING 22
|
||||
#define FLDEFF_BERRY_TREE_GROWTH_SPARKLE 23
|
||||
#define FLDEFF_DEEP_SAND_FOOTPRINTS 24
|
||||
@ -75,6 +75,7 @@
|
||||
#define FLDEFF_TRACKS_SLITHER 70
|
||||
#define FLDEFF_TRACKS_SPOT 71
|
||||
#define FLDEFF_TRACKS_BUG 72
|
||||
#define FLDEFF_CAVE_DUST 73
|
||||
|
||||
#define FLDEFFOBJ_SHADOW_S 0
|
||||
#define FLDEFFOBJ_SHADOW_M 1
|
||||
@ -116,6 +117,7 @@
|
||||
#define FLDEFFOBJ_TRACKS_SLITHER 37
|
||||
#define FLDEFFOBJ_TRACKS_SPOT 38
|
||||
#define FLDEFFOBJ_TRACKS_BUG 39
|
||||
#define FLDEFFOBJ_CAVE_DUST 40
|
||||
|
||||
#define FLDEFF_PAL_TAG_CUT_GRASS 0x1000
|
||||
#define FLDEFF_PAL_TAG_SECRET_POWER_TREE 0x1003
|
||||
@ -129,6 +131,7 @@
|
||||
#define FLDEFF_PAL_TAG_SMALL_SPARKLE 0x100F
|
||||
#define FLDEFF_PAL_TAG_HOF_MONITOR 0x1010
|
||||
#define FLDEFF_PAL_TAG_UNKNOWN 0x1011
|
||||
#define FLDEFF_PAL_TAG_CAVE_DUST 0x1012
|
||||
#define FLDEFF_PAL_TAG_FIELD_MOVE_MON 0x8400
|
||||
|
||||
// tile tags, for field effects that may have many copies on screen at once
|
||||
|
||||
@ -53,8 +53,9 @@
|
||||
#define GAME_STAT_ENTERED_HOT_SPRINGS 49
|
||||
#define GAME_STAT_NUM_UNION_ROOM_BATTLES 50
|
||||
#define GAME_STAT_PLAYED_BERRY_CRUSH 51
|
||||
#define GAME_STAT_DEXNAV_SCANNED 52
|
||||
|
||||
#define NUM_USED_GAME_STATS 52
|
||||
#define NUM_USED_GAME_STATS 53
|
||||
#define NUM_GAME_STATS 64
|
||||
|
||||
#endif // GUARD_CONSTANTS_GAME_STAT_H
|
||||
|
||||
10
include/constants/generational_changes.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef GUARD_CONSTANTS_GENERATIONAL_CHANGES_H
|
||||
#define GUARD_CONSTANTS_GENERATIONAL_CHANGES_H
|
||||
|
||||
enum GenConfigTag
|
||||
{
|
||||
GEN_CONFIG_GALE_WINGS,
|
||||
GEN_CONFIG_COUNT
|
||||
};
|
||||
|
||||
#endif // GUARD_CONSTANTS_GENERATIONAL_CHANGES_H
|
||||
@ -8,6 +8,7 @@
|
||||
#include "config/caps.h"
|
||||
#include "config/pokemon.h"
|
||||
#include "config/overworld.h"
|
||||
#include "config/dexnav.h"
|
||||
|
||||
// Invalid Versions show as "----------" in Gen 4 and Gen 5's summary screen.
|
||||
// In Gens 6 and 7, invalid versions instead show "a distant land" in the summary screen.
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#define WATER_WILD_COUNT 5
|
||||
#define ROCK_WILD_COUNT 5
|
||||
#define FISH_WILD_COUNT 10
|
||||
#define HIDDEN_WILD_COUNT 3
|
||||
|
||||
#define NUM_ALTERING_CAVE_TABLES 9
|
||||
|
||||
|
||||
@ -88,7 +88,7 @@ struct Trainer
|
||||
/*0x12*/ u8 trainerPic;
|
||||
/*0x13*/ u8 trainerName[TRAINER_NAME_LENGTH + 1];
|
||||
/*0x1E*/ bool8 doubleBattle:1;
|
||||
bool8 mugshotEnabled:1;
|
||||
bool8 padding:1;
|
||||
u8 startingStatus:6; // this trainer starts a battle with a given status. see include/constants/battle.h for values
|
||||
/*0x1F*/ u8 mugshotColor;
|
||||
/*0x20*/ u8 partySize;
|
||||
@ -235,7 +235,7 @@ static inline const u8 GetTrainerPartySizeFromId(u16 trainerId)
|
||||
|
||||
static inline const bool32 DoesTrainerHaveMugshot(u16 trainerId)
|
||||
{
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].mugshotEnabled;
|
||||
return gTrainers[SanitizeTrainerId(trainerId)].mugshotColor;
|
||||
}
|
||||
|
||||
static inline const u8 GetTrainerMugshotColorFromId(u16 trainerId)
|
||||
|
||||
@ -34,5 +34,6 @@ void ShowDaycareLevelMenu(void);
|
||||
void ChooseSendDaycareMon(void);
|
||||
u8 GetEggMovesBySpecies(u16 species, u16 *eggMoves);
|
||||
bool8 SpeciesCanLearnEggMove(u16 species, u16 move);
|
||||
u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves);
|
||||
|
||||
#endif // GUARD_DAYCARE_H
|
||||
|
||||
77
include/dexnav.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef GUARD_DEXNAV_H
|
||||
#define GUARD_DEXNAV_H
|
||||
|
||||
#include "config/dexnav.h"
|
||||
|
||||
// GUI Info
|
||||
#define ROW_WATER 0
|
||||
#define ROW_LAND_TOP 1
|
||||
#define ROW_LAND_BOT 2
|
||||
#define ROW_HIDDEN 3
|
||||
#define ROWS_COUNT 4
|
||||
|
||||
#define ROW_WATER_ICON_X 30
|
||||
#define ROW_WATER_ICON_Y 35
|
||||
|
||||
#define ROW_LAND_ICON_X 20
|
||||
#define ROW_LAND_TOP_ICON_Y 72
|
||||
#define ROW_LAND_BOT_ICON_Y (ROW_LAND_TOP_ICON_Y + 28)
|
||||
|
||||
#define ROW_HIDDEN_ICON_X 52
|
||||
#define ROW_HIDDEN_ICON_Y 138
|
||||
|
||||
#define ENCOUNTER_TYPE_LAND 0
|
||||
#define ENCOUNTER_TYPE_WATER 1
|
||||
#define ENCOUNTER_TYPE_HIDDEN 2 // Get from species
|
||||
|
||||
#define COL_WATER_COUNT 5
|
||||
#define COL_LAND_COUNT 6
|
||||
#define COL_HIDDEN_COUNT 3
|
||||
|
||||
#define COL_WATER_MAX (COL_WATER_COUNT - 1)
|
||||
#define COL_LAND_MAX (COL_LAND_COUNT - 1)
|
||||
#define COL_HIDDEN_MAX (COL_HIDDEN_COUNT - 1)
|
||||
|
||||
// SEARCH INFO
|
||||
#define SCANSTART_X 0
|
||||
#define SCANSTART_Y 0
|
||||
#define SCANSIZE_X 12
|
||||
#define SCANSIZE_Y 12
|
||||
|
||||
#define SPECIES_INFO_Y 5
|
||||
#define TYPE_ICONS_Y (SPECIES_INFO_Y + 24)
|
||||
#define SEARCH_LEVEL_Y (TYPE_ICONS_Y + 24)
|
||||
#define HA_INFO_Y (SEARCH_LEVEL_Y + 24)
|
||||
#define CHAIN_BONUS_Y (HA_INFO_Y + 24)
|
||||
|
||||
#define MON_LEVEL_NONEXISTENT 255 // If mon not in area GetEncounterLevel returns this to exit the search
|
||||
|
||||
// GUI tags
|
||||
#define ICON_PAL_TAG 56000
|
||||
#define ICON_GFX_TAG 55130
|
||||
#define SELECTION_CURSOR_TAG 0x4005
|
||||
#define CAPTURED_ALL_TAG 0x4002
|
||||
|
||||
// Search tags
|
||||
#define OWNED_ICON_TAG 0x4003
|
||||
#define HIDDEN_SEARCH_TAG SELECTION_CURSOR_TAG
|
||||
#define HIDDEN_MON_ICON_TAG 0x4006
|
||||
#define LIT_STAR_TILE_TAG 0x4010
|
||||
#define HELD_ITEM_TAG 0xd750
|
||||
|
||||
// DexNav search variable
|
||||
#define DEXNAV_MASK_SPECIES 0x3FFF // First 14 bits
|
||||
#define DEXNAV_MASK_ENVIRONMENT 0xC000 // Last two bit
|
||||
|
||||
void EndDexNavSearch(u8 taskId);
|
||||
void Task_OpenDexNavFromStartMenu(u8 taskId);
|
||||
bool8 TryStartDexNavSearch(void);
|
||||
void TryIncrementSpeciesSearchLevel(u16 dexNum);
|
||||
void ResetDexNavSearch(void);
|
||||
bool8 TryFindHiddenPokemon(void);
|
||||
u32 CalculateDexNavShinyRolls(void);
|
||||
void IncrementDexNavChain(void);
|
||||
|
||||
extern bool8 gDexNavBattle;
|
||||
|
||||
#endif // GUARD_DEXNAV_H
|
||||
@ -320,6 +320,7 @@ u8 GetJumpMovementAction(u32);
|
||||
u8 GetJump2MovementAction(u32);
|
||||
u8 CopySprite(struct Sprite *sprite, s16 x, s16 y, u8 subpriority);
|
||||
u8 CreateCopySpriteAt(struct Sprite *sprite, s16 x, s16 y, u8 subpriority);
|
||||
bool8 IsElevationMismatchAt(u8, s16, s16);
|
||||
|
||||
u8 MovementType_WanderAround_Step0(struct ObjectEvent *, struct Sprite *);
|
||||
u8 MovementType_WanderAround_Step1(struct ObjectEvent *, struct Sprite *);
|
||||
|
||||
@ -653,5 +653,13 @@ extern const u8 Common_Movement_FollowerSafeEnd[];
|
||||
extern const u8 EventScript_CancelMessageBox[];
|
||||
extern const u8 Common_EventScript_ShowPokemonCenterSign[];
|
||||
extern const u8 Common_EventScript_ShowPokemartSign[];
|
||||
// DexNav
|
||||
extern const u8 EventScript_StartDexNavBattle[];
|
||||
extern const u8 EventScript_NotFoundNearby[];
|
||||
extern const u8 EventScript_PokemonGotAway[];
|
||||
extern const u8 EventScript_LostSignal[];
|
||||
extern const u8 EventScript_TooDark[];
|
||||
extern const u8 EventScript_MovedTooFast[];
|
||||
|
||||
|
||||
#endif // GUARD_EVENT_SCRIPTS_H
|
||||
|
||||
@ -11,7 +11,7 @@ struct FieldInput
|
||||
bool8 heldDirection2:1;
|
||||
bool8 tookStep:1;
|
||||
bool8 pressedBButton:1;
|
||||
bool8 input_field_1_0:1;
|
||||
bool8 pressedRButton:1;
|
||||
bool8 input_field_1_1:1;
|
||||
bool8 input_field_1_2:1;
|
||||
bool8 input_field_1_3:1;
|
||||
|
||||
@ -48,5 +48,7 @@ void MultiplyPaletteRGBComponents(u16 i, u8 r, u8 g, u8 b);
|
||||
void FreeResourcesAndDestroySprite(struct Sprite *sprite, u8 spriteId);
|
||||
u8 CreateMonSprite_PicBox(u16 species, s16 x, s16 y, u8 subpriority);
|
||||
void StartEscapeRopeFieldEffect(void);
|
||||
void FieldEffectFreeGraphicsResources(struct Sprite *sprite);
|
||||
void FieldEff_CaveDust(void);
|
||||
|
||||
#endif // GUARD_FIELD_EFFECTS_H
|
||||
|
||||
41
include/generational_changes.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef GUARD_GENERATIONAL_CHANGES_H
|
||||
#define GUARD_GENERATIONAL_CHANGES_H
|
||||
|
||||
#include "constants/generational_changes.h"
|
||||
#include "config/battle.h"
|
||||
|
||||
static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
|
||||
{
|
||||
[GEN_CONFIG_GALE_WINGS] = B_GALE_WINGS,
|
||||
};
|
||||
|
||||
#if TESTING
|
||||
extern u8 *gGenerationalChangesTestOverride;
|
||||
#endif
|
||||
|
||||
static inline u32 GetGenConfig(enum GenConfigTag configTag)
|
||||
{
|
||||
if (configTag >= GEN_CONFIG_COUNT) return GEN_LATEST;
|
||||
#if TESTING
|
||||
if (gGenerationalChangesTestOverride == NULL) return sGenerationalChanges[configTag];
|
||||
return gGenerationalChangesTestOverride[configTag];
|
||||
#else
|
||||
return sGenerationalChanges[configTag];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void SetGenConfig(enum GenConfigTag configTag, u32 value)
|
||||
{
|
||||
#if TESTING
|
||||
if (configTag >= GEN_CONFIG_COUNT) return;
|
||||
if (gGenerationalChangesTestOverride == NULL) return;
|
||||
gGenerationalChangesTestOverride[configTag] = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TESTING
|
||||
void TestInitConfigData(void);
|
||||
void TestFreeConfigData(void);
|
||||
#endif
|
||||
|
||||
#endif // GUARD_GENERATIONAL_CHANGES_H
|
||||
@ -326,7 +326,8 @@ struct PlayerAvatar
|
||||
{
|
||||
/*0x00*/ u8 flags;
|
||||
/*0x01*/ u8 transitionFlags; // used to be named bike, but its definitely not that. seems to be some transition flags
|
||||
/*0x02*/ u8 runningState; // this is a static running state. 00 is not moving, 01 is turn direction, 02 is moving.
|
||||
/*0x02*/ u8 runningState:7; // this is a static running state. 00 is not moving, 01 is turn direction, 02 is moving.
|
||||
u8 creeping:1;
|
||||
/*0x03*/ u8 tileTransitionState; // this is a transition running state: 00 is not moving, 01 is transition between tiles, 02 means you are on the frame in which you have centered on a tile but are about to keep moving, even if changing directions. 2 is also used for a ledge hop, since you are transitioning.
|
||||
/*0x04*/ u8 spriteId;
|
||||
/*0x05*/ u8 objectEventId;
|
||||
|
||||
@ -211,7 +211,11 @@ struct SaveBlock3
|
||||
#if OW_SHOW_ITEM_DESCRIPTIONS == OW_ITEM_DESCRIPTIONS_FIRST_TIME
|
||||
u8 itemFlags[ITEM_FLAGS_COUNT];
|
||||
#endif
|
||||
};
|
||||
#if USE_DEXNAV_SEARCH_LEVELS == TRUE
|
||||
u8 dexNavSearchLevels[NUM_SPECIES];
|
||||
#endif
|
||||
u8 dexNavChain;
|
||||
}; /* max size 1624 bytes */
|
||||
|
||||
extern struct SaveBlock3 *gSaveBlock3Ptr;
|
||||
|
||||
|
||||
@ -53,7 +53,6 @@ extern u16 gKeyRepeatContinueDelay;
|
||||
extern bool8 gSoftResetDisabled;
|
||||
extern IntrFunc gIntrTable[];
|
||||
extern u8 gLinkVSyncDisabled;
|
||||
extern u32 IntrMain_Buffer[];
|
||||
extern s8 gPcmDmaCounter;
|
||||
|
||||
void AgbMain(void);
|
||||
|
||||
544
include/move.h
Normal file
@ -0,0 +1,544 @@
|
||||
#ifndef GUARD_MOVES_H
|
||||
#define GUARD_MOVES_H
|
||||
|
||||
#include "contest_effect.h"
|
||||
#include "constants/battle_move_effects.h"
|
||||
#include "constants/moves.h"
|
||||
|
||||
// For defining EFFECT_HIT etc. with battle TV scores and flags etc.
|
||||
struct __attribute__((packed, aligned(2))) BattleMoveEffect
|
||||
{
|
||||
const u8 *battleScript;
|
||||
u16 battleTvScore:3;
|
||||
u16 encourageEncore:1;
|
||||
u16 twoTurnEffect:1;
|
||||
u16 semiInvulnerableEffect:1;
|
||||
u16 usesProtectCounter:1;
|
||||
u16 padding:9;
|
||||
};
|
||||
|
||||
#define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__}
|
||||
#define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ ))
|
||||
|
||||
enum SheerForceBoost
|
||||
{
|
||||
SHEER_FORCE_AUTO_BOOST, // This is the default state when a move has a move effect with a chance
|
||||
SHEER_FORCE_BOOST, // If a move effect doesn't have an effect with a chance this can force a boost
|
||||
SHEER_FORCE_NO_BOOST, // Prevents a Sheer Force boost
|
||||
};
|
||||
|
||||
struct AdditionalEffect
|
||||
{
|
||||
u16 moveEffect;
|
||||
u8 self:1;
|
||||
u8 onlyIfTargetRaisedStats:1;
|
||||
u8 onChargeTurnOnly:1;
|
||||
u8 sheerForceBoost:2; // Handles edge cases for Sheer Force
|
||||
u8 padding:3;
|
||||
u8 chance; // 0% = effect certain, primary effect
|
||||
};
|
||||
|
||||
struct MoveInfo
|
||||
{
|
||||
const u8 *name;
|
||||
const u8 *description;
|
||||
u16 effect;
|
||||
u16 type:5; // Up to 32
|
||||
u16 category:2;
|
||||
u16 power:9; // up to 511
|
||||
// end of word
|
||||
u16 accuracy:7;
|
||||
u16 target:9;
|
||||
u8 pp;
|
||||
union {
|
||||
u8 effect;
|
||||
u8 powerOverride;
|
||||
} zMove;
|
||||
// end of word
|
||||
s32 priority:4;
|
||||
u32 recoil:7;
|
||||
u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit.
|
||||
u32 criticalHitStage:2;
|
||||
bool32 alwaysCriticalHit:1;
|
||||
u32 numAdditionalEffects:2; // limited to 3 - don't want to get too crazy
|
||||
// Flags
|
||||
bool32 makesContact:1;
|
||||
bool32 ignoresProtect:1;
|
||||
bool32 magicCoatAffected:1;
|
||||
bool32 snatchAffected:1;
|
||||
bool32 ignoresKingsRock:1;
|
||||
bool32 punchingMove:1;
|
||||
bool32 bitingMove:1;
|
||||
bool32 pulseMove:1;
|
||||
bool32 soundMove:1;
|
||||
bool32 ballisticMove:1;
|
||||
bool32 powderMove:1;
|
||||
bool32 danceMove:1;
|
||||
// end of word
|
||||
bool32 windMove:1;
|
||||
bool32 slicingMove:1;
|
||||
bool32 healingMove:1;
|
||||
bool32 minimizeDoubleDamage:1;
|
||||
bool32 ignoresTargetAbility:1;
|
||||
bool32 ignoresTargetDefenseEvasionStages:1;
|
||||
bool32 damagesUnderground:1;
|
||||
bool32 damagesUnderwater:1;
|
||||
bool32 damagesAirborne:1;
|
||||
bool32 damagesAirborneDoubleDamage:1;
|
||||
bool32 ignoreTypeIfFlyingAndUngrounded:1;
|
||||
bool32 thawsUser:1;
|
||||
bool32 ignoresSubstitute:1;
|
||||
bool32 forcePressure:1;
|
||||
bool32 cantUseTwice:1;
|
||||
// Ban flags
|
||||
bool32 gravityBanned:1;
|
||||
bool32 mirrorMoveBanned:1;
|
||||
bool32 meFirstBanned:1;
|
||||
bool32 mimicBanned:1;
|
||||
bool32 metronomeBanned:1;
|
||||
bool32 copycatBanned:1;
|
||||
bool32 assistBanned:1; // Matches same moves as copycatBanned + semi-invulnerable moves and Mirror Coat.
|
||||
bool32 sleepTalkBanned:1;
|
||||
bool32 instructBanned:1;
|
||||
bool32 encoreBanned:1;
|
||||
bool32 parentalBondBanned:1;
|
||||
bool32 skyBattleBanned:1;
|
||||
bool32 sketchBanned:1;
|
||||
u32 padding:19;
|
||||
// end of word
|
||||
|
||||
union {
|
||||
struct {
|
||||
u16 stringId;
|
||||
u16 status;
|
||||
} twoTurnAttack;
|
||||
struct {
|
||||
u16 side;
|
||||
u16 property; // can be used to remove the hardcoded values
|
||||
} protect;
|
||||
u32 status;
|
||||
u16 moveProperty;
|
||||
u16 holdEffect;
|
||||
u16 type;
|
||||
u16 fixedDamage;
|
||||
u16 absorbPercentage;
|
||||
u16 maxEffect;
|
||||
} argument;
|
||||
|
||||
// primary/secondary effects
|
||||
const struct AdditionalEffect *additionalEffects;
|
||||
|
||||
// contest parameters
|
||||
u8 contestEffect;
|
||||
u8 contestCategory:3;
|
||||
u8 contestComboStarterId;
|
||||
u8 contestComboMoves[MAX_COMBO_MOVES];
|
||||
const u8 *battleAnimScript;
|
||||
};
|
||||
|
||||
extern const struct MoveInfo gMovesInfo[];
|
||||
extern const u8 gNotDoneYetDescription[];
|
||||
extern const struct BattleMoveEffect gBattleMoveEffects[];
|
||||
|
||||
static inline u32 SanitizeMoveId(u32 moveId)
|
||||
{
|
||||
if (moveId >= MOVES_COUNT_ALL)
|
||||
return MOVE_NONE;
|
||||
else
|
||||
return moveId;
|
||||
}
|
||||
|
||||
static inline const u8 *GetMoveName(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].name;
|
||||
}
|
||||
|
||||
static inline const u8 *GetMoveDescription(u32 moveId)
|
||||
{
|
||||
moveId = SanitizeMoveId(moveId);
|
||||
if (gMovesInfo[moveId].effect == EFFECT_PLACEHOLDER)
|
||||
return gNotDoneYetDescription;
|
||||
return gMovesInfo[moveId].description;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveEffect(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].effect;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveType(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].type;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveCategory(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].category;
|
||||
}
|
||||
|
||||
static inline u32 GetMovePower(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].power;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveAccuracy(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].accuracy;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveTarget(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].target;
|
||||
}
|
||||
|
||||
static inline u32 GetMovePP(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].pp;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveZEffect(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].zMove.effect;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveZPowerOverride(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].zMove.powerOverride;
|
||||
}
|
||||
|
||||
static inline s32 GetMovePriority(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].priority;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveRecoil(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].recoil;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveStrikeCount(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].strikeCount;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveCriticalHitStage(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].criticalHitStage;
|
||||
}
|
||||
|
||||
static inline bool32 MoveAlwaysCrits(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].alwaysCriticalHit;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveAdditionalEffectCount(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].numAdditionalEffects;
|
||||
}
|
||||
|
||||
static inline bool32 MoveMakesContact(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].makesContact;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIgnoresProtect(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ignoresProtect;
|
||||
}
|
||||
|
||||
static inline bool32 MoveCanBeBouncedBack(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].magicCoatAffected;
|
||||
}
|
||||
|
||||
static inline bool32 MoveCanBeSnatched(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].snatchAffected;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIgnoresKingsRock(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ignoresKingsRock;
|
||||
}
|
||||
|
||||
static inline bool32 IsPunchingMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].punchingMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsBitingMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].bitingMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsPulseMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].pulseMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsSoundMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].soundMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsBallisticMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ballisticMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsPowderMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].powderMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsDanceMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].danceMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsWindMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].windMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsSlicingMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].slicingMove;
|
||||
}
|
||||
|
||||
static inline bool32 IsHealingMove(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].healingMove;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIncreasesPowerToMinimizedTargets(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].minimizeDoubleDamage;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIgnoresTargetAbility(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ignoresTargetAbility;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIgnoresDefenseEvasionStages(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ignoresTargetDefenseEvasionStages;
|
||||
}
|
||||
|
||||
static inline bool32 MoveDamagesUnderground(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].damagesUnderground;
|
||||
}
|
||||
|
||||
static inline bool32 MoveDamagesUnderWater(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].damagesUnderwater;
|
||||
}
|
||||
|
||||
static inline bool32 MoveDamagesAirborne(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].damagesAirborne;
|
||||
}
|
||||
|
||||
static inline bool32 MoveDamagesAirborneDoubleDamage(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].damagesAirborneDoubleDamage;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIgnoresTypeIfFlyingAndUngrounded(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ignoreTypeIfFlyingAndUngrounded;
|
||||
}
|
||||
|
||||
static inline bool32 MoveThawsUser(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].thawsUser;
|
||||
}
|
||||
|
||||
static inline bool32 MoveIgnoresSubstitute(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].ignoresSubstitute;
|
||||
}
|
||||
|
||||
static inline bool32 MoveForcesPressure(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].forcePressure;
|
||||
}
|
||||
|
||||
static inline bool32 MoveCantBeUsedTwice(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].cantUseTwice;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveGravityBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].gravityBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveMirrorMoveBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].mirrorMoveBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveMeFirstBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].meFirstBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveMimicBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].mimicBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveMetronomeBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].metronomeBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveCopycatBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].copycatBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveAssistBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].assistBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveSleepTalkBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].sleepTalkBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveInstructBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].instructBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveEncoreBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].encoreBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveParentalBondBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].parentalBondBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveSkyBattleBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].skyBattleBanned;
|
||||
}
|
||||
|
||||
static inline bool32 IsMoveSketchBanned(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].sketchBanned;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveTwoTurnAttackStringId(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.stringId;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveTwoTurnAttackStatus(u32 moveId)
|
||||
{
|
||||
return UNCOMPRESS_BITS(gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.status);
|
||||
}
|
||||
|
||||
static inline u32 GetMoveTwoTurnAttackWeather(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.twoTurnAttack.status;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveProtectSide(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.protect.side;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveEffectArg_Status(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.status;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveEffectArg_MoveProperty(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.moveProperty;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveEffectArg_HoldEffect(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.holdEffect;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveArgType(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.type;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveFixedDamage(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.fixedDamage;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveAbsorbPercentage(u32 moveId)
|
||||
{
|
||||
moveId = SanitizeMoveId(moveId);
|
||||
if (gMovesInfo[moveId].argument.absorbPercentage == 0)
|
||||
return 50;
|
||||
return gMovesInfo[moveId].argument.absorbPercentage;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveMaxEffect(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].argument.maxEffect;
|
||||
}
|
||||
|
||||
static inline const struct AdditionalEffect *GetMoveAdditionalEffectById(u32 moveId, u32 effect)
|
||||
{
|
||||
return &gMovesInfo[SanitizeMoveId(moveId)].additionalEffects[effect];
|
||||
}
|
||||
|
||||
static inline u32 GetMoveContestEffect(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].contestEffect;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveContestCategory(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].contestCategory;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveContestComboStarter(u32 moveId)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].contestComboStarterId;
|
||||
}
|
||||
|
||||
static inline u32 GetMoveContestComboMoves(u32 moveId, u32 comboMove)
|
||||
{
|
||||
return gMovesInfo[SanitizeMoveId(moveId)].contestComboMoves[comboMove];
|
||||
}
|
||||
|
||||
static inline const u8 *GetMoveAnimationScript(u32 moveId)
|
||||
{
|
||||
moveId = SanitizeMoveId(moveId);
|
||||
if (gMovesInfo[moveId].battleAnimScript == NULL)
|
||||
{
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "No animation for moveId=%u", moveId);
|
||||
return gMovesInfo[MOVE_NONE].battleAnimScript;
|
||||
}
|
||||
return gMovesInfo[moveId].battleAnimScript;
|
||||
}
|
||||
|
||||
static inline const u8 *GetMoveBattleScript(u32 moveId)
|
||||
{
|
||||
moveId = SanitizeMoveId(moveId);
|
||||
if (gBattleMoveEffects[gMovesInfo[moveId].effect].battleScript == NULL)
|
||||
{
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "No effect for moveId=%u", moveId);
|
||||
return gBattleMoveEffects[EFFECT_PLACEHOLDER].battleScript;
|
||||
}
|
||||
return gBattleMoveEffects[gMovesInfo[moveId].effect].battleScript;
|
||||
}
|
||||
|
||||
#endif // GUARD_MOVES_H
|
||||
@ -27,6 +27,9 @@ extern MainCallback gPostMenuFieldCallback;
|
||||
extern u8 gSelectedOrderFromParty[MAX_FRONTIER_PARTY_SIZE];
|
||||
extern u8 gBattlePartyCurrentOrder[PARTY_SIZE / 2];
|
||||
|
||||
extern const struct SpriteSheet gSpriteSheet_HeldItem;
|
||||
extern const u16 gHeldItemPalette[];
|
||||
|
||||
extern void (*gItemUseCB)(u8, TaskFunc);
|
||||
extern const struct SpriteTemplate gSpriteTemplate_StatusIcons;
|
||||
|
||||
|
||||
@ -479,103 +479,6 @@ struct SpeciesInfo /*0xC4*/
|
||||
#endif //OW_POKEMON_OBJECT_EVENTS
|
||||
};
|
||||
|
||||
struct MoveInfo
|
||||
{
|
||||
const u8 *name;
|
||||
const u8 *description;
|
||||
u16 effect;
|
||||
u16 type:5;
|
||||
u16 category:2;
|
||||
u16 power:9; // up to 511
|
||||
u16 accuracy:7;
|
||||
u16 target:9;
|
||||
u8 pp;
|
||||
union {
|
||||
u8 effect;
|
||||
u8 powerOverride;
|
||||
} zMove;
|
||||
|
||||
s32 priority:4;
|
||||
u32 recoil:7;
|
||||
u32 strikeCount:4; // Max 15 hits. Defaults to 1 if not set. May apply its effect on each hit.
|
||||
u32 criticalHitStage:2;
|
||||
u32 alwaysCriticalHit:1;
|
||||
u32 numAdditionalEffects:2; // limited to 3 - don't want to get too crazy
|
||||
// 12 bits left to complete this word - continues into flags
|
||||
|
||||
// Flags
|
||||
u32 makesContact:1;
|
||||
u32 ignoresProtect:1;
|
||||
u32 magicCoatAffected:1;
|
||||
u32 snatchAffected:1;
|
||||
u32 ignoresKingsRock:1;
|
||||
u32 punchingMove:1;
|
||||
u32 bitingMove:1;
|
||||
u32 pulseMove:1;
|
||||
u32 soundMove:1;
|
||||
u32 ballisticMove:1;
|
||||
u32 powderMove:1;
|
||||
u32 danceMove:1;
|
||||
u32 windMove:1;
|
||||
u32 slicingMove:1; // end of word
|
||||
u32 healingMove:1;
|
||||
u32 minimizeDoubleDamage:1;
|
||||
u32 ignoresTargetAbility:1;
|
||||
u32 ignoresTargetDefenseEvasionStages:1;
|
||||
u32 damagesUnderground:1;
|
||||
u32 damagesUnderwater:1;
|
||||
u32 damagesAirborne:1;
|
||||
u32 damagesAirborneDoubleDamage:1;
|
||||
u32 ignoreTypeIfFlyingAndUngrounded:1;
|
||||
u32 thawsUser:1;
|
||||
u32 ignoresSubstitute:1;
|
||||
u32 forcePressure:1;
|
||||
u32 cantUseTwice:1;
|
||||
|
||||
// Ban flags
|
||||
u32 gravityBanned:1;
|
||||
u32 mirrorMoveBanned:1;
|
||||
u32 meFirstBanned:1;
|
||||
u32 mimicBanned:1;
|
||||
u32 metronomeBanned:1;
|
||||
u32 copycatBanned:1;
|
||||
u32 assistBanned:1; // Matches same moves as copycatBanned + semi-invulnerable moves and Mirror Coat.
|
||||
u32 sleepTalkBanned:1;
|
||||
u32 instructBanned:1;
|
||||
u32 encoreBanned:1;
|
||||
u32 parentalBondBanned:1;
|
||||
u32 skyBattleBanned:1;
|
||||
u32 sketchBanned:1;
|
||||
u32 padding:5; // end of word
|
||||
|
||||
u32 argument;
|
||||
|
||||
// primary/secondary effects
|
||||
const struct AdditionalEffect *additionalEffects;
|
||||
|
||||
// contest parameters
|
||||
u8 contestEffect;
|
||||
u8 contestCategory:3;
|
||||
u8 contestComboStarterId;
|
||||
u8 contestComboMoves[MAX_COMBO_MOVES];
|
||||
const u8 *battleAnimScript;
|
||||
};
|
||||
|
||||
#define EFFECTS_ARR(...) (const struct AdditionalEffect[]) {__VA_ARGS__}
|
||||
#define ADDITIONAL_EFFECTS(...) EFFECTS_ARR( __VA_ARGS__ ), .numAdditionalEffects = ARRAY_COUNT(EFFECTS_ARR( __VA_ARGS__ ))
|
||||
|
||||
// Just a hack to make a move boosted by Sheer Force despite having no secondary effects affected
|
||||
#define SHEER_FORCE_HACK { .moveEffect = 0, .chance = 100, }
|
||||
|
||||
struct AdditionalEffect
|
||||
{
|
||||
u16 moveEffect;
|
||||
u8 self:1;
|
||||
u8 onlyIfTargetRaisedStats:1;
|
||||
u8 onChargeTurnOnly:1;
|
||||
u8 chance; // 0% = effect certain, primary effect
|
||||
};
|
||||
|
||||
struct Ability
|
||||
{
|
||||
u8 name[ABILITY_NAME_LENGTH + 1];
|
||||
@ -705,7 +608,6 @@ extern struct Pokemon gEnemyParty[PARTY_SIZE];
|
||||
extern struct SpriteTemplate gMultiuseSpriteTemplate;
|
||||
extern u16 gFollowerSteps;
|
||||
|
||||
extern const struct MoveInfo gMovesInfo[];
|
||||
extern const u8 gFacilityClassToPicIndex[];
|
||||
extern const u8 gFacilityClassToTrainerClass[];
|
||||
extern const struct SpeciesInfo gSpeciesInfo[];
|
||||
@ -885,6 +787,7 @@ u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg);
|
||||
u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg);
|
||||
bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method);
|
||||
u16 MonTryLearningNewMoveEvolution(struct Pokemon *mon, bool8 firstMove);
|
||||
void RemoveIVIndexFromList(u8 *ivs, u8 selectedIv);
|
||||
bool32 SpeciesHasGenderDifferences(u16 species);
|
||||
bool32 TryFormChange(u32 monId, u32 side, u16 method);
|
||||
void TryToSetBattleFormChangeMoves(struct Pokemon *mon, u16 method);
|
||||
@ -898,8 +801,6 @@ u16 GetCryIdBySpecies(u16 species);
|
||||
u16 GetSpeciesPreEvolution(u16 species);
|
||||
void HealPokemon(struct Pokemon *mon);
|
||||
void HealBoxPokemon(struct BoxPokemon *boxMon);
|
||||
const u8 *GetMoveName(u16 moveId);
|
||||
const u8 *GetMoveAnimationScript(u16 moveId);
|
||||
void UpdateDaysPassedSinceFormChange(u16 days);
|
||||
void TrySetDayLimitToFormChange(struct Pokemon *mon);
|
||||
u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler);
|
||||
|
||||
@ -24,5 +24,6 @@ void LoadMonIconPalettePersonality(u16 species, u32 personality);
|
||||
void SpriteCB_MonIcon(struct Sprite *sprite);
|
||||
void SetPartyHPBarSprite(struct Sprite *sprite, u8 animNum);
|
||||
u8 GetMonIconPaletteIndexFromSpecies(u16 species);
|
||||
void SafeFreeMonIconPalette(u16 species);
|
||||
|
||||
#endif // GUARD_POKEMON_ICON_H
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
extern u8 gLastViewedMonIndex;
|
||||
|
||||
extern const u8 gNotDoneYetDescription[];
|
||||
extern const struct SpriteTemplate gSpriteTemplate_MoveTypes;
|
||||
extern const struct CompressedSpriteSheet gSpriteSheet_MoveTypes;
|
||||
extern const struct CompressedSpriteSheet gSpriteSheet_CategoryIcons;
|
||||
|
||||
@ -176,6 +176,7 @@ enum RandomTag
|
||||
RNG_RANDOM_TARGET,
|
||||
RNG_AI_PREDICT_ABILITY,
|
||||
RNG_HEALER,
|
||||
RNG_DEXNAV_ENCOUNTER_LEVEL,
|
||||
};
|
||||
|
||||
#define RandomWeighted(tag, ...) \
|
||||
|
||||
@ -209,6 +209,7 @@ extern const u8 gText_MenuOption[];
|
||||
extern const u8 gText_MenuExit[];
|
||||
extern const u8 gText_MenuRetire[];
|
||||
extern const u8 gText_MenuRest[];
|
||||
extern const u8 gText_MenuDexNav[];
|
||||
extern const u8 gText_Floor1[];
|
||||
extern const u8 gText_Floor2[];
|
||||
extern const u8 gText_Floor3[];
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
*
|
||||
* ASSUMPTIONS
|
||||
* {
|
||||
* ASSUME(gMovesInfo[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE);
|
||||
* ASSUME(GetMoveEffect(MOVE_STUN_SPORE) == EFFECT_PARALYZE);
|
||||
* }
|
||||
*
|
||||
* SINGLE_BATTLE_TEST("Stun Spore inflicts paralysis")
|
||||
@ -87,7 +87,7 @@
|
||||
* SINGLE_BATTLE_TEST("Stun Spore does not affect Grass-types")
|
||||
* {
|
||||
* GIVEN {
|
||||
* ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove);
|
||||
* ASSUME(IsPowderMove(MOVE_STUN_SPORE));
|
||||
* ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS);
|
||||
* PLAYER(SPECIES_ODDISH); // 1.
|
||||
* OPPONENT(SPECIES_ODDISH); // 2.
|
||||
@ -129,7 +129,7 @@
|
||||
* PARAMETRIZE { raiseAttack = FALSE; }
|
||||
* PARAMETRIZE { raiseAttack = TRUE; }
|
||||
* GIVEN {
|
||||
* ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
* ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
* PLAYER(SPECIES_WOBBUFFET);
|
||||
* OPPONENT(SPECIES_WOBBUFFET);
|
||||
* } WHEN {
|
||||
@ -176,7 +176,7 @@
|
||||
* Pokémon we can observe the damage of a physical attack with and
|
||||
* without the burn. To document that this test assumes the attack is
|
||||
* physical we can use:
|
||||
* ASSUME(gMovesInfo[MOVE_WHATEVER].category == DAMAGE_CATEGORY_PHYSICAL);
|
||||
* ASSUME(GetMoveCategory(MOVE_WHATEVER) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
*
|
||||
* ASSUMPTIONS
|
||||
* Should be placed immediately after any #includes and contain any
|
||||
@ -186,7 +186,7 @@
|
||||
* move_effect_poison_hit.c should be:
|
||||
* ASSUMPTIONS
|
||||
* {
|
||||
* ASSUME(gMovesInfo[MOVE_POISON_STING].effect == EFFECT_POISON_HIT);
|
||||
* ASSUME(GetMoveEffect(MOVE_POISON_STING) == EFFECT_POISON_HIT);
|
||||
* }
|
||||
*
|
||||
* SINGLE_BATTLE_TEST(name, results...) and DOUBLE_BATTLE_TEST(name, results...)
|
||||
@ -228,7 +228,7 @@
|
||||
* PARAMETRIZE { hp = 99; }
|
||||
* PARAMETRIZE { hp = 33; }
|
||||
* GIVEN {
|
||||
* ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE);
|
||||
* ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE);
|
||||
* PLAYER(SPECIES_CHARMANDER) { Ability(ABILITY_BLAZE); MaxHP(99); HP(hp); }
|
||||
* OPPONENT(SPECIES_WOBBUFFET);
|
||||
* } WHEN {
|
||||
@ -265,7 +265,7 @@
|
||||
*
|
||||
* If the tag is not provided, runs the test 50 times and computes an
|
||||
* approximate pass ratio.
|
||||
* PASSES_RANDOMLY(gMovesInfo[move].accuracy, 100);
|
||||
* PASSES_RANDOMLY(GetMoveAccuracy(move), 100);
|
||||
* Note that this mode of PASSES_RANDOMLY makes the tests run very
|
||||
* slowly and should be avoided where possible. If the mechanic you are
|
||||
* testing is missing its tag, you should add it.
|
||||
@ -287,6 +287,16 @@
|
||||
* GIVEN {
|
||||
* FLAG_SET(FLAG_SYS_EXAMPLE_FLAG);
|
||||
*
|
||||
* WITH_CONFIG(configTag, value)
|
||||
* Runs the test with a specified config override. `configTag` must be
|
||||
* of `enum GenConfigTag`
|
||||
* Example:
|
||||
* GIVEN {
|
||||
* WITH_CONFIG(GEN_CONFIG_GALE_WINGS, GEN_6);
|
||||
* }
|
||||
* The `value` may be inferred from a local variable, e.g. set by
|
||||
* PARAMETRIZE.
|
||||
*
|
||||
* PLAYER(species) and OPPONENT(species)
|
||||
* Adds the species to the player's or opponent's party respectively.
|
||||
* The Pokémon can be further customized with the following functions:
|
||||
@ -488,6 +498,7 @@
|
||||
#include "battle.h"
|
||||
#include "battle_anim.h"
|
||||
#include "data.h"
|
||||
#include "generational_changes.h"
|
||||
#include "item.h"
|
||||
#include "random.h"
|
||||
#include "recorded_battle.h"
|
||||
@ -742,7 +753,7 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
|
||||
/* Test */
|
||||
|
||||
#define TO_DO_BATTLE_TEST(_name) \
|
||||
TEST("TODO: " _name) \
|
||||
TEST(_name) \
|
||||
{ \
|
||||
TO_DO; \
|
||||
}
|
||||
@ -822,6 +833,7 @@ struct moveWithPP {
|
||||
#define AI_LOG AILogScores(__LINE__)
|
||||
|
||||
#define FLAG_SET(flagId) SetFlagForTest(__LINE__, flagId)
|
||||
#define WITH_CONFIG(configTag, value) TestSetConfig(__LINE__, configTag, value)
|
||||
|
||||
#define PLAYER(species) for (OpenPokemon(__LINE__, B_SIDE_PLAYER, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__))
|
||||
#define OPPONENT(species) for (OpenPokemon(__LINE__, B_SIDE_OPPONENT, species); gBattleTestRunnerState->data.currentMon; ClosePokemon(__LINE__))
|
||||
@ -855,6 +867,7 @@ struct moveWithPP {
|
||||
#define Shadow(isShadow) Shadow_(__LINE__, shadow)
|
||||
|
||||
void SetFlagForTest(u32 sourceLine, u16 flagId);
|
||||
void TestSetConfig(u32 sourceLine, enum GenConfigTag configTag, u32 value);
|
||||
void ClearFlagAfterTest(void);
|
||||
void OpenPokemon(u32 sourceLine, u32 side, u32 species);
|
||||
void ClosePokemon(u32 sourceLine);
|
||||
|
||||
@ -95,7 +95,7 @@ s32 Test_MgbaPrintf(const char *fmt, ...);
|
||||
|
||||
#define ASSUMPTIONS \
|
||||
static void Assumptions(void); \
|
||||
__attribute__((section(".tests"), used)) static const struct Test sAssumptions = \
|
||||
__attribute__((section(".tests"), used, no_reorder)) static const struct Test sAssumptions = \
|
||||
{ \
|
||||
.name = "ASSUMPTIONS: " __FILE__, \
|
||||
.filename = __FILE__, \
|
||||
|
||||
@ -25,5 +25,6 @@ void rbox_fill_rectangle(u8 windowId);
|
||||
const u16 *GetTextWindowPalette(u8 id);
|
||||
const u16 *GetOverworldTextboxPalettePtr(void);
|
||||
void LoadSignPostWindowFrameGfx(void);
|
||||
void LoadDexNavWindowGfx(u8 windowId, u16 destOffset, u8 palOffset);
|
||||
|
||||
#endif // GUARD_TEXT_WINDOW_H
|
||||
|
||||
@ -23,6 +23,7 @@ struct WildPokemonHeader
|
||||
const struct WildPokemonInfo *landMonsInfo;
|
||||
const struct WildPokemonInfo *waterMonsInfo;
|
||||
const struct WildPokemonInfo *rockSmashMonsInfo;
|
||||
const struct WildPokemonInfo *hiddenMonsInfo;
|
||||
const struct WildPokemonInfo *fishingMonsInfo;
|
||||
};
|
||||
|
||||
@ -43,5 +44,11 @@ bool8 UpdateRepelCounter(void);
|
||||
bool8 TryDoDoubleWildBattle(void);
|
||||
bool8 StandardWildEncounter_Debug(void);
|
||||
u32 CalculateChainFishingShinyRolls(void);
|
||||
void CreateWildMon(u16 species, u8 level);
|
||||
u16 GetCurrentMapWildMonHeaderId(void);
|
||||
u8 ChooseWildMonIndex_Land(void);
|
||||
u8 ChooseWildMonIndex_WaterRock(void);
|
||||
u8 ChooseHiddenMonIndex(void);
|
||||
bool32 MapHasNoEncounterData(void);
|
||||
|
||||
#endif // GUARD_WILD_ENCOUNTER_H
|
||||
|
||||
@ -38,7 +38,7 @@ SECTIONS {
|
||||
__iwram_end = .;
|
||||
} > IWRAM
|
||||
|
||||
.iwram.sbss (NOLOAD) :
|
||||
.iwram.bss (NOLOAD) :
|
||||
ALIGN(4)
|
||||
{
|
||||
src/*.o(.bss);
|
||||
@ -55,13 +55,17 @@ SECTIONS {
|
||||
data/*.o(COMMON);
|
||||
test/*.o(COMMON);
|
||||
*libc.a:sbrkr.o(COMMON);
|
||||
. = ALIGN(4);
|
||||
} > IWRAM
|
||||
|
||||
/* .persistent starts at 0x3007F00 */
|
||||
/* WARNING: This is the end of the IRQ stack, if there's too
|
||||
* much data it WILL be overwritten. */
|
||||
. = 0x7F00;
|
||||
test/*.o(.persistent);
|
||||
/* .persistent starts at 0x3007F00 */
|
||||
/* WARNING: This is the end of the IRQ stack, if there's too
|
||||
* much data it WILL be overwritten. */
|
||||
|
||||
. = 0x03007F00;
|
||||
.iwram.persistent (NOLOAD) :
|
||||
ALIGN(4)
|
||||
{
|
||||
test/*.o(.persistent);
|
||||
} > IWRAM
|
||||
|
||||
/* BEGIN ROM DATA */
|
||||
@ -79,7 +83,7 @@ SECTIONS {
|
||||
script_data :
|
||||
ALIGN(4)
|
||||
{
|
||||
data/*.o(script_data);
|
||||
data/*.o(script_data);
|
||||
} > ROM =0
|
||||
|
||||
lib_text :
|
||||
@ -114,7 +118,7 @@ SECTIONS {
|
||||
} > ROM =0
|
||||
|
||||
.data.iwram :
|
||||
ALIGN(4)
|
||||
ALIGN(8)
|
||||
{
|
||||
__iwram_lma = .;
|
||||
. = . + (__iwram_end - __iwram_start);
|
||||
|
||||
@ -278,7 +278,7 @@ u32 BattleAI_ChooseMoveOrAction(void)
|
||||
ret = ChooseMoveOrAction_Doubles(sBattler_AI);
|
||||
|
||||
// Clear protect structures, some flags may be set during AI calcs
|
||||
// e.g. pranksterElevated from GetMovePriority
|
||||
// e.g. pranksterElevated from GetBattleMovePriority
|
||||
memset(&gProtectStructs, 0, MAX_BATTLERS_COUNT * sizeof(struct ProtectStruct));
|
||||
#if TESTING
|
||||
TestRunner_Battle_CheckAiMoveScores(sBattler_AI);
|
||||
@ -399,7 +399,7 @@ static u32 Ai_SetMoveAccuracy(struct AiLogicData *aiData, u32 battlerAtk, u32 ba
|
||||
u32 accuracy;
|
||||
u32 abilityAtk = aiData->abilities[battlerAtk];
|
||||
u32 abilityDef = aiData->abilities[battlerDef];
|
||||
if (abilityAtk == ABILITY_NO_GUARD || abilityDef == ABILITY_NO_GUARD || gMovesInfo[move].accuracy == 0) // Moves with accuracy 0 or no guard ability always hit.
|
||||
if (abilityAtk == ABILITY_NO_GUARD || abilityDef == ABILITY_NO_GUARD || GetMoveAccuracy(move) == 0) // Moves with accuracy 0 or no guard ability always hit.
|
||||
accuracy = 100;
|
||||
else
|
||||
accuracy = GetTotalAccuracy(battlerAtk, battlerDef, move, abilityAtk, abilityDef, aiData->holdEffects[battlerAtk], aiData->holdEffects[battlerDef]);
|
||||
@ -431,9 +431,9 @@ static void SetBattlerAiMovesData(struct AiLogicData *aiData, u32 battlerAtk, u3
|
||||
u8 effectiveness = AI_EFFECTIVENESS_x0;
|
||||
move = moves[moveIndex];
|
||||
|
||||
if (move != 0
|
||||
&& move != 0xFFFF
|
||||
//&& !IS_MOVE_STATUS(gMovesInfo[move]) /* we want to get effectiveness and accuracy of status moves */
|
||||
if (move != MOVE_NONE
|
||||
&& move != MOVE_UNAVAILABLE
|
||||
//&& !IsBattleMoveStatus(move) /* we want to get effectiveness and accuracy of status moves */
|
||||
&& !(aiData->moveLimitations[battlerAtk] & (1u << moveIndex)))
|
||||
{
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, &effectiveness, TRUE, weather, rollType);
|
||||
@ -661,7 +661,8 @@ static inline bool32 ShouldConsiderMoveForBattler(u32 battlerAi, u32 battlerDef,
|
||||
{
|
||||
if (battlerAi == BATTLE_PARTNER(battlerDef))
|
||||
{
|
||||
if (gMovesInfo[move].target == MOVE_TARGET_BOTH || gMovesInfo[move].target == MOVE_TARGET_OPPONENTS_FIELD)
|
||||
u32 target = GetBattlerMoveTargetType(battlerAi, move);
|
||||
if (target == MOVE_TARGET_BOTH || target == MOVE_TARGET_OPPONENTS_FIELD)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
@ -707,8 +708,8 @@ static inline void BattleAI_DoAIProcessing(struct AI_ThinkingStruct *aiThink, u3
|
||||
static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
// move data
|
||||
s8 atkPriority = GetMovePriority(battlerAtk, move);
|
||||
u32 moveEffect = gMovesInfo[move].effect;
|
||||
s8 atkPriority = GetBattleMovePriority(battlerAtk, move);
|
||||
u32 moveEffect = GetMoveEffect(move);
|
||||
s32 moveType;
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
@ -722,9 +723,9 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
return score;
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
moveType = GetBattleMoveType(move);
|
||||
|
||||
if (gMovesInfo[move].powderMove && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))
|
||||
if (IsPowderMove(move) && !IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef]))
|
||||
RETURN_SCORE_MINUS(10);
|
||||
|
||||
if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
@ -799,11 +800,11 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
RETURN_SCORE_MINUS(20);
|
||||
break;
|
||||
case ABILITY_JUSTIFIED:
|
||||
if (moveType == TYPE_DARK && !IS_MOVE_STATUS(move))
|
||||
if (moveType == TYPE_DARK && !IsBattleMoveStatus(move))
|
||||
RETURN_SCORE_MINUS(10);
|
||||
break;
|
||||
case ABILITY_RATTLED:
|
||||
if (!IS_MOVE_STATUS(move)
|
||||
if (!IsBattleMoveStatus(move)
|
||||
&& (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG))
|
||||
RETURN_SCORE_MINUS(10);
|
||||
break;
|
||||
@ -820,7 +821,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
RETURN_SCORE_MINUS(10);
|
||||
break;
|
||||
case ABILITY_MAGIC_BOUNCE:
|
||||
if (gMovesInfo[move].magicCoatAffected)
|
||||
if (MoveCanBeBouncedBack(move))
|
||||
RETURN_SCORE_MINUS(20);
|
||||
break;
|
||||
case ABILITY_CONTRARY:
|
||||
@ -889,7 +890,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
RETURN_SCORE_MINUS(20);
|
||||
break;
|
||||
case ABILITY_MAGIC_BOUNCE:
|
||||
if (gMovesInfo[move].magicCoatAffected && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD))
|
||||
if (MoveCanBeBouncedBack(move) && moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY | MOVE_TARGET_OPPONENTS_FIELD))
|
||||
RETURN_SCORE_MINUS(20);
|
||||
break;
|
||||
case ABILITY_SWEET_VEIL:
|
||||
@ -910,7 +911,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
// gen7+ dark type mons immune to priority->elevated moves from prankster
|
||||
if (B_PRANKSTER_DARK_TYPES >= GEN_7 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_DARK)
|
||||
&& aiData->abilities[battlerAtk] == ABILITY_PRANKSTER && IS_MOVE_STATUS(move)
|
||||
&& aiData->abilities[battlerAtk] == ABILITY_PRANKSTER && IsBattleMoveStatus(move)
|
||||
&& !(moveTarget & (MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_USER)))
|
||||
RETURN_SCORE_MINUS(10);
|
||||
|
||||
@ -936,7 +937,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
// the following checks apply to any target (including user)
|
||||
|
||||
// throat chop check
|
||||
if (gDisableStructs[battlerAtk].throatChopTimer && gMovesInfo[move].soundMove)
|
||||
if (gDisableStructs[battlerAtk].throatChopTimer && IsSoundMove(move))
|
||||
return 0; // Can't even select move at all
|
||||
// heal block check
|
||||
if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(battlerAtk, move))
|
||||
@ -955,7 +956,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
RETURN_SCORE_MINUS(30);
|
||||
}
|
||||
|
||||
if (!IS_MOVE_STATUS(move))
|
||||
if (!IsBattleMoveStatus(move))
|
||||
{
|
||||
if (weather & B_WEATHER_SUN_PRIMAL)
|
||||
{
|
||||
@ -974,7 +975,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
switch (moveEffect)
|
||||
{
|
||||
case EFFECT_HIT: // only applies to Vital Throw
|
||||
if (gMovesInfo[move].priority < 0 && AI_IsFaster(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40)
|
||||
if (GetBattleMovePriority(battlerAtk, move) < 0 && AI_IsFaster(battlerAtk, battlerDef, move) && aiData->hpPercents[battlerAtk] < 40)
|
||||
ADJUST_SCORE(-2); // don't want to move last
|
||||
break;
|
||||
default:
|
||||
@ -1696,7 +1697,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (!isDoubleBattle
|
||||
|| !IsBattlerAlive(BATTLE_PARTNER(battlerAtk))
|
||||
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)
|
||||
|| (aiData->partnerMove != MOVE_NONE && IS_MOVE_STATUS(aiData->partnerMove))
|
||||
|| (aiData->partnerMove != MOVE_NONE && IsBattleMoveStatus(aiData->partnerMove))
|
||||
|| *(gBattleStruct->monToSwitchIntoId + BATTLE_PARTNER(battlerAtk)) != PARTY_SIZE) //Partner is switching out.
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
@ -1792,7 +1793,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case EFFECT_CONVERSION:
|
||||
//Check first move type
|
||||
if (IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[gBattleMons[battlerAtk].moves[0]].type))
|
||||
if (IS_BATTLER_OF_TYPE(battlerAtk, GetMoveType(gBattleMons[battlerAtk].moves[0])))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_REST:
|
||||
@ -1883,7 +1884,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_HEAL_BELL:
|
||||
if (!AnyPartyMemberStatused(battlerAtk, gMovesInfo[move].soundMove) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
if (!AnyPartyMemberStatused(battlerAtk, IsSoundMove(move)) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove))
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_ENDURE:
|
||||
@ -1985,7 +1986,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
if (isDoubleBattle)
|
||||
{
|
||||
if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // partner is going to set up hazards
|
||||
if (IsHazardMoveEffect(GetMoveEffect(aiData->partnerMove)) // partner is going to set up hazards
|
||||
&& AI_IsFaster(BATTLE_PARTNER(battlerAtk), battlerAtk, aiData->partnerMove)) // partner is going to set up before the potential Defog
|
||||
{
|
||||
ADJUST_SCORE(-10);
|
||||
@ -2015,7 +2016,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_SEMI_INVULNERABLE:
|
||||
if (predictedMove != MOVE_NONE
|
||||
&& AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
&& gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE)
|
||||
&& GetMoveEffect(predictedMove) == EFFECT_SEMI_INVULNERABLE)
|
||||
ADJUST_SCORE(-10); // Don't Fly/dig/etc if opponent is going to fly/dig/etc after you
|
||||
|
||||
if (BattlerWillFaintFromWeather(battlerAtk, aiData->abilities[battlerAtk])
|
||||
@ -2247,7 +2248,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (isDoubleBattle && gBattleMons[BATTLE_PARTNER(battlerAtk)].hp > 0)
|
||||
{
|
||||
if (aiData->partnerMove != MOVE_NONE
|
||||
&& gMovesInfo[aiData->partnerMove].effect == EFFECT_PLEDGE
|
||||
&& GetMoveEffect(aiData->partnerMove) == EFFECT_PLEDGE
|
||||
&& move != aiData->partnerMove) // Different pledge moves
|
||||
{
|
||||
if (gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & (STATUS1_SLEEP | STATUS1_FREEZE))
|
||||
@ -2435,7 +2436,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
instructedMove = gLastMoves[battlerDef];
|
||||
|
||||
if (instructedMove == MOVE_NONE
|
||||
|| gMovesInfo[instructedMove].instructBanned
|
||||
|| IsMoveInstructBanned(instructedMove)
|
||||
|| MoveHasAdditionalEffectSelf(instructedMove, MOVE_EFFECT_RECHARGE)
|
||||
|| IsZMove(instructedMove)
|
||||
|| (gLockedMoves[battlerDef] != 0 && gLockedMoves[battlerDef] != 0xFFFF)
|
||||
@ -2482,7 +2483,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_SUCKER_PUNCH:
|
||||
if (predictedMove != MOVE_NONE)
|
||||
{
|
||||
if (IS_MOVE_STATUS(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move)) // Opponent going first
|
||||
if (IsBattleMoveStatus(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move)) // Opponent going first
|
||||
ADJUST_SCORE(-10);
|
||||
}
|
||||
break;
|
||||
@ -2523,8 +2524,6 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-4);
|
||||
break;
|
||||
//TODO
|
||||
//case EFFECT_PLASMA_FISTS:
|
||||
//break;
|
||||
//case EFFECT_SHELL_TRAP:
|
||||
//break;
|
||||
//case EFFECT_BEAK_BLAST:
|
||||
@ -2583,7 +2582,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_UPPER_HAND:
|
||||
if (predictedMove == MOVE_NONE || IS_MOVE_STATUS(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move) || GetMovePriority(battlerDef, predictedMove) < 1 || GetMovePriority(battlerDef, predictedMove) > 3) // Opponent going first or not using priority move
|
||||
if (predictedMove == MOVE_NONE || IsBattleMoveStatus(predictedMove) || AI_IsSlower(battlerAtk, battlerDef, move) || GetBattleMovePriority(battlerDef, predictedMove) < 1 || GetBattleMovePriority(battlerDef, predictedMove) > 3) // Opponent going first or not using priority move
|
||||
ADJUST_SCORE(-10);
|
||||
break;
|
||||
case EFFECT_PLACEHOLDER:
|
||||
@ -2619,10 +2618,10 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
if (IS_MOVE_STATUS(move))
|
||||
if (IsBattleMoveStatus(move))
|
||||
return score; // status moves aren't accounted here
|
||||
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && gMovesInfo[move].effect != EFFECT_EXPLOSION)
|
||||
if (CanIndexMoveFaintTarget(battlerAtk, battlerDef, movesetIndex, 0) && GetMoveEffect(move) != EFFECT_EXPLOSION)
|
||||
{
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(FAST_KILL);
|
||||
@ -2631,7 +2630,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
else if (CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& GetWhichBattlerFasterOrTies(battlerAtk, battlerDef, TRUE) != AI_IS_FASTER
|
||||
&& GetMovePriority(battlerAtk, move) > 0)
|
||||
&& GetBattleMovePriority(battlerAtk, move) > 0)
|
||||
{
|
||||
ADJUST_SCORE(LAST_CHANCE);
|
||||
}
|
||||
@ -2643,29 +2642,30 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
// move data
|
||||
u32 moveType = gMovesInfo[move].type;
|
||||
u32 effect = gMovesInfo[move].effect;
|
||||
u32 moveType = GetMoveType(move);
|
||||
u32 effect = GetMoveEffect(move);
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move);
|
||||
// ally data
|
||||
u32 battlerAtkPartner = BATTLE_PARTNER(battlerAtk);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
u32 atkPartnerAbility = aiData->abilities[BATTLE_PARTNER(battlerAtk)];
|
||||
u32 atkPartnerHoldEffect = aiData->holdEffects[BATTLE_PARTNER(battlerAtk)];
|
||||
bool32 partnerProtecting = (gMovesInfo[aiData->partnerMove].effect == EFFECT_PROTECT);
|
||||
u32 partnerEffect = GetMoveEffect(aiData->partnerMove);
|
||||
bool32 partnerProtecting = (partnerEffect == EFFECT_PROTECT);
|
||||
bool32 attackerHasBadAbility = (gAbilitiesInfo[aiData->abilities[battlerAtk]].aiRating < 0);
|
||||
bool32 partnerHasBadAbility = (gAbilitiesInfo[atkPartnerAbility].aiRating < 0);
|
||||
u32 predictedMove = aiData->lastUsedMove[battlerDef];
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
moveType = GetBattleMoveType(move);
|
||||
|
||||
// check what effect partner is using
|
||||
if (aiData->partnerMove != 0)
|
||||
{
|
||||
switch (gMovesInfo[aiData->partnerMove].effect)
|
||||
switch (partnerEffect)
|
||||
{
|
||||
case EFFECT_HELPING_HAND:
|
||||
if (IS_MOVE_STATUS(move))
|
||||
if (IsBattleMoveStatus(move))
|
||||
ADJUST_SCORE(-7);
|
||||
break;
|
||||
case EFFECT_PERISH_SONG:
|
||||
@ -2689,7 +2689,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
} // check partner move effect
|
||||
|
||||
// Adjust for always crit moves
|
||||
if (gMovesInfo[aiData->partnerMove].alwaysCriticalHit && aiData->abilities[battlerAtk] == ABILITY_ANGER_POINT)
|
||||
if (MoveAlwaysCrits(aiData->partnerMove) && aiData->abilities[battlerAtk] == ABILITY_ANGER_POINT)
|
||||
{
|
||||
if (AI_IsSlower(battlerAtk, battlerAtkPartner, move)) // Partner moving first
|
||||
{
|
||||
@ -2697,7 +2697,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (IsAttackBoostMoveEffect(effect))
|
||||
ADJUST_SCORE(-3);
|
||||
// encourage moves hitting multiple opponents
|
||||
if (!IS_MOVE_STATUS(move) && (moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
|
||||
if (!IsBattleMoveStatus(move) && (moveTarget & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY)))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
}
|
||||
}
|
||||
@ -2726,7 +2726,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
ADJUST_SCORE(-5);
|
||||
else if (atkPartnerHoldEffect == HOLD_EFFECT_SCOPE_LENS
|
||||
|| IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_DRAGON)
|
||||
|| gMovesInfo[aiData->partnerMove].criticalHitStage > 0
|
||||
|| GetMoveCriticalHitStage(aiData->partnerMove) > 0
|
||||
|| HasMoveWithCriticalHitChance(battlerAtkPartner))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
@ -2779,7 +2779,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
switch (atkPartnerAbility)
|
||||
{
|
||||
case ABILITY_ANGER_POINT:
|
||||
if (gMovesInfo[move].alwaysCriticalHit == TRUE
|
||||
if (MoveAlwaysCrits(move)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
|
||||
&& AI_IsFaster(battlerAtk, battlerAtkPartner, move)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1))
|
||||
@ -2850,7 +2850,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
break;
|
||||
case ABILITY_JUSTIFIED:
|
||||
if (moveType == TYPE_DARK
|
||||
&& !IS_MOVE_STATUS(move)
|
||||
&& !IsBattleMoveStatus(move)
|
||||
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1))
|
||||
@ -2859,7 +2859,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
}
|
||||
break;
|
||||
case ABILITY_RATTLED:
|
||||
if (!IS_MOVE_STATUS(move)
|
||||
if (!IsBattleMoveStatus(move)
|
||||
&& (moveType == TYPE_DARK || moveType == TYPE_GHOST || moveType == TYPE_BUG)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_SPEED)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 1))
|
||||
@ -2916,7 +2916,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
case EFFECT_BEAT_UP:
|
||||
if (atkPartnerAbility == ABILITY_JUSTIFIED
|
||||
&& moveType == TYPE_DARK
|
||||
&& !IS_MOVE_STATUS(move)
|
||||
&& !IsBattleMoveStatus(move)
|
||||
&& HasMoveWithCategory(battlerAtkPartner, DAMAGE_CATEGORY_PHYSICAL)
|
||||
&& BattlerStatCanRise(battlerAtkPartner, atkPartnerAbility, STAT_ATK)
|
||||
&& !CanIndexMoveFaintTarget(battlerAtk, battlerAtkPartner, AI_THINKING_STRUCT->movesetIndex, 0))
|
||||
@ -2986,7 +2986,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
instructedMove = gLastMoves[battlerAtkPartner];
|
||||
|
||||
if (instructedMove != MOVE_NONE
|
||||
&& !IS_MOVE_STATUS(instructedMove)
|
||||
&& !IsBattleMoveStatus(instructedMove)
|
||||
&& (GetBattlerMoveTargetType(battlerAtkPartner, instructedMove) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) // Use instruct on multi-target moves
|
||||
{
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT);
|
||||
@ -2997,7 +2997,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (AI_IsSlower(battlerAtkPartner, FOE(battlerAtkPartner), aiData->partnerMove) // Opponent mon 1 goes before partner
|
||||
|| AI_IsSlower(battlerAtkPartner, BATTLE_PARTNER(FOE(battlerAtkPartner)), aiData->partnerMove)) // Opponent mon 2 goes before partner
|
||||
{
|
||||
if (gMovesInfo[aiData->partnerMove].effect == EFFECT_COUNTER || gMovesInfo[aiData->partnerMove].effect == EFFECT_MIRROR_COAT)
|
||||
if (partnerEffect == EFFECT_COUNTER || partnerEffect == EFFECT_MIRROR_COAT)
|
||||
break; // These moves need to go last
|
||||
RETURN_SCORE_PLUS(WEAK_EFFECT);
|
||||
}
|
||||
@ -3071,7 +3071,7 @@ static inline bool32 ShouldUseSpreadDamageMove(u32 battlerAtk, u32 move, u32 mov
|
||||
return (IsDoubleBattle()
|
||||
&& noOfHitsToFaintPartner != 0 // Immunity check
|
||||
&& IsBattlerAlive(partnerBattler)
|
||||
&& gMovesInfo[move].target == MOVE_TARGET_FOES_AND_ALLY
|
||||
&& GetBattlerMoveTargetType(battlerAtk, move) == MOVE_TARGET_FOES_AND_ALLY
|
||||
&& !(noOfHitsToFaintPartner < 4 && hitsToFaintOpposingBattler == 1)
|
||||
&& noOfHitsToFaintPartner < 7);
|
||||
}
|
||||
@ -3090,7 +3090,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && gMovesInfo[moves[i]].power)
|
||||
if (moves[i] != MOVE_NONE && GetMovePower(moves[i]) != 0)
|
||||
{
|
||||
noOfHits[i] = GetNoOfHitsToKOBattler(battlerAtk, battlerDef, i);
|
||||
if (ShouldUseSpreadDamageMove(battlerAtk,moves[i], i, noOfHits[i]))
|
||||
@ -3182,27 +3182,28 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId)
|
||||
static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
// move data
|
||||
u32 moveEffect = gMovesInfo[move].effect;
|
||||
u32 moveEffect = GetMoveEffect(move);
|
||||
struct AiLogicData *aiData = AI_DATA;
|
||||
u32 movesetIndex = AI_THINKING_STRUCT->movesetIndex;
|
||||
u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][movesetIndex];
|
||||
|
||||
s32 score = 0;
|
||||
u32 predictedMove = aiData->lastUsedMove[battlerDef];
|
||||
u32 predictedType = GetMoveType(predictedMove);
|
||||
u32 predictedMoveSlot = GetMoveSlot(GetMovesArray(battlerDef), predictedMove);
|
||||
bool32 isDoubleBattle = IsValidDoubleBattle(battlerAtk);
|
||||
u32 i;
|
||||
|
||||
// The AI should understand that while Dynamaxed, status moves function like Protect.
|
||||
if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX && gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS)
|
||||
if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX && GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS)
|
||||
moveEffect = EFFECT_PROTECT;
|
||||
|
||||
// check status move preference
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IS_MOVE_STATUS(move) && effectiveness != AI_EFFECTIVENESS_x0)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_PREFER_STATUS_MOVES && IsBattleMoveStatus(move) && effectiveness != AI_EFFECTIVENESS_x0)
|
||||
ADJUST_SCORE(10);
|
||||
|
||||
// check thawing moves
|
||||
if ((gBattleMons[battlerAtk].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) && gMovesInfo[move].thawsUser)
|
||||
if ((gBattleMons[battlerAtk].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE)) && MoveThawsUser(move))
|
||||
ADJUST_SCORE(10);
|
||||
|
||||
// check burn / frostbite
|
||||
@ -3391,7 +3392,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
score += AI_TryToClearStats(battlerAtk, battlerDef, isDoubleBattle);
|
||||
break;
|
||||
case EFFECT_ROAR:
|
||||
if ((gMovesInfo[move].soundMove && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF)
|
||||
if ((IsSoundMove(move) && aiData->abilities[battlerDef] == ABILITY_SOUNDPROOF)
|
||||
|| aiData->abilities[battlerDef] == ABILITY_SUCTION_CUPS)
|
||||
break;
|
||||
else if (GetActiveGimmick(battlerDef) == GIMMICK_DYNAMAX)
|
||||
@ -3407,7 +3408,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(-2);
|
||||
break;
|
||||
case EFFECT_CONVERSION:
|
||||
if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[gBattleMons[battlerAtk].moves[0]].type))
|
||||
if (!IS_BATTLER_OF_TYPE(battlerAtk, GetMoveType(gBattleMons[battlerAtk].moves[0])))
|
||||
ADJUST_SCORE(WEAK_EFFECT);
|
||||
break;
|
||||
case EFFECT_SWALLOW:
|
||||
@ -3584,7 +3585,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
break;
|
||||
else if (gDisableStructs[battlerDef].encoreTimer == 0
|
||||
&& (B_MENTAL_HERB < GEN_5 || aiData->holdEffects[battlerDef] != HOLD_EFFECT_MENTAL_HERB)
|
||||
&& (gBattleMoveEffects[gMovesInfo[gLastMoves[battlerDef]].effect].encourageEncore))
|
||||
&& (gBattleMoveEffects[GetMoveEffect(gLastMoves[battlerDef])].encourageEncore))
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
break;
|
||||
case EFFECT_SLEEP_TALK:
|
||||
@ -3632,7 +3633,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
switch (move)
|
||||
{
|
||||
case MOVE_QUICK_GUARD:
|
||||
if (predictedMove != MOVE_NONE && gMovesInfo[predictedMove].priority > 0)
|
||||
if (predictedMove != MOVE_NONE && GetMovePriority(predictedMove) > 0)
|
||||
ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score);
|
||||
break;
|
||||
case MOVE_WIDE_GUARD:
|
||||
@ -3647,13 +3648,13 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case MOVE_CRAFTY_SHIELD:
|
||||
if (predictedMove != MOVE_NONE && IS_MOVE_STATUS(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER))
|
||||
if (predictedMove != MOVE_NONE && IsBattleMoveStatus(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER))
|
||||
ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score);
|
||||
break;
|
||||
|
||||
case MOVE_MAT_BLOCK:
|
||||
if (gDisableStructs[battlerAtk].isFirstTurn && predictedMove != MOVE_NONE
|
||||
&& !IS_MOVE_STATUS(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER))
|
||||
&& !IsBattleMoveStatus(predictedMove) && !(GetBattlerMoveTargetType(battlerDef, predictedMove) & MOVE_TARGET_USER))
|
||||
ProtectChecks(battlerAtk, battlerDef, move, predictedMove, &score);
|
||||
break;
|
||||
case MOVE_KINGS_SHIELD:
|
||||
@ -3801,10 +3802,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case EFFECT_SEMI_INVULNERABLE:
|
||||
if (predictedMove != MOVE_NONE && !isDoubleBattle)
|
||||
{
|
||||
u32 predictedEffect = GetMoveEffect(predictedMove);
|
||||
if ((AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
&& (gMovesInfo[predictedMove].effect == EFFECT_EXPLOSION || gMovesInfo[predictedMove].effect == EFFECT_PROTECT))
|
||||
&& (predictedEffect == EFFECT_EXPLOSION || predictedEffect == EFFECT_PROTECT))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else if (gMovesInfo[predictedMove].effect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
|
||||
else if (predictedEffect == EFFECT_SEMI_INVULNERABLE && !(gStatuses3[battlerDef] & STATUS3_SEMI_INVULNERABLE))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
}
|
||||
break;
|
||||
@ -3876,7 +3878,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
if (isDoubleBattle)
|
||||
{
|
||||
if (IsHazardMoveEffect(gMovesInfo[aiData->partnerMove].effect) // Partner is going to set up hazards
|
||||
if (IsHazardMoveEffect(GetMoveEffect(aiData->partnerMove)) // Partner is going to set up hazards
|
||||
&& AI_IsSlower(battlerAtk, BATTLE_PARTNER(battlerAtk), move)) // Partner going first
|
||||
break; // Don't use Defog if partner is going to set up hazards
|
||||
}
|
||||
@ -3897,7 +3899,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
&& IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))
|
||||
{
|
||||
u32 predictedMoveOnPartner = gLastMoves[BATTLE_PARTNER(battlerAtk)];
|
||||
if (predictedMoveOnPartner != MOVE_NONE && !IS_MOVE_STATUS(predictedMoveOnPartner))
|
||||
if (predictedMoveOnPartner != MOVE_NONE && !IsBattleMoveStatus(predictedMoveOnPartner))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
}
|
||||
break;
|
||||
@ -3908,7 +3910,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, STAT_CHANGE_SPDEF));
|
||||
break;
|
||||
case EFFECT_TAUNT:
|
||||
if (IS_MOVE_STATUS(predictedMove))
|
||||
if (IsBattleMoveStatus(predictedMove))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
else if (HasMoveWithCategory(battlerDef, DAMAGE_CATEGORY_STATUS))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
@ -3972,7 +3974,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT); // Force 'em out next turn
|
||||
break;
|
||||
default:
|
||||
if (gMovesInfo[move].effect != EFFECT_BESTOW && aiData->items[battlerAtk] == ITEM_NONE && aiData->items[battlerDef] != ITEM_NONE)
|
||||
if (GetMoveEffect(move) != EFFECT_BESTOW && aiData->items[battlerAtk] == ITEM_NONE && aiData->items[battlerDef] != ITEM_NONE)
|
||||
{
|
||||
switch (aiData->holdEffects[battlerDef])
|
||||
{
|
||||
@ -4033,7 +4035,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_MAGIC_COAT:
|
||||
if (IS_MOVE_STATUS(predictedMove) && GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH))
|
||||
if (IsBattleMoveStatus(predictedMove) && GetBattlerMoveTargetType(battlerDef, predictedMove) & (MOVE_TARGET_SELECTED | MOVE_TARGET_OPPONENTS_FIELD | MOVE_TARGET_BOTH))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_RECYCLE:
|
||||
@ -4113,7 +4115,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case EFFECT_GRUDGE:
|
||||
break;
|
||||
case EFFECT_SNATCH:
|
||||
if (predictedMove != MOVE_NONE && gMovesInfo[predictedMove].snatchAffected)
|
||||
if (predictedMove != MOVE_NONE && MoveCanBeSnatched(predictedMove))
|
||||
ADJUST_SCORE(GOOD_EFFECT); // Steal move
|
||||
break;
|
||||
case EFFECT_MUD_SPORT:
|
||||
@ -4280,7 +4282,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
if ((aiData->abilities[battlerAtk] == ABILITY_VOLT_ABSORB
|
||||
|| aiData->abilities[battlerAtk] == ABILITY_MOTOR_DRIVE
|
||||
|| (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && aiData->abilities[battlerAtk] == ABILITY_LIGHTNING_ROD))
|
||||
&& gMovesInfo[predictedMove].type == TYPE_NORMAL)
|
||||
&& predictedType == TYPE_NORMAL)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_FLING:
|
||||
@ -4311,7 +4313,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_POWDER:
|
||||
if (predictedMove != MOVE_NONE && !IS_MOVE_STATUS(predictedMove) && gMovesInfo[predictedMove].type == TYPE_FIRE)
|
||||
if (predictedMove != MOVE_NONE && !IsBattleMoveStatus(predictedMove) && predictedType == TYPE_FIRE)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_TELEKINESIS:
|
||||
@ -4327,7 +4329,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_SOAK:
|
||||
if (HasMoveWithType(battlerAtk, TYPE_ELECTRIC) || HasMoveWithType(battlerAtk, TYPE_GRASS) || (HasMoveEffect(battlerAtk, EFFECT_SUPER_EFFECTIVE_ON_ARG) && gMovesInfo[move].argument == TYPE_WATER) )
|
||||
if (HasMoveWithType(battlerAtk, TYPE_ELECTRIC) || HasMoveWithType(battlerAtk, TYPE_GRASS) || (HasMoveEffect(battlerAtk, EFFECT_SUPER_EFFECTIVE_ON_ARG) && GetMoveArgType(move) == TYPE_WATER) )
|
||||
ADJUST_SCORE(DECENT_EFFECT); // Get some super effective moves
|
||||
break;
|
||||
case EFFECT_THIRD_TYPE:
|
||||
@ -4369,7 +4371,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first
|
||||
{
|
||||
if (gMovesInfo[predictedMove].type == TYPE_GROUND)
|
||||
if (predictedType == TYPE_GROUND)
|
||||
ADJUST_SCORE(GOOD_EFFECT); // Cause the enemy's move to fail
|
||||
break;
|
||||
}
|
||||
@ -4383,7 +4385,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
break;
|
||||
case EFFECT_CAMOUFLAGE:
|
||||
if (predictedMove != MOVE_NONE && AI_IsFaster(battlerAtk, battlerDef, move) // Attacker goes first
|
||||
&& !IS_MOVE_STATUS(move) && AI_GetMoveEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0)
|
||||
&& !IsBattleMoveStatus(move) && AI_GetMoveEffectiveness(predictedMove, battlerDef, battlerAtk) != AI_EFFECTIVENESS_x0)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
case EFFECT_TOXIC_THREAD:
|
||||
@ -4437,34 +4439,32 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
|| gBattleMons[BATTLE_PARTNER(battlerAtk)].status1 & STATUS1_ANY)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case EFFECT_SALT_CURE:
|
||||
if (IS_BATTLER_ANY_TYPE(battlerDef, TYPE_WATER, TYPE_STEEL))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
} // move effect checks
|
||||
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
// check move additional effects that are likely to happen
|
||||
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
|
||||
// Only consider effects with a guaranteed chance to happen
|
||||
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], &gMovesInfo[move].additionalEffects[i]))
|
||||
if (!MoveEffectIsGuaranteed(battlerAtk, aiData->abilities[battlerAtk], additionalEffect))
|
||||
continue;
|
||||
|
||||
// Consider move effects that target self
|
||||
if (gMovesInfo[move].additionalEffects[i].self)
|
||||
if (additionalEffect->self)
|
||||
{
|
||||
u32 StageStatId;
|
||||
|
||||
if (aiData->abilities[battlerAtk] != ABILITY_CONTRARY)
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_SPD_PLUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_PLUS_1:
|
||||
StageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
StageStatId = STAT_CHANGE_ATK + additionalEffect->moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, StageStatId));
|
||||
break;
|
||||
case MOVE_EFFECT_ATK_PLUS_2:
|
||||
@ -4472,7 +4472,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case MOVE_EFFECT_SPD_PLUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_PLUS_2:
|
||||
case MOVE_EFFECT_SP_DEF_PLUS_2:
|
||||
StageStatId = STAT_CHANGE_ATK_2 + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
StageStatId = STAT_CHANGE_ATK_2 + additionalEffect->moveEffect - MOVE_EFFECT_ATK_PLUS_1;
|
||||
ADJUST_SCORE(IncreaseStatUpScore(battlerAtk, battlerDef, StageStatId));
|
||||
break;
|
||||
case MOVE_EFFECT_ACC_PLUS_1:
|
||||
@ -4492,14 +4492,14 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_SPD_MINUS_1:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_1:
|
||||
StageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1;
|
||||
StageStatId = STAT_CHANGE_ATK + additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1;
|
||||
ADJUST_SCORE(IncreaseStatUpScoreContrary(battlerAtk, battlerDef, StageStatId));
|
||||
break;
|
||||
case MOVE_EFFECT_ATK_MINUS_2:
|
||||
@ -4507,7 +4507,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
case MOVE_EFFECT_SPD_MINUS_2:
|
||||
case MOVE_EFFECT_SP_ATK_MINUS_2:
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_2:
|
||||
StageStatId = STAT_CHANGE_ATK + gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_2;
|
||||
StageStatId = STAT_CHANGE_ATK + additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2;
|
||||
ADJUST_SCORE(IncreaseStatUpScoreContrary(battlerAtk, battlerDef, StageStatId));
|
||||
break;
|
||||
case MOVE_EFFECT_ACC_MINUS_1:
|
||||
@ -4536,7 +4536,7 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
else // consider move effects that hinder the target
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_FLINCH:
|
||||
score += ShouldTryToFlinch(battlerAtk, battlerDef, aiData->abilities[battlerAtk], aiData->abilities[battlerDef], move);
|
||||
@ -4669,11 +4669,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
break;
|
||||
case MOVE_EFFECT_FEINT:
|
||||
if (gMovesInfo[predictedMove].effect == EFFECT_PROTECT)
|
||||
if (GetMoveEffect(predictedMove) == EFFECT_PROTECT)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
break;
|
||||
case MOVE_EFFECT_THROAT_CHOP:
|
||||
if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].soundMove)
|
||||
if (IsSoundMove(GetBestDmgMoveFromBattler(battlerDef, battlerAtk)))
|
||||
{
|
||||
if (AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
@ -4685,6 +4685,11 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
if (!HasMoveWithAdditionalEffect(battlerDef, MOVE_EFFECT_RAPID_SPIN) && ShouldTrap(battlerAtk, battlerDef, move))
|
||||
ADJUST_SCORE(BEST_EFFECT);
|
||||
break;
|
||||
case MOVE_EFFECT_SALT_CURE:
|
||||
if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_WATER) || IS_BATTLER_OF_TYPE(battlerDef, TYPE_STEEL))
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4699,7 +4704,7 @@ static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
if (gMovesInfo[move].power)
|
||||
if (GetMovePower(move) != 0)
|
||||
{
|
||||
if (GetNoOfHitsToKOBattler(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex) == 0)
|
||||
ADJUST_AND_RETURN_SCORE(NO_DAMAGE_OR_FAILS); // No point in checking the move further so return early
|
||||
@ -4728,13 +4733,13 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_SMART_SWITCHING
|
||||
&& AI_IsSlower(battlerAtk, battlerDef, move)
|
||||
&& CanTargetFaintAi(battlerDef, battlerAtk)
|
||||
&& GetMovePriority(battlerAtk, move) == 0)
|
||||
&& GetBattleMovePriority(battlerAtk, move) == 0)
|
||||
{
|
||||
RETURN_SCORE_MINUS(20); // No point in setting up if you will faint. Should just switch if possible..
|
||||
}
|
||||
|
||||
// check effects to prioritize first turn
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_ATTACK_UP:
|
||||
case EFFECT_ATTACK_UP_USER_ALLY:
|
||||
@ -4826,9 +4831,11 @@ static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32
|
||||
{
|
||||
// TEMPORARY - should applied to all moves regardless of EFFECT
|
||||
// Consider move effects
|
||||
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_STEALTH_ROCK:
|
||||
case MOVE_EFFECT_SPIKES:
|
||||
@ -4855,11 +4862,11 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
return score;
|
||||
|
||||
if (gMovesInfo[move].criticalHitStage > 0)
|
||||
if (GetMoveCriticalHitStage(move) > 0)
|
||||
ADJUST_SCORE(DECENT_EFFECT);
|
||||
|
||||
// +3 Score
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_COUNTER:
|
||||
if (gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack + 10)
|
||||
@ -4898,9 +4905,11 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
// TEMPORARY - should applied to all moves regardless of EFFECT
|
||||
// Consider move effects
|
||||
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ALL_STATS_UP:
|
||||
if (Random() & 1)
|
||||
@ -4937,12 +4946,14 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor
|
||||
{
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)
|
||||
|| CountUsablePartyMons(battlerAtk) == 0
|
||||
|| !IS_MOVE_STATUS(move)
|
||||
|| !IsBattleMoveStatus(move)
|
||||
|| !HasMoveEffect(battlerAtk, EFFECT_BATON_PASS)
|
||||
|| IsBattlerTrapped(battlerAtk, TRUE))
|
||||
return score;
|
||||
|
||||
if (IsStatRaisingEffect(gMovesInfo[move].effect))
|
||||
u32 effect = GetMoveEffect(move);
|
||||
|
||||
if (IsStatRaisingEffect(effect))
|
||||
{
|
||||
if (gBattleResults.battleTurnCounter == 0)
|
||||
ADJUST_SCORE(GOOD_EFFECT);
|
||||
@ -4953,7 +4964,7 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor
|
||||
}
|
||||
|
||||
// other specific checks
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (effect)
|
||||
{
|
||||
case EFFECT_INGRAIN:
|
||||
if (!(gStatuses3[battlerAtk] & STATUS3_ROOTED))
|
||||
@ -4985,11 +4996,11 @@ static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 scor
|
||||
|
||||
static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
u32 effect = gMovesInfo[move].effect;
|
||||
u32 effect = GetMoveEffect(move);
|
||||
u32 moveType = 0;
|
||||
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
moveType = GetBattleMoveType(move);
|
||||
|
||||
if (IS_TARGETING_PARTNER(battlerAtk, battlerDef))
|
||||
{
|
||||
@ -5167,7 +5178,7 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
else
|
||||
{
|
||||
// low HP
|
||||
if (IS_MOVE_STATUS(move))
|
||||
if (IsBattleMoveStatus(move))
|
||||
ADJUST_SCORE(-2); // don't use status moves if target is at low health
|
||||
}
|
||||
}
|
||||
@ -5177,9 +5188,9 @@ static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
|
||||
static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
|
||||
{
|
||||
u32 moveEffect = gMovesInfo[move].effect;
|
||||
u32 moveEffect = GetMoveEffect(move);
|
||||
|
||||
if (gMovesInfo[move].category != DAMAGE_CATEGORY_STATUS || gMovesInfo[AI_DATA->partnerMove].effect == moveEffect)
|
||||
if (GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS || GetMoveEffect(AI_DATA->partnerMove) == moveEffect)
|
||||
return score;
|
||||
|
||||
switch (moveEffect)
|
||||
|
||||
@ -108,7 +108,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
aiMove = gBattleMons[battler].moves[i];
|
||||
aiMoveEffect = gMovesInfo[aiMove].effect;
|
||||
aiMoveEffect = GetMoveEffect(aiMove);
|
||||
if (aiMove != MOVE_NONE)
|
||||
{
|
||||
// Check if mon has an "important" status move
|
||||
@ -123,7 +123,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
}
|
||||
|
||||
// Only check damage if it's a damaging move
|
||||
if (!IS_MOVE_STATUS(aiMove))
|
||||
if (!IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
// Check if mon has a super effective move
|
||||
if (AI_GetMoveEffectiveness(aiMove, battler, opposingBattler) >= AI_EFFECTIVENESS_x2)
|
||||
@ -156,7 +156,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
playerMove = gBattleMons[opposingBattler].moves[i];
|
||||
if (playerMove != MOVE_NONE && !IS_MOVE_STATUS(playerMove))
|
||||
if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove))
|
||||
{
|
||||
damageTaken = AI_CalcDamage(playerMove, opposingBattler, battler, &effectiveness, FALSE, weather, DMG_ROLL_HIGHEST).expected;
|
||||
if (damageTaken > maxDamageTaken)
|
||||
@ -332,7 +332,9 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
u16 monAbility;
|
||||
u32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler)));
|
||||
u32 incomingMove = AI_DATA->lastUsedMove[opposingBattler];
|
||||
u32 incomingType = GetMoveType(incomingMove);
|
||||
u32 predictedMove = incomingMove; // Update for move prediction
|
||||
u32 predictedType = GetMoveType(predictedMove);
|
||||
bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove));
|
||||
s32 i, j;
|
||||
|
||||
@ -356,34 +358,34 @@ static bool32 FindMonThatAbsorbsOpponentsMove(u32 battler)
|
||||
}
|
||||
|
||||
// Create an array of possible absorb abilities so the AI considers all of them
|
||||
if (gMovesInfo[predictedMove].type == TYPE_FIRE)
|
||||
if (predictedType == TYPE_FIRE)
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_FLASH_FIRE;
|
||||
}
|
||||
else if (gMovesInfo[predictedMove].type == TYPE_WATER || (isOpposingBattlerChargingOrInvulnerable && gMovesInfo[incomingMove].type == TYPE_WATER))
|
||||
else if (predictedType == TYPE_WATER || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_WATER))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_WATER_ABSORB;
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_DRY_SKIN;
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_STORM_DRAIN;
|
||||
}
|
||||
else if (gMovesInfo[predictedMove].type == TYPE_ELECTRIC || (isOpposingBattlerChargingOrInvulnerable && gMovesInfo[incomingMove].type == TYPE_ELECTRIC))
|
||||
else if (predictedType == TYPE_ELECTRIC || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_ELECTRIC))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_VOLT_ABSORB;
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_MOTOR_DRIVE;
|
||||
if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5)
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_LIGHTNING_ROD;
|
||||
}
|
||||
else if (gMovesInfo[predictedMove].type == TYPE_GRASS || (isOpposingBattlerChargingOrInvulnerable && gMovesInfo[incomingMove].type == TYPE_GRASS))
|
||||
else if (predictedType == TYPE_GRASS || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_GRASS))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_SAP_SIPPER;
|
||||
}
|
||||
else if (gMovesInfo[predictedMove].type == TYPE_GROUND || (isOpposingBattlerChargingOrInvulnerable && gMovesInfo[incomingMove].type == TYPE_GROUND))
|
||||
else if (predictedType == TYPE_GROUND || (isOpposingBattlerChargingOrInvulnerable && incomingType == TYPE_GROUND))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_EARTH_EATER;
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_LEVITATE;
|
||||
}
|
||||
else if (gMovesInfo[predictedMove].soundMove || (isOpposingBattlerChargingOrInvulnerable && gMovesInfo[incomingMove].soundMove))
|
||||
else if (IsSoundMove(predictedMove) || (isOpposingBattlerChargingOrInvulnerable && IsSoundMove(incomingMove)))
|
||||
{
|
||||
absorbingTypeAbilities[numAbsorbingAbilities++] = ABILITY_SOUNDPROOF;
|
||||
}
|
||||
@ -702,7 +704,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc
|
||||
return FALSE;
|
||||
if (gLastHitBy[battler] == 0xFF)
|
||||
return FALSE;
|
||||
if (IS_MOVE_STATUS(gLastLandedMoves[battler]))
|
||||
if (IsBattleMoveStatus(gLastLandedMoves[battler]))
|
||||
return FALSE;
|
||||
|
||||
if (IsDoubleBattle())
|
||||
@ -812,9 +814,10 @@ static bool32 CanMonSurviveHazardSwitchin(u32 battler)
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j, NULL);
|
||||
u32 aiEffect = GetMoveEffect(aiMove);
|
||||
if (MoveHasAdditionalEffectSelf(aiMove, MOVE_EFFECT_RAPID_SPIN)
|
||||
|| (B_DEFOG_EFFECT_CLEARING >= GEN_6 && gMovesInfo[aiMove].effect == EFFECT_DEFOG)
|
||||
|| gMovesInfo[aiMove].effect == EFFECT_TIDY_UP)
|
||||
|| (B_DEFOG_EFFECT_CLEARING >= GEN_6 && aiEffect == EFFECT_DEFOG)
|
||||
|| aiEffect == EFFECT_TIDY_UP)
|
||||
{
|
||||
// Have a mon that can clear the hazards, so switching out is okay
|
||||
return TRUE;
|
||||
@ -841,7 +844,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler)
|
||||
return FALSE;
|
||||
|
||||
// Switch out if status move
|
||||
if (gMovesInfo[encoredMove].category == DAMAGE_CATEGORY_STATUS)
|
||||
if (GetMoveCategory(encoredMove) == DAMAGE_CATEGORY_STATUS)
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
|
||||
// Stay in if effective move
|
||||
@ -861,7 +864,7 @@ static bool32 ShouldSwitchIfBadChoiceLock(u32 battler)
|
||||
|
||||
if (HOLD_EFFECT_CHOICE(holdEffect) && gBattleMons[battler].ability != ABILITY_KLUTZ)
|
||||
{
|
||||
if (gMovesInfo[gLastUsedMove].category == DAMAGE_CATEGORY_STATUS)
|
||||
if (GetMoveCategory(gLastUsedMove) == DAMAGE_CATEGORY_STATUS)
|
||||
return SetSwitchinAndSwitch(battler, PARTY_SIZE);
|
||||
}
|
||||
|
||||
@ -922,7 +925,6 @@ bool32 ShouldSwitch(u32 battler)
|
||||
struct Pokemon *party;
|
||||
s32 i;
|
||||
s32 availableToSwitch;
|
||||
bool32 hasAceMon = FALSE;
|
||||
|
||||
if (gBattleMons[battler].status2 & (STATUS2_WRAPPED | STATUS2_ESCAPE_PREVENTION))
|
||||
return FALSE;
|
||||
@ -970,21 +972,13 @@ bool32 ShouldSwitch(u32 battler)
|
||||
if (i == gBattleStruct->monToSwitchIntoId[battlerIn2])
|
||||
continue;
|
||||
if (IsAceMon(battler, i))
|
||||
{
|
||||
hasAceMon = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
availableToSwitch++;
|
||||
}
|
||||
|
||||
if (availableToSwitch == 0)
|
||||
{
|
||||
if (hasAceMon) // If the ace mon is the only available mon, use it
|
||||
availableToSwitch++;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// NOTE: The sequence of the below functions matter! Do not change unless you have carefully considered the outcome.
|
||||
// Since the order is sequencial, and some of these functions prompt switch to specific party members.
|
||||
@ -1242,7 +1236,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
|
||||
for (j = 0; j < MAX_MON_MOVES; j++)
|
||||
{
|
||||
aiMove = AI_DATA->switchinCandidate.battleMon.moves[j];
|
||||
if (aiMove != MOVE_NONE && !IS_MOVE_STATUS(aiMove))
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
aiMove = GetMonData(&party[i], MON_DATA_MOVE1 + j);
|
||||
dmg = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, rollType);
|
||||
@ -1289,10 +1283,10 @@ static u32 GetSwitchinHazardsDamage(u32 battler, struct BattlePokemon *battleMon
|
||||
{
|
||||
// Stealth Rock
|
||||
if ((hazardFlags & SIDE_STATUS_STEALTH_ROCK) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(gMovesInfo[MOVE_STEALTH_ROCK].type, defType1, defType2, battleMon->maxHP);
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(GetMoveType(MOVE_STEALTH_ROCK), defType1, defType2, battleMon->maxHP);
|
||||
// G-Max Steelsurge
|
||||
if ((hazardFlags & SIDE_STATUS_STEELSURGE) && heldItemEffect != HOLD_EFFECT_HEAVY_DUTY_BOOTS)
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(gMovesInfo[MOVE_G_MAX_STEELSURGE].type, defType1, defType2, battleMon->maxHP);
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(GetMoveType(MOVE_G_MAX_STEELSURGE), defType1, defType2, battleMon->maxHP);
|
||||
// Spikes
|
||||
if ((hazardFlags & SIDE_STATUS_SPIKES) && IsMonGrounded(heldItemEffect, ability, defType1, defType2))
|
||||
{
|
||||
@ -1698,7 +1692,7 @@ static s32 GetMaxDamagePlayerCouldDealToSwitchin(u32 battler, u32 opposingBattle
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
playerMove = gBattleMons[opposingBattler].moves[i];
|
||||
if (playerMove != MOVE_NONE && !IS_MOVE_STATUS(playerMove))
|
||||
if (playerMove != MOVE_NONE && !IsBattleMoveStatus(playerMove))
|
||||
{
|
||||
damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, FALSE, DMG_ROLL_HIGHEST);
|
||||
if (damageTaken > maxDamageTaken)
|
||||
@ -1734,7 +1728,7 @@ static inline bool32 IsFreeSwitch(bool32 isSwitchAfterKO, u32 battlerSwitchingOu
|
||||
// Switch out effects
|
||||
if (!IsDoubleBattle()) // Not handling doubles' additional complexity
|
||||
{
|
||||
if (IsSwitchOutEffect(gMovesInfo[gLastUsedMove].effect) && movedSecond)
|
||||
if (IsSwitchOutEffect(GetMoveEffect(gLastUsedMove)) && movedSecond)
|
||||
return TRUE;
|
||||
if (AI_DATA->ejectButtonSwitch)
|
||||
return TRUE;
|
||||
@ -1775,7 +1769,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
{
|
||||
int revengeKillerId = PARTY_SIZE, slowRevengeKillerId = PARTY_SIZE, fastThreatenId = PARTY_SIZE, slowThreatenId = PARTY_SIZE, damageMonId = PARTY_SIZE;
|
||||
int batonPassId = PARTY_SIZE, typeMatchupId = PARTY_SIZE, typeMatchupEffectiveId = PARTY_SIZE, defensiveMonId = PARTY_SIZE, aceMonId = PARTY_SIZE, trapperId = PARTY_SIZE;
|
||||
int i, j, aliveCount = 0, bits = 0;
|
||||
int i, j, aliveCount = 0, bits = 0, aceMonCount = 0;
|
||||
s32 defensiveMonHitKOThreshold = 3; // 3HKO threshold that candidate defensive mons must exceed
|
||||
s32 playerMonHP = gBattleMons[opposingBattler].hp, maxDamageDealt = 0, damageDealt = 0;
|
||||
u32 aiMove, hitsToKOAI, maxHitsToKO = 0;
|
||||
@ -1798,6 +1792,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
else if (IsAceMon(battler, i))
|
||||
{
|
||||
aceMonId = i;
|
||||
aceMonCount++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@ -1826,7 +1821,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
{
|
||||
aiMove = AI_DATA->switchinCandidate.battleMon.moves[j];
|
||||
|
||||
if (aiMove != MOVE_NONE && !IS_MOVE_STATUS(aiMove))
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_CONSERVATIVE)
|
||||
damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_LOWEST);
|
||||
@ -1856,7 +1851,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
}
|
||||
|
||||
// Check for mon with resistance and super effective move for best type matchup mon with effective move
|
||||
if (aiMove != MOVE_NONE && !IS_MOVE_STATUS(aiMove))
|
||||
if (aiMove != MOVE_NONE && !IsBattleMoveStatus(aiMove))
|
||||
{
|
||||
if (typeMatchup < bestResistEffective)
|
||||
{
|
||||
@ -1871,7 +1866,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
}
|
||||
|
||||
// If a self destruction move doesn't OHKO, don't factor it into revenge killing
|
||||
if (gMovesInfo[aiMove].effect == EFFECT_EXPLOSION && damageDealt < playerMonHP)
|
||||
if (GetMoveEffect(aiMove) == EFFECT_EXPLOSION && damageDealt < playerMonHP)
|
||||
continue;
|
||||
|
||||
// Check that mon isn't one shot and set best damage mon
|
||||
@ -1944,7 +1939,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
else if (batonPassId != PARTY_SIZE) return batonPassId;
|
||||
}
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && IsSwitchOutEffect(gMovesInfo[gLastUsedMove].effect))
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount && IsSwitchOutEffect(GetMoveEffect(gLastUsedMove)))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
@ -2022,7 +2017,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
||||
// This all handled by the GetBestMonIntegrated function if the AI_FLAG_SMART_MON_CHOICES flag is set
|
||||
else
|
||||
{
|
||||
s32 i, aliveCount = 0;
|
||||
s32 i, aliveCount = 0, aceMonCount = 0;
|
||||
u32 invalidMons = 0, aceMonId = PARTY_SIZE;
|
||||
// Get invalid slots ids.
|
||||
for (i = firstId; i < lastId; i++)
|
||||
@ -2039,6 +2034,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
||||
else if (IsAceMon(battler, i)) // Save Ace Pokemon for last.
|
||||
{
|
||||
aceMonId = i;
|
||||
aceMonCount++;
|
||||
invalidMons |= 1u << i;
|
||||
}
|
||||
else
|
||||
@ -2058,8 +2054,8 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd)
|
||||
if (bestMonId != PARTY_SIZE)
|
||||
return bestMonId;
|
||||
|
||||
// If ace mon is the last available Pokemon and switch move was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE)
|
||||
// If ace mon is the last available Pokemon and U-Turn/Volt Switch was used - switch to the mon.
|
||||
if (aceMonId != PARTY_SIZE && CountUsablePartyMons(battler) <= aceMonCount && IsSwitchOutEffect(gMovesInfo[gLastUsedMove].effect))
|
||||
return aceMonId;
|
||||
|
||||
return PARTY_SIZE;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "event_data.h"
|
||||
#include "data.h"
|
||||
#include "item.h"
|
||||
#include "move.h"
|
||||
#include "pokemon.h"
|
||||
#include "random.h"
|
||||
#include "recorded_battle.h"
|
||||
@ -22,16 +23,6 @@
|
||||
#include "constants/moves.h"
|
||||
#include "constants/items.h"
|
||||
|
||||
#define CHECK_MOVE_FLAG(flag) \
|
||||
s32 i; \
|
||||
u16 *moves = GetMovesArray(battler); \
|
||||
for (i = 0; i < MAX_MON_MOVES; i++) \
|
||||
{ \
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].flag) \
|
||||
return TRUE; \
|
||||
} \
|
||||
return FALSE
|
||||
|
||||
static u32 AI_GetEffectiveness(uq4_12_t multiplier);
|
||||
|
||||
// Functions
|
||||
@ -338,9 +329,10 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
u32 move = gBattleResources->battleHistory->usedMoves[opposingBattler][i];
|
||||
if (gMovesInfo[move].effect == EFFECT_PROTECT && move != MOVE_ENDURE)
|
||||
u32 effect = GetMoveEffect(move);
|
||||
if (effect == EFFECT_PROTECT && move != MOVE_ENDURE)
|
||||
return TRUE;
|
||||
if (gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE && AI_IsSlower(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)))
|
||||
if (effect == EFFECT_SEMI_INVULNERABLE && AI_IsSlower(battlerAI, opposingBattler, GetAIChosenMove(battlerAI)))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
@ -373,7 +365,7 @@ bool32 MovesWithCategoryUnusable(u32 attacker, u32 target, u32 category)
|
||||
&& !(unusable & (1u << i)))
|
||||
{
|
||||
SetTypeBeforeUsingMove(moves[i], attacker);
|
||||
moveType = GetMoveType(moves[i]);
|
||||
moveType = GetBattleMoveType(moves[i]);
|
||||
if (CalcTypeEffectivenessMultiplier(moves[i], moveType, attacker, target, AI_DATA->abilities[target], FALSE) != 0)
|
||||
usable |= 1u << i;
|
||||
}
|
||||
@ -450,7 +442,7 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy
|
||||
if (CanAbilityAbsorbMove(battlerAtk, battlerDef, aiData->abilities[battlerDef], move, moveType))
|
||||
return TRUE;
|
||||
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_DREAM_EATER:
|
||||
if (!AI_IsBattlerAsleepOrComatose(battlerDef))
|
||||
@ -470,11 +462,11 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_FAIL_IF_NOT_ARG_TYPE:
|
||||
if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[move].argument))
|
||||
if (!IS_BATTLER_OF_TYPE(battlerAtk, GetMoveArgType(move)))
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_HIT_SET_REMOVE_TERRAIN:
|
||||
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && gMovesInfo[move].argument == ARG_TRY_REMOVE_TERRAIN_FAIL)
|
||||
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && GetMoveEffectArg_MoveProperty(move) == ARG_TRY_REMOVE_TERRAIN_FAIL)
|
||||
return TRUE;
|
||||
break;
|
||||
case EFFECT_POLTERGEIST:
|
||||
@ -512,7 +504,7 @@ static inline s32 GetDamageByRollType(s32 dmg, enum DamageRollType rollType)
|
||||
|
||||
static inline void SetMoveDamageCategory(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
{
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_PHOTON_GEYSER:
|
||||
gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(battlerAtk) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
@ -535,14 +527,14 @@ static inline void SetMoveDamageCategory(u32 battlerAtk, u32 battlerDef, u32 mov
|
||||
static inline s32 SetFixedMoveBasePower(u32 battlerAtk, u32 move)
|
||||
{
|
||||
s32 fixedBasePower = 0, n = 0;
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_ROLLOUT:
|
||||
n = gDisableStructs[battlerAtk].rolloutTimer - 1;
|
||||
fixedBasePower = CalcRolloutBasePower(battlerAtk, gMovesInfo[move].power, n < 0 ? 5 : n);
|
||||
fixedBasePower = CalcRolloutBasePower(battlerAtk, GetMovePower(move), n < 0 ? 5 : n);
|
||||
break;
|
||||
case EFFECT_FURY_CUTTER:
|
||||
fixedBasePower = CalcFuryCutterBasePower(gMovesInfo[move].power, min(gDisableStructs[battlerAtk].furyCutterCounter + 1, 5));
|
||||
fixedBasePower = CalcFuryCutterBasePower(GetMovePower(move), min(gDisableStructs[battlerAtk].furyCutterCounter + 1, 5));
|
||||
break;
|
||||
default:
|
||||
fixedBasePower = 0;
|
||||
@ -554,10 +546,11 @@ static inline s32 SetFixedMoveBasePower(u32 battlerAtk, u32 move)
|
||||
static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCalcData, s32 *expectedDamage, s32 *minimumDamage, u32 holdEffectAtk, u32 abilityAtk)
|
||||
{
|
||||
u32 move = damageCalcData->move;
|
||||
u32 effect = GetMoveEffect(move);
|
||||
s32 expected = *expectedDamage;
|
||||
s32 minimum = *minimumDamage;
|
||||
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (effect)
|
||||
{
|
||||
case EFFECT_LEVEL_DAMAGE:
|
||||
expected = minimum = gBattleMons[damageCalcData->battlerAtk].level * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1);
|
||||
@ -566,7 +559,7 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal
|
||||
expected = minimum = gBattleMons[damageCalcData->battlerAtk].level * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1);
|
||||
break;
|
||||
case EFFECT_FIXED_DAMAGE_ARG:
|
||||
expected = minimum = gMovesInfo[move].argument * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1);
|
||||
expected = minimum = GetMoveFixedDamage(move) * (abilityAtk == ABILITY_PARENTAL_BOND ? 2 : 1);
|
||||
break;
|
||||
case EFFECT_MULTI_HIT:
|
||||
if (move == MOVE_WATER_SHURIKEN && gBattleMons[damageCalcData->battlerAtk].species == SPECIES_GRENINJA_ASH)
|
||||
@ -620,10 +613,11 @@ static inline void CalcDynamicMoveDamage(struct DamageCalculationData *damageCal
|
||||
}
|
||||
|
||||
// Handle other multi-strike moves
|
||||
if (gMovesInfo[move].strikeCount > 1 && gMovesInfo[move].effect != EFFECT_TRIPLE_KICK)
|
||||
u32 strikeCount = GetMoveStrikeCount(move);
|
||||
if (strikeCount > 1 && effect != EFFECT_TRIPLE_KICK)
|
||||
{
|
||||
expected *= gMovesInfo[move].strikeCount;
|
||||
minimum *= gMovesInfo[move].strikeCount;
|
||||
expected *= strikeCount;
|
||||
minimum *= strikeCount;
|
||||
}
|
||||
|
||||
if (expected == 0)
|
||||
@ -639,7 +633,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
{
|
||||
struct SimulatedDamage simDamage;
|
||||
s32 moveType;
|
||||
u32 moveEffect = gMovesInfo[move].effect;
|
||||
u32 moveEffect = GetMoveEffect(move);
|
||||
uq4_12_t effectivenessMultiplier;
|
||||
bool32 isDamageMoveUnusable = FALSE;
|
||||
bool32 toggledGimmick = FALSE;
|
||||
@ -663,13 +657,14 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
|
||||
SetMoveDamageCategory(battlerAtk, battlerDef, move);
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
moveType = GetBattleMoveType(move);
|
||||
effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE);
|
||||
|
||||
if (gMovesInfo[move].power)
|
||||
u32 movePower = GetMovePower(move);
|
||||
if (movePower)
|
||||
isDamageMoveUnusable = IsDamageMoveUnusable(battlerAtk, battlerDef, move, moveType);
|
||||
|
||||
if (gMovesInfo[move].power && !isDamageMoveUnusable)
|
||||
if (movePower && !isDamageMoveUnusable)
|
||||
{
|
||||
s32 critChanceIndex, fixedBasePower;
|
||||
|
||||
@ -723,7 +718,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||
s32 nonCritDmg = 0;
|
||||
if (moveEffect == EFFECT_TRIPLE_KICK)
|
||||
{
|
||||
for (gMultiHitCounter = gMovesInfo[move].strikeCount; gMultiHitCounter > 0; gMultiHitCounter--) // The global is used to simulate actual damage done
|
||||
for (gMultiHitCounter = GetMoveStrikeCount(move); gMultiHitCounter > 0; gMultiHitCounter--) // The global is used to simulate actual damage done
|
||||
{
|
||||
nonCritDmg += CalculateMoveDamageVars(&damageCalcData, fixedBasePower,
|
||||
effectivenessMultiplier, weather,
|
||||
@ -785,7 +780,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
u32 abilityDef = AI_DATA->abilities[battlerDef];
|
||||
u32 abilityAtk = AI_DATA->abilities[battlerAtk];
|
||||
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_HIT_ESCAPE:
|
||||
if (CountUsablePartyMons(battlerAtk) != 0 && ShouldPivot(battlerAtk, battlerDef, abilityDef, move, AI_THINKING_STRUCT->movesetIndex))
|
||||
@ -798,12 +793,14 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
}
|
||||
|
||||
// check ADDITIONAL_EFFECTS
|
||||
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
|
||||
// Consider move effects that target self
|
||||
if (gMovesInfo[move].additionalEffects[i].self)
|
||||
if (additionalEffect->self)
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_ATK_PLUS_2:
|
||||
@ -846,7 +843,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
}
|
||||
else // consider move effects that hinder the target
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_POISON:
|
||||
case MOVE_EFFECT_TOXIC:
|
||||
@ -880,7 +877,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_1:
|
||||
case MOVE_EFFECT_ACC_MINUS_1:
|
||||
case MOVE_EFFECT_EVS_MINUS_1:
|
||||
if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1)
|
||||
if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_1)) && noOfHitsToKo != 1)
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_ATK_MINUS_2:
|
||||
@ -890,7 +887,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3
|
||||
case MOVE_EFFECT_SP_DEF_MINUS_2:
|
||||
case MOVE_EFFECT_ACC_MINUS_2:
|
||||
case MOVE_EFFECT_EVS_MINUS_2:
|
||||
if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (gMovesInfo[move].additionalEffects[i].moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1)
|
||||
if (ShouldLowerStat(battlerDef, abilityDef, STAT_ATK + (additionalEffect->moveEffect - MOVE_EFFECT_ATK_MINUS_2)) && noOfHitsToKo != 1)
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
@ -907,10 +904,10 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
|
||||
u8 i;
|
||||
|
||||
// recoil
|
||||
if (gMovesInfo[move].recoil > 0 && AI_IsDamagedByRecoil(battlerAtk))
|
||||
if (GetMoveRecoil(move) > 0 && AI_IsDamagedByRecoil(battlerAtk))
|
||||
return TRUE;
|
||||
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_MAX_HP_50_RECOIL:
|
||||
case EFFECT_MIND_BLOWN:
|
||||
@ -923,9 +920,11 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
|
||||
break;
|
||||
default:
|
||||
{
|
||||
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MOVE_EFFECT_ATK_MINUS_1:
|
||||
case MOVE_EFFECT_DEF_MINUS_1:
|
||||
@ -944,12 +943,12 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
|
||||
case MOVE_EFFECT_V_CREATE:
|
||||
case MOVE_EFFECT_ATK_DEF_DOWN:
|
||||
case MOVE_EFFECT_DEF_SPDEF_DOWN:
|
||||
if ((gMovesInfo[move].additionalEffects[i].self && abilityAtk != ABILITY_CONTRARY)
|
||||
if ((additionalEffect->self && abilityAtk != ABILITY_CONTRARY)
|
||||
|| (noOfHitsToKo != 1 && abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(abilityAtk, move)))
|
||||
return TRUE;
|
||||
break;
|
||||
case MOVE_EFFECT_RECHARGE:
|
||||
return gMovesInfo[move].additionalEffects[i].self;
|
||||
return additionalEffect->self;
|
||||
case MOVE_EFFECT_ATK_PLUS_1:
|
||||
case MOVE_EFFECT_DEF_PLUS_1:
|
||||
case MOVE_EFFECT_SPD_PLUS_1:
|
||||
@ -965,7 +964,7 @@ static bool32 AI_IsMoveEffectInMinus(u32 battlerAtk, u32 battlerDef, u32 move, s
|
||||
case MOVE_EFFECT_EVS_PLUS_2:
|
||||
case MOVE_EFFECT_ACC_PLUS_2:
|
||||
case MOVE_EFFECT_ALL_STATS_UP:
|
||||
if ((gMovesInfo[move].additionalEffects[i].self && abilityAtk == ABILITY_CONTRARY)
|
||||
if ((additionalEffect->self && abilityAtk == ABILITY_CONTRARY)
|
||||
|| (noOfHitsToKo != 1 && !(abilityDef == ABILITY_CONTRARY && !DoesBattlerIgnoreAbilityChecks(abilityAtk, move))))
|
||||
return TRUE;
|
||||
break;
|
||||
@ -989,9 +988,11 @@ s32 AI_WhichMoveBetter(u32 move1, u32 move2, u32 battlerAtk, u32 battlerDef, s32
|
||||
&& (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_ROCKY_HELMET
|
||||
|| defAbility == ABILITY_IRON_BARBS || defAbility == ABILITY_ROUGH_SKIN))
|
||||
{
|
||||
if (gMovesInfo[move1].makesContact && !gMovesInfo[move2].makesContact)
|
||||
bool32 moveContact1 = MoveMakesContact(move1);
|
||||
bool32 moveContact2 = MoveMakesContact(move2);
|
||||
if (moveContact1 && !moveContact2)
|
||||
return -1;
|
||||
if (gMovesInfo[move2].makesContact && !gMovesInfo[move1].makesContact)
|
||||
if (moveContact2 && !moveContact1)
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1050,7 +1051,7 @@ uq4_12_t AI_GetTypeEffectiveness(u32 move, u32 battlerAtk, u32 battlerDef)
|
||||
|
||||
gBattleStruct->dynamicMoveType = 0;
|
||||
SetTypeBeforeUsingMove(move, battlerAtk);
|
||||
moveType = GetMoveType(move);
|
||||
moveType = GetBattleMoveType(move);
|
||||
typeEffectiveness = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], FALSE);
|
||||
|
||||
RestoreBattlerData(battlerAtk);
|
||||
@ -1102,7 +1103,7 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 moveConsidered)
|
||||
u32 abilityAI = AI_DATA->abilities[battlerAI];
|
||||
u32 abilityPlayer = AI_DATA->abilities[battler];
|
||||
|
||||
if (GetMovePriority(battlerAI, moveConsidered) > 0)
|
||||
if (GetBattleMovePriority(battlerAI, moveConsidered) > 0)
|
||||
return AI_IS_FASTER;
|
||||
|
||||
speedBattlerAI = GetBattlerTotalSpeedStatArgs(battlerAI, abilityAI, holdEffectAI);
|
||||
@ -1142,9 +1143,10 @@ s32 AI_WhoStrikesFirst(u32 battlerAI, u32 battler, u32 moveConsidered)
|
||||
|
||||
static bool32 CanEndureHit(u32 battler, u32 battlerTarget, u32 move)
|
||||
{
|
||||
if (!AI_BattlerAtMaxHp(battlerTarget) || gMovesInfo[move].effect == EFFECT_MULTI_HIT)
|
||||
u32 effect = GetMoveEffect(move);
|
||||
if (!AI_BattlerAtMaxHp(battlerTarget) || effect == EFFECT_MULTI_HIT)
|
||||
return FALSE;
|
||||
if (gMovesInfo[move].strikeCount > 1 && !(gMovesInfo[move].effect == EFFECT_DRAGON_DARTS && IsValidDoubleBattle(battlerTarget)))
|
||||
if (GetMoveStrikeCount(move) > 1 && !(effect == EFFECT_DRAGON_DARTS && IsValidDoubleBattle(battlerTarget)))
|
||||
return FALSE;
|
||||
if (AI_DATA->holdEffects[battlerTarget] == HOLD_EFFECT_FOCUS_SASH)
|
||||
return TRUE;
|
||||
@ -1409,7 +1411,7 @@ bool32 DoesBattlerIgnoreAbilityChecks(u32 atkAbility, u32 move)
|
||||
if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE)
|
||||
return FALSE; // AI handicap flag: doesn't understand ability suppression concept
|
||||
|
||||
if (IsMoldBreakerTypeAbility(sBattler_AI, atkAbility) || gMovesInfo[move].ignoresTargetAbility)
|
||||
if (IsMoldBreakerTypeAbility(sBattler_AI, atkAbility) || MoveIgnoresTargetAbility(move))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
@ -1510,11 +1512,11 @@ bool32 IsSemiInvulnerable(u32 battlerDef, u32 move)
|
||||
return TRUE;
|
||||
else if (gBattleStruct->commandingDondozo & (1u << battlerDef))
|
||||
return TRUE;
|
||||
else if (!gMovesInfo[move].damagesAirborne && gStatuses3[battlerDef] & STATUS3_ON_AIR)
|
||||
else if (!MoveDamagesAirborne(move) && gStatuses3[battlerDef] & STATUS3_ON_AIR)
|
||||
return TRUE;
|
||||
else if (!gMovesInfo[move].damagesUnderwater && gStatuses3[battlerDef] & STATUS3_UNDERWATER)
|
||||
else if (!MoveDamagesUnderWater(move) && gStatuses3[battlerDef] & STATUS3_UNDERWATER)
|
||||
return TRUE;
|
||||
else if (!gMovesInfo[move].damagesUnderground && gStatuses3[battlerDef] & STATUS3_UNDERGROUND)
|
||||
else if (!MoveDamagesUnderground(move) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
@ -1535,22 +1537,23 @@ bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
if (AI_DATA->abilities[battlerDef] == ABILITY_NO_GUARD || AI_DATA->abilities[battlerAtk] == ABILITY_NO_GUARD)
|
||||
return TRUE;
|
||||
|
||||
if (B_TOXIC_NEVER_MISS >= GEN_6 && gMovesInfo[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|
||||
u32 effect = GetMoveEffect(move);
|
||||
if (B_TOXIC_NEVER_MISS >= GEN_6 && effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|
||||
return TRUE;
|
||||
|
||||
// discouraged from hitting
|
||||
weather = AI_GetWeather(AI_DATA);
|
||||
if ((weather & B_WEATHER_SUN) && gMovesInfo[move].effect == EFFECT_THUNDER)
|
||||
if ((weather & B_WEATHER_SUN) && effect == EFFECT_THUNDER)
|
||||
return FALSE;
|
||||
|
||||
// increased accuracy but don't always hit
|
||||
if ((weather & B_WEATHER_RAIN) && gMovesInfo[move].effect == EFFECT_THUNDER)
|
||||
if ((weather & B_WEATHER_RAIN) && effect == EFFECT_THUNDER)
|
||||
return TRUE;
|
||||
if ((weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && gMovesInfo[move].effect == EFFECT_BLIZZARD)
|
||||
if ((weather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && effect == EFFECT_BLIZZARD)
|
||||
return TRUE;
|
||||
if (B_MINIMIZE_DMG_ACC >= GEN_6 && (gStatuses3[battlerDef] & STATUS3_MINIMIZED) && gMovesInfo[move].minimizeDoubleDamage)
|
||||
if (B_MINIMIZE_DMG_ACC >= GEN_6 && (gStatuses3[battlerDef] & STATUS3_MINIMIZED) && MoveIncreasesPowerToMinimizedTargets(move))
|
||||
return TRUE;
|
||||
if (gMovesInfo[move].accuracy == 0)
|
||||
if (GetMoveAccuracy(move) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
@ -1712,7 +1715,7 @@ void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove,
|
||||
|
||||
if (uses == 0)
|
||||
{
|
||||
if (predictedMove != MOVE_NONE && predictedMove != 0xFFFF && !IS_MOVE_STATUS(predictedMove))
|
||||
if (predictedMove != MOVE_NONE && predictedMove != 0xFFFF && !IsBattleMoveStatus(predictedMove))
|
||||
ADJUST_SCORE_PTR(DECENT_EFFECT);
|
||||
else if (Random() % 256 < 100)
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
@ -1976,7 +1979,7 @@ bool32 HasOnlyMovesWithCategory(u32 battlerId, u32 category, bool32 onlyOffensiv
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (onlyOffensive && IS_MOVE_STATUS(moves[i]))
|
||||
if (onlyOffensive && IsBattleMoveStatus(moves[i]))
|
||||
continue;
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetBattleMoveCategory(moves[i]) != category)
|
||||
return FALSE;
|
||||
@ -2005,7 +2008,7 @@ bool32 HasMoveWithType(u32 battler, u32 type)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].type == type)
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMoveType(moves[i]) == type)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2020,14 +2023,14 @@ bool32 HasMoveEffect(u32 battlerId, u32 effect)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
|
||||
&& gMovesInfo[moves[i]].effect == effect)
|
||||
&& GetMoveEffect(moves[i]) == effect)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument)
|
||||
bool32 IsPowerBasedOnStatus(u32 battlerId, u32 effect, u32 argument)
|
||||
{
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battlerId);
|
||||
@ -2035,8 +2038,8 @@ bool32 HasMoveEffectANDArg(u32 battlerId, u32 effect, u32 argument)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
|
||||
&& gMovesInfo[moves[i]].effect == effect
|
||||
&& (gMovesInfo[moves[i]].argument & argument))
|
||||
&& GetMoveEffect(moves[i]) == effect
|
||||
&& (GetMoveEffectArg_Status(moves[i]) & argument))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2066,7 +2069,7 @@ bool32 HasMoveWithCriticalHitChance(u32 battlerId)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
|
||||
&& gMovesInfo[moves[i]].criticalHitStage > 0)
|
||||
&& GetMoveCriticalHitStage(moves[i]) > 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2081,7 +2084,7 @@ bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
|
||||
&& gMovesInfo[moves[i]].effect != exception
|
||||
&& GetMoveEffect(moves[i]) != exception
|
||||
&& MoveHasAdditionalEffect(moves[i], moveEffect))
|
||||
return TRUE;
|
||||
}
|
||||
@ -2127,9 +2130,11 @@ bool32 HasMoveThatLowersOwnStats(u32 battlerId)
|
||||
aiMove = moves[i];
|
||||
if (aiMove != MOVE_NONE && aiMove != MOVE_UNAVAILABLE)
|
||||
{
|
||||
for (j = 0; j < gMovesInfo[aiMove].numAdditionalEffects; j++)
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(aiMove);
|
||||
for (j = 0; j < additionalEffectCount; j++)
|
||||
{
|
||||
if (IsSelfStatLoweringEffect(gMovesInfo[aiMove].additionalEffects[j].moveEffect) && gMovesInfo[aiMove].additionalEffects[j].self)
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(aiMove, j);
|
||||
if (IsSelfStatLoweringEffect(additionalEffect->moveEffect) && additionalEffect->self)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -2150,9 +2155,9 @@ bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool
|
||||
|
||||
if (!((1u << i) & moveLimitations))
|
||||
{
|
||||
if (ignoreStatus && IS_MOVE_STATUS(moves[i]))
|
||||
if (ignoreStatus && IsBattleMoveStatus(moves[i]))
|
||||
continue;
|
||||
else if ((!IS_MOVE_STATUS(moves[i]) && gMovesInfo[moves[i]].accuracy == 0)
|
||||
else if ((!IsBattleMoveStatus(moves[i]) && GetMoveAccuracy(moves[i]) == 0)
|
||||
|| GetBattlerMoveTargetType(battlerAtk, moves[i]) & (MOVE_TARGET_USER | MOVE_TARGET_OPPONENTS_FIELD))
|
||||
continue;
|
||||
|
||||
@ -2176,7 +2181,7 @@ bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef)
|
||||
break;
|
||||
if (!((1u << i) & moveLimitations))
|
||||
{
|
||||
if (gMovesInfo[moves[i]].effect == EFFECT_SLEEP
|
||||
if (GetMoveEffect(moves[i]) == EFFECT_SLEEP
|
||||
&& AI_DATA->moveAccuracy[battlerAtk][battlerDef][i] < 85)
|
||||
return TRUE;
|
||||
}
|
||||
@ -2184,11 +2189,6 @@ bool32 HasSleepMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsHealingMove(u32 move)
|
||||
{
|
||||
return gMovesInfo[move].healingMove;
|
||||
}
|
||||
|
||||
bool32 HasHealingEffect(u32 battlerId)
|
||||
{
|
||||
s32 i;
|
||||
@ -2205,7 +2205,7 @@ bool32 HasHealingEffect(u32 battlerId)
|
||||
|
||||
bool32 IsTrappingMove(u32 move)
|
||||
{
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_MEAN_LOOK:
|
||||
case EFFECT_FAIRY_LOCK:
|
||||
@ -2233,7 +2233,14 @@ bool32 HasTrappingMoveEffect(u32 battler)
|
||||
|
||||
bool32 HasThawingMove(u32 battler)
|
||||
{
|
||||
CHECK_MOVE_FLAG(thawsUser);
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveThawsUser(moves[i]))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsUngroundingEffect(u32 effect)
|
||||
@ -2388,7 +2395,7 @@ bool32 IsSwitchOutEffect(u32 effect)
|
||||
|
||||
static inline bool32 IsMoveSleepClauseTrigger(u32 move)
|
||||
{
|
||||
u32 i, effect = gMovesInfo[move].effect;
|
||||
u32 i, effect = GetMoveEffect(move);
|
||||
|
||||
// Sleeping effects like Sleep Powder, Yawn, Dark Void, etc.
|
||||
switch (effect)
|
||||
@ -2400,9 +2407,11 @@ static inline bool32 IsMoveSleepClauseTrigger(u32 move)
|
||||
}
|
||||
|
||||
// Sleeping effects like G-Max Befuddle, G-Max Snooze, etc.
|
||||
for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++)
|
||||
u32 additionalEffectCount = GetMoveAdditionalEffectCount(move);
|
||||
for (i = 0; i < additionalEffectCount; i++)
|
||||
{
|
||||
switch (gMovesInfo[move].additionalEffects[i].moveEffect)
|
||||
const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i);
|
||||
switch (additionalEffect->moveEffect)
|
||||
{
|
||||
case MAX_EFFECT_EFFECT_SPORE_FOES:
|
||||
case MAX_EFFECT_YAWN_FOE:
|
||||
@ -2419,7 +2428,7 @@ bool32 HasDamagingMove(u32 battlerId)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !IS_MOVE_STATUS(moves[i]))
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && !IsBattleMoveStatus(moves[i]))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2434,7 +2443,7 @@ bool32 HasDamagingMoveOfType(u32 battlerId, u32 type)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE
|
||||
&& !IS_MOVE_STATUS(moves[i]].type == type && gMovesInfo[moves[i]))
|
||||
&& GetMoveType(moves[i]) == type && !IsBattleMoveStatus(moves[i]))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2443,7 +2452,14 @@ bool32 HasDamagingMoveOfType(u32 battlerId, u32 type)
|
||||
|
||||
bool32 HasSubstituteIgnoringMove(u32 battler)
|
||||
{
|
||||
CHECK_MOVE_FLAG(ignoresSubstitute);
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveIgnoresSubstitute(moves[i]))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasHighCritRatioMove(u32 battler)
|
||||
@ -2453,7 +2469,7 @@ bool32 HasHighCritRatioMove(u32 battler)
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && gMovesInfo[moves[i]].criticalHitStage > 0)
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && GetMoveCriticalHitStage(moves[i]) > 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2462,22 +2478,36 @@ bool32 HasHighCritRatioMove(u32 battler)
|
||||
|
||||
bool32 HasMagicCoatAffectedMove(u32 battler)
|
||||
{
|
||||
CHECK_MOVE_FLAG(magicCoatAffected);
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveCanBeBouncedBack(moves[i]))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 HasSnatchAffectedMove(u32 battler)
|
||||
{
|
||||
CHECK_MOVE_FLAG(snatchAffected);
|
||||
s32 i;
|
||||
u16 *moves = GetMovesArray(battler);
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE && MoveCanBeSnatched(moves[i]))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move)
|
||||
{
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_SOLAR_BEAM:
|
||||
case EFFECT_TWO_TURNS_ATTACK:
|
||||
return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB
|
||||
|| (AI_GetWeather(AI_DATA) & gMovesInfo[move].argument));
|
||||
|| (AI_GetWeather(AI_DATA) & GetMoveTwoTurnAttackWeather(move)));
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
@ -2714,7 +2744,7 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler)
|
||||
return FALSE;
|
||||
|
||||
if (flags & SIDE_STATUS_STEALTH_ROCK)
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(gMovesInfo[MOVE_STEALTH_ROCK].type, type1, type2, maxHp);
|
||||
hazardDamage += GetStealthHazardDamageByTypesAndHP(GetMoveType(MOVE_STEALTH_ROCK), type1, type2, maxHp);
|
||||
|
||||
if (flags & SIDE_STATUS_SPIKES && ((type1 != TYPE_FLYING && type2 != TYPE_FLYING
|
||||
&& ability != ABILITY_LEVITATE && holdEffect != HOLD_EFFECT_AIR_BALLOON)
|
||||
@ -2760,7 +2790,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov
|
||||
if (CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
return SHOULD_PIVOT; // Won't get the two turns, pivot
|
||||
|
||||
if (!IS_MOVE_STATUS(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk))
|
||||
if (!IsBattleMoveStatus(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk))
|
||||
|| (AI_BattlerAtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|
||||
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|
||||
|| defAbility == ABILITY_MULTISCALE
|
||||
@ -2769,7 +2799,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov
|
||||
}
|
||||
else if (!hasStatBoost)
|
||||
{
|
||||
if (!IS_MOVE_STATUS(move) && (AI_BattlerAtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|
||||
if (!IsBattleMoveStatus(move) && (AI_BattlerAtMaxHp(battlerDef) && (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH
|
||||
|| (B_STURDY >= GEN_5 && defAbility == ABILITY_STURDY)
|
||||
|| defAbility == ABILITY_MULTISCALE
|
||||
|| defAbility == ABILITY_SHADOW_SHIELD)))
|
||||
@ -2816,7 +2846,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov
|
||||
{
|
||||
if (CanTargetFaintAi(battlerDef, battlerAtk))
|
||||
{
|
||||
if (gMovesInfo[move].effect == EFFECT_TELEPORT)
|
||||
if (GetMoveEffect(move) == EFFECT_TELEPORT)
|
||||
return DONT_PIVOT; // If you're going to faint because you'll go second, use a different move
|
||||
else
|
||||
return CAN_TRY_PIVOT; // You're probably going to faint anyways so if for some reason you don't, better switch
|
||||
@ -2846,7 +2876,7 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov
|
||||
else if (CanAIFaintTarget(battlerAtk, battlerDef, 2))
|
||||
{
|
||||
// can knock out foe in 2 hits
|
||||
if (IS_MOVE_STATUS(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk)) //Damaging move
|
||||
if (IsBattleMoveStatus(move) && ((AI_DATA->shouldSwitch & (1u << battlerAtk)) //Damaging move
|
||||
//&& (switchScore >= SWITCHING_INCREASE_RESIST_ALL_MOVES + SWITCHING_INCREASE_KO_FOE //remove hazards
|
||||
|| (AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_FOCUS_SASH && AI_BattlerAtMaxHp(battlerDef))))
|
||||
return DONT_PIVOT; // Pivot to break the sash
|
||||
@ -3002,7 +3032,7 @@ bool32 AI_CanBeConfused(u32 battlerAtk, u32 battlerDef, u32 move, u32 ability)
|
||||
|
||||
bool32 AI_CanConfuse(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 battlerAtkPartner, u32 move, u32 partnerMove)
|
||||
{
|
||||
if (gMovesInfo[move].target == MOVE_TARGET_FOES_AND_ALLY
|
||||
if (GetBattlerMoveTargetType(battlerAtk, move) == MOVE_TARGET_FOES_AND_ALLY
|
||||
&& AI_CanBeConfused(battlerAtk, battlerDef, move, defAbility)
|
||||
&& !AI_CanBeConfused(battlerAtk, BATTLE_PARTNER(battlerDef), move, AI_DATA->abilities[BATTLE_PARTNER(battlerDef)]))
|
||||
return FALSE;
|
||||
@ -3229,8 +3259,7 @@ bool32 ShouldAbsorb(u32 battlerAtk, u32 battlerDef, u32 move, s32 damage)
|
||||
if (move == 0xFFFF || AI_IsFaster(battlerAtk, battlerDef, move))
|
||||
{
|
||||
// using item or user goes first
|
||||
u32 healPercent = (gMovesInfo[move].argument == 0) ? 50 : gMovesInfo[move].argument;
|
||||
s32 healDmg = (healPercent * damage) / 100;
|
||||
s32 healDmg = (GetMoveAbsorbPercentage(move) * damage) / 100;
|
||||
|
||||
if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK)
|
||||
healDmg = 0;
|
||||
@ -3331,7 +3360,7 @@ bool32 DoesPartnerHaveSameMoveEffect(u32 battlerAtkPartner, u32 battlerDef, u32
|
||||
if (!IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
if (gMovesInfo[move].effect == gMovesInfo[partnerMove].effect
|
||||
if (GetMoveEffect(move) == GetMoveEffect(partnerMove)
|
||||
&& partnerMove != MOVE_NONE
|
||||
&& gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef)
|
||||
{
|
||||
@ -3346,7 +3375,7 @@ bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u3
|
||||
if (!IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
if (gMovesInfo[move].effect == gMovesInfo[partnerMove].effect
|
||||
if (GetMoveEffect(move) == GetMoveEffect(partnerMove)
|
||||
&& partnerMove != MOVE_NONE)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
@ -3358,27 +3387,29 @@ bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef
|
||||
if (!IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
u32 partnerEffect = GetMoveEffect(partnerMove);
|
||||
if (partnerMove != MOVE_NONE
|
||||
&& gBattleStruct->moveTarget[battlerAtkPartner] == battlerDef
|
||||
&& (gMovesInfo[partnerMove].effect == EFFECT_SLEEP
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_POISON
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_TOXIC
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_PARALYZE
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_WILL_O_WISP
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_YAWN))
|
||||
&& (partnerEffect == EFFECT_SLEEP
|
||||
|| partnerEffect == EFFECT_POISON
|
||||
|| partnerEffect == EFFECT_TOXIC
|
||||
|| partnerEffect == EFFECT_PARALYZE
|
||||
|| partnerEffect == EFFECT_WILL_O_WISP
|
||||
|| partnerEffect == EFFECT_YAWN))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 IsMoveEffectWeather(u32 move)
|
||||
{
|
||||
u32 effect = GetMoveEffect(move);
|
||||
if (move != MOVE_NONE
|
||||
&& (gMovesInfo[move].effect == EFFECT_SUNNY_DAY
|
||||
|| gMovesInfo[move].effect == EFFECT_RAIN_DANCE
|
||||
|| gMovesInfo[move].effect == EFFECT_SANDSTORM
|
||||
|| gMovesInfo[move].effect == EFFECT_HAIL
|
||||
|| gMovesInfo[move].effect == EFFECT_SNOWSCAPE
|
||||
|| gMovesInfo[move].effect == EFFECT_CHILLY_RECEPTION))
|
||||
&& (effect == EFFECT_SUNNY_DAY
|
||||
|| effect == EFFECT_RAIN_DANCE
|
||||
|| effect == EFFECT_SANDSTORM
|
||||
|| effect == EFFECT_HAIL
|
||||
|| effect == EFFECT_SNOWSCAPE
|
||||
|| effect == EFFECT_CHILLY_RECEPTION))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
@ -3389,11 +3420,12 @@ bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove)
|
||||
if (!IsDoubleBattle())
|
||||
return FALSE;
|
||||
|
||||
u32 partnerEffect = GetMoveEffect(partnerMove);
|
||||
if (partnerMove != MOVE_NONE
|
||||
&& (gMovesInfo[partnerMove].effect == EFFECT_GRASSY_TERRAIN
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_MISTY_TERRAIN
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_ELECTRIC_TERRAIN
|
||||
|| gMovesInfo[partnerMove].effect == EFFECT_PSYCHIC_TERRAIN))
|
||||
&& (partnerEffect == EFFECT_GRASSY_TERRAIN
|
||||
|| partnerEffect == EFFECT_MISTY_TERRAIN
|
||||
|| partnerEffect == EFFECT_ELECTRIC_TERRAIN
|
||||
|| partnerEffect == EFFECT_PSYCHIC_TERRAIN))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
@ -3443,7 +3475,7 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
u32 i;
|
||||
s32 firstId, lastId;
|
||||
struct Pokemon* party;
|
||||
bool32 hasStatus = AnyPartyMemberStatused(battlerAtk, gMovesInfo[move].soundMove);
|
||||
bool32 hasStatus = AnyPartyMemberStatused(battlerAtk, IsSoundMove(move));
|
||||
bool32 needHealing = FALSE;
|
||||
|
||||
GetAIPartyIndexes(battlerAtk, &firstId, &lastId);
|
||||
@ -3470,7 +3502,7 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
|
||||
if (!IsDoubleBattle())
|
||||
{
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_WISH:
|
||||
if (needHealing)
|
||||
@ -3483,7 +3515,7 @@ bool32 ShouldUseWishAromatherapy(u32 battlerAtk, u32 battlerDef, u32 move)
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_WISH:
|
||||
return ShouldRecover(battlerAtk, battlerDef, move, 50); // Switch recovery isn't good idea in doubles
|
||||
@ -3626,7 +3658,7 @@ bool32 PartyHasMoveCategory(u32 battlerId, u32 category)
|
||||
if (pp > 0 && move != MOVE_NONE)
|
||||
{
|
||||
//TODO - handle photon geyser, light that burns the sky
|
||||
if (gMovesInfo[move].category == category)
|
||||
if (GetMoveCategory(move) == category)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -3847,7 +3879,7 @@ void IncreasePoisonScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_STALL && HasMoveEffect(battlerAtk, EFFECT_PROTECT))
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT); // stall tactic
|
||||
|
||||
if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY)
|
||||
if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PSN_ANY)
|
||||
|| HasMoveEffect(battlerAtk, EFFECT_VENOM_DRENCH)
|
||||
|| AI_DATA->abilities[battlerAtk] == ABILITY_MERCILESS)
|
||||
ADJUST_SCORE_PTR(DECENT_EFFECT);
|
||||
@ -3868,14 +3900,14 @@ void IncreaseBurnScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
|| (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects physical attacker
|
||||
&& gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack + 10))
|
||||
{
|
||||
if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].category == DAMAGE_CATEGORY_PHYSICAL)
|
||||
if (GetMoveCategory(GetBestDmgMoveFromBattler(battlerDef, battlerAtk)) == DAMAGE_CATEGORY_PHYSICAL)
|
||||
ADJUST_SCORE_PTR(DECENT_EFFECT);
|
||||
else
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
}
|
||||
|
||||
if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN)
|
||||
|| HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN))
|
||||
if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN)
|
||||
|| IsPowerBasedOnStatus(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_BURN))
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
}
|
||||
}
|
||||
@ -3892,7 +3924,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
u32 defSpeed = AI_DATA->speedStats[battlerDef];
|
||||
|
||||
if ((defSpeed >= atkSpeed && defSpeed / 2 < atkSpeed) // You'll go first after paralyzing foe
|
||||
|| HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS)
|
||||
|| IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_PARALYSIS)
|
||||
|| (HasMoveWithMoveEffectExcept(battlerAtk, MOVE_EFFECT_FLINCH, EFFECT_FIRST_TURN_ONLY)) // filter out Fake Out
|
||||
|| gBattleMons[battlerDef].status2 & STATUS2_INFATUATION
|
||||
|| gBattleMons[battlerDef].status2 & STATUS2_CONFUSION)
|
||||
@ -3917,8 +3949,8 @@ void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
&& !(HasMoveEffect(battlerDef, EFFECT_SNORE) || HasMoveEffect(battlerDef, EFFECT_SLEEP_TALK)))
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
|
||||
if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP)
|
||||
|| HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP))
|
||||
if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP)
|
||||
|| IsPowerBasedOnStatus(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_SLEEP))
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
}
|
||||
|
||||
@ -3952,21 +3984,21 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score
|
||||
|| (!(AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_OMNISCIENT) // Not Omniscient but expects special attacker
|
||||
&& gSpeciesInfo[gBattleMons[battlerDef].species].baseSpAttack >= gSpeciesInfo[gBattleMons[battlerDef].species].baseAttack + 10))
|
||||
{
|
||||
if (gMovesInfo[GetBestDmgMoveFromBattler(battlerDef, battlerAtk)].category == DAMAGE_CATEGORY_SPECIAL)
|
||||
if (GetMoveCategory(GetBestDmgMoveFromBattler(battlerDef, battlerAtk)) == DAMAGE_CATEGORY_SPECIAL)
|
||||
ADJUST_SCORE_PTR(DECENT_EFFECT);
|
||||
else
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
}
|
||||
|
||||
if (HasMoveEffectANDArg(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE)
|
||||
|| HasMoveEffectANDArg(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE))
|
||||
if (IsPowerBasedOnStatus(battlerAtk, EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE)
|
||||
|| IsPowerBasedOnStatus(BATTLE_PARTNER(battlerAtk), EFFECT_DOUBLE_POWER_ON_ARG_STATUS, STATUS1_FROSTBITE))
|
||||
ADJUST_SCORE_PTR(WEAK_EFFECT);
|
||||
}
|
||||
}
|
||||
|
||||
bool32 AI_MoveMakesContact(u32 ability, u32 holdEffect, u32 move)
|
||||
{
|
||||
if (gMovesInfo[move].makesContact
|
||||
if (MoveMakesContact(move)
|
||||
&& ability != ABILITY_LONG_REACH
|
||||
&& holdEffect != HOLD_EFFECT_PROTECTIVE_PADS)
|
||||
return TRUE;
|
||||
@ -3989,22 +4021,22 @@ bool32 ShouldUseZMove(u32 battlerAtk, u32 battlerDef, u32 chosenMove)
|
||||
struct SimulatedDamage dmg;
|
||||
|
||||
if (gBattleMons[battlerDef].ability == ABILITY_DISGUISE
|
||||
&& !gMovesInfo[zMove].ignoresTargetAbility
|
||||
&& !MoveIgnoresTargetAbility(zMove)
|
||||
&& (gBattleMons[battlerDef].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battlerDef].species == SPECIES_MIMIKYU_TOTEM_DISGUISED))
|
||||
return FALSE; // Don't waste a Z-Move busting disguise
|
||||
if (gBattleMons[battlerDef].ability == ABILITY_ICE_FACE
|
||||
&& !gMovesInfo[zMove].ignoresTargetAbility
|
||||
&& gBattleMons[battlerDef].species == SPECIES_EISCUE_ICE && IS_MOVE_PHYSICAL(chosenMove))
|
||||
&& !MoveIgnoresTargetAbility(zMove)
|
||||
&& gBattleMons[battlerDef].species == SPECIES_EISCUE_ICE && IsBattleMovePhysical(chosenMove))
|
||||
return FALSE; // Don't waste a Z-Move busting Ice Face
|
||||
|
||||
if (IS_MOVE_STATUS(chosenMove) && !IS_MOVE_STATUS(zMove))
|
||||
if (IsBattleMoveStatus(chosenMove) && !IsBattleMoveStatus(zMove))
|
||||
return FALSE;
|
||||
else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(zMove))
|
||||
else if (!IsBattleMoveStatus(chosenMove) && IsBattleMoveStatus(zMove))
|
||||
return FALSE;
|
||||
|
||||
dmg = AI_CalcDamageSaveBattlers(chosenMove, battlerAtk, battlerDef, &effectiveness, FALSE, DMG_ROLL_DEFAULT);
|
||||
|
||||
if (!IS_MOVE_STATUS(chosenMove) && dmg.minimum >= gBattleMons[battlerDef].hp)
|
||||
if (!IsBattleMoveStatus(chosenMove) && dmg.minimum >= gBattleMons[battlerDef].hp)
|
||||
return FALSE; // don't waste damaging z move if can otherwise faint target
|
||||
|
||||
return TRUE;
|
||||
@ -4107,7 +4139,7 @@ bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, st
|
||||
|| partnerAbility == ABILITY_WHITE_SMOKE
|
||||
|| partnerHoldEffect == HOLD_EFFECT_CLEAR_AMULET);
|
||||
|
||||
switch (gMovesInfo[aiData->partnerMove].effect)
|
||||
switch (GetMoveEffect(aiData->partnerMove))
|
||||
{
|
||||
case EFFECT_DEFENSE_UP:
|
||||
case EFFECT_DEFENSE_UP_2:
|
||||
@ -4125,12 +4157,13 @@ bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, st
|
||||
|
||||
void IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score)
|
||||
{
|
||||
if (gMovesInfo[move].effect == EFFECT_SUBSTITUTE) // Substitute specific
|
||||
u32 effect = GetMoveEffect(move);
|
||||
if (effect == EFFECT_SUBSTITUTE) // Substitute specific
|
||||
{
|
||||
if (HasAnyKnownMove(battlerDef) && GetBestDmgFromBattler(battlerDef, battlerAtk) < gBattleMons[battlerAtk].maxHP / 4)
|
||||
ADJUST_SCORE_PTR(GOOD_EFFECT);
|
||||
}
|
||||
else if (gMovesInfo[move].effect == EFFECT_SHED_TAIL) // Shed Tail specific
|
||||
else if (effect == EFFECT_SHED_TAIL) // Shed Tail specific
|
||||
{
|
||||
if ((ShouldPivot(battlerAtk, battlerDef, AI_DATA->abilities[battlerDef], move, AI_THINKING_STRUCT->movesetIndex))
|
||||
&& (HasAnyKnownMove(battlerDef) && (GetBestDmgFromBattler(battlerDef, battlerAtk) < gBattleMons[battlerAtk].maxHP / 2)))
|
||||
|
||||
@ -2230,7 +2230,7 @@ static void Cmd_jumpifmovetypeequal(void)
|
||||
{
|
||||
const u8 *type = sBattleAnimScriptPtr + 1;
|
||||
sBattleAnimScriptPtr += 2;
|
||||
if (*type != GetMoveType(gCurrentMove))
|
||||
if (*type != GetBattleMoveType(gCurrentMove))
|
||||
sBattleAnimScriptPtr += 4;
|
||||
else
|
||||
sBattleAnimScriptPtr = T2_READ_PTR(sBattleAnimScriptPtr);
|
||||
|
||||
@ -6736,6 +6736,7 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
|
||||
SwapStructData(&gSpecialStatuses[battlerAtk], &gSpecialStatuses[battlerPartner], data, sizeof(struct SpecialStatus));
|
||||
SwapStructData(&gProtectStructs[battlerAtk], &gProtectStructs[battlerPartner], data, sizeof(struct ProtectStruct));
|
||||
SwapStructData(&gBattleSpritesDataPtr->battlerData[battlerAtk], &gBattleSpritesDataPtr->battlerData[battlerPartner], data, sizeof(struct BattleSpriteInfo));
|
||||
SwapStructData(&gBattleStruct->illusion[battlerAtk], &gBattleStruct->illusion[battlerPartner], data, sizeof(struct Illusion));
|
||||
|
||||
SWAP(gBattleSpritesDataPtr->battlerData[battlerAtk].invisible, gBattleSpritesDataPtr->battlerData[battlerPartner].invisible, temp);
|
||||
SWAP(gTransformedPersonalities[battlerAtk], gTransformedPersonalities[battlerPartner], temp);
|
||||
|
||||
@ -4380,6 +4380,29 @@ const struct SpriteTemplate gSpriteTemplate_FlipTurnBack = {
|
||||
.callback = AnimAbsorptionOrb
|
||||
};
|
||||
|
||||
// U-Turn
|
||||
const struct SpriteTemplate gUTurnBallSpriteTemplate =
|
||||
{
|
||||
.tileTag = ANIM_TAG_SMALL_BUBBLES,
|
||||
.paletteTag = ANIM_TAG_RAZOR_LEAF,
|
||||
.oam = &gOamData_AffineOff_ObjNormal_16x16,
|
||||
.anims = gDummySpriteAnimTable,
|
||||
.images = NULL,
|
||||
.affineAnims = gAffineAnims_ShadowBall,
|
||||
.callback = AnimShadowBall,
|
||||
};
|
||||
|
||||
const struct SpriteTemplate gUTurnBallBackSpriteTemplate =
|
||||
{
|
||||
.tileTag = ANIM_TAG_SMALL_BUBBLES,
|
||||
.paletteTag = ANIM_TAG_RAZOR_LEAF,
|
||||
.oam = &gOamData_AffineOff_ObjNormal_16x16,
|
||||
.anims = gDummySpriteAnimTable,
|
||||
.images = NULL,
|
||||
.affineAnims = gAffineAnims_ShadowBall,
|
||||
.callback = AnimAbsorptionOrb,
|
||||
};
|
||||
|
||||
// wicked blow
|
||||
static const union AffineAnimCmd sSpriteAffineAnim_DrainPunchFist[] = {
|
||||
AFFINEANIMCMD_FRAME(256, 256, 0, 1), //Double sprite size
|
||||
@ -9244,19 +9267,19 @@ void AnimTask_DynamaxGrowth(u8 taskId) // from CFRU
|
||||
|
||||
void AnimTask_GetWeatherToSet(u8 taskId)
|
||||
{
|
||||
switch (gMovesInfo[gCurrentMove].argument)
|
||||
switch (GetMoveMaxEffect(gCurrentMove))
|
||||
{
|
||||
case MAX_EFFECT_SUN:
|
||||
gBattleAnimArgs[ARG_RET_ID] = 1;
|
||||
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_SUN;
|
||||
break;
|
||||
case MAX_EFFECT_RAIN:
|
||||
gBattleAnimArgs[ARG_RET_ID] = 2;
|
||||
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_RAIN;
|
||||
break;
|
||||
case MAX_EFFECT_SANDSTORM:
|
||||
gBattleAnimArgs[ARG_RET_ID] = 3;
|
||||
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_SANDSTORM;
|
||||
break;
|
||||
case MAX_EFFECT_HAIL:
|
||||
gBattleAnimArgs[ARG_RET_ID] = 4;
|
||||
gBattleAnimArgs[ARG_RET_ID] = ANIM_WEATHER_HAIL;
|
||||
break;
|
||||
}
|
||||
DestroyAnimVisualTask(taskId);
|
||||
|
||||
@ -362,18 +362,19 @@ void BattleArena_AddMindPoints(u8 battler)
|
||||
// - Fake Out subtracts 1 point
|
||||
// All status moves give 0 points, with the following exceptions:
|
||||
// - Protect, Detect, and Endure subtract 1 point
|
||||
u32 effect = GetMoveEffect(gCurrentMove);
|
||||
|
||||
if (gMovesInfo[gCurrentMove].effect == EFFECT_FIRST_TURN_ONLY
|
||||
|| gMovesInfo[gCurrentMove].effect == EFFECT_PROTECT
|
||||
|| gMovesInfo[gCurrentMove].effect == EFFECT_ENDURE)
|
||||
if (effect == EFFECT_FIRST_TURN_ONLY
|
||||
|| effect == EFFECT_PROTECT
|
||||
|| effect == EFFECT_ENDURE)
|
||||
{
|
||||
gBattleStruct->arenaMindPoints[battler]--;
|
||||
}
|
||||
else if (!IS_MOVE_STATUS(gCurrentMove)
|
||||
&& gMovesInfo[gCurrentMove].effect != EFFECT_COUNTER
|
||||
&& gMovesInfo[gCurrentMove].effect != EFFECT_MIRROR_COAT
|
||||
&& gMovesInfo[gCurrentMove].effect != EFFECT_METAL_BURST
|
||||
&& gMovesInfo[gCurrentMove].effect != EFFECT_BIDE)
|
||||
else if (!IsBattleMoveStatus(gCurrentMove)
|
||||
&& effect != EFFECT_COUNTER
|
||||
&& effect != EFFECT_MIRROR_COAT
|
||||
&& effect != EFFECT_METAL_BURST
|
||||
&& effect != EFFECT_BIDE)
|
||||
{
|
||||
gBattleStruct->arenaMindPoints[battler]++;
|
||||
}
|
||||
|
||||
@ -609,7 +609,7 @@ static void OpponentHandleChooseMove(u32 battler)
|
||||
} while (!CanTargetBattler(battler, target, move));
|
||||
|
||||
// Don't bother to loop through table if the move can't attack ally
|
||||
if (B_WILD_NATURAL_ENEMIES == TRUE && !(gMovesInfo[move].target & MOVE_TARGET_BOTH))
|
||||
if (B_WILD_NATURAL_ENEMIES == TRUE && !(GetBattlerMoveTargetType(battler, move) & MOVE_TARGET_BOTH))
|
||||
{
|
||||
u16 i, speciesAttacker, speciesTarget, isPartnerEnemy = FALSE;
|
||||
static const u16 naturalEnemies[][2] =
|
||||
|
||||
@ -680,13 +680,13 @@ void HandleInputChooseMove(u32 battler)
|
||||
if (gBattleStruct->zmove.viewing)
|
||||
{
|
||||
gBattleStruct->zmove.viewing = FALSE;
|
||||
if (gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].category != DAMAGE_CATEGORY_STATUS)
|
||||
if (GetMoveCategory(moveInfo->moves[gMoveSelectionCursor[battler]]) != DAMAGE_CATEGORY_STATUS)
|
||||
moveTarget = MOVE_TARGET_SELECTED; //damaging z moves always have selected target
|
||||
}
|
||||
|
||||
// Status moves turn into Max Guard when Dynamaxed, targets user.
|
||||
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX))
|
||||
moveTarget = gMovesInfo[GetMaxMove(battler, moveInfo->moves[gMoveSelectionCursor[battler]])].target;
|
||||
moveTarget = GetMoveTarget(GetMaxMove(battler, moveInfo->moves[gMoveSelectionCursor[battler]]));
|
||||
|
||||
if (moveTarget & MOVE_TARGET_USER)
|
||||
gMultiUsePlayerCursor = battler;
|
||||
@ -1715,7 +1715,7 @@ static void MoveSelectionDisplayMoveType(u32 battler)
|
||||
u32 speciesId;
|
||||
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]);
|
||||
txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType);
|
||||
type = gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].type;
|
||||
type = GetMoveType(moveInfo->moves[gMoveSelectionCursor[battler]]);
|
||||
|
||||
if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_BLAST)
|
||||
{
|
||||
@ -1731,7 +1731,7 @@ static void MoveSelectionDisplayMoveType(u32 battler)
|
||||
|| speciesId == SPECIES_OGERPON_CORNERSTONE || speciesId == SPECIES_OGERPON_CORNERSTONE_TERA)
|
||||
type = gBattleMons[battler].types[1];
|
||||
}
|
||||
else if (gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].category == DAMAGE_CATEGORY_STATUS
|
||||
else if (GetMoveCategory(moveInfo->moves[gMoveSelectionCursor[battler]]) == DAMAGE_CATEGORY_STATUS
|
||||
&& (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX)))
|
||||
{
|
||||
type = TYPE_NORMAL; // Max Guard is always a Normal-type move
|
||||
@ -1757,8 +1757,8 @@ static void MoveSelectionDisplayMoveDescription(u32 battler)
|
||||
{
|
||||
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct*)(&gBattleResources->bufferA[battler][4]);
|
||||
u16 move = moveInfo->moves[gMoveSelectionCursor[battler]];
|
||||
u16 pwr = gMovesInfo[move].power;
|
||||
u16 acc = gMovesInfo[move].accuracy;
|
||||
u16 pwr = GetMovePower(move);
|
||||
u16 acc = GetMoveAccuracy(move);
|
||||
|
||||
u8 pwr_num[3], acc_num[3];
|
||||
u8 cat_desc[7] = _("CAT: ");
|
||||
@ -1786,10 +1786,7 @@ static void MoveSelectionDisplayMoveDescription(u32 battler)
|
||||
StringAppend(gDisplayedStringBattle, acc_desc);
|
||||
StringAppend(gDisplayedStringBattle, acc_num);
|
||||
StringAppend(gDisplayedStringBattle, gText_NewLine);
|
||||
if (gMovesInfo[move].effect == EFFECT_PLACEHOLDER)
|
||||
StringAppend(gDisplayedStringBattle, gNotDoneYetDescription);
|
||||
else
|
||||
StringAppend(gDisplayedStringBattle, gMovesInfo[move].description);
|
||||
StringAppend(gDisplayedStringBattle, GetMoveDescription(move));
|
||||
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_DESCRIPTION);
|
||||
|
||||
if (gCategoryIconSpriteId == 0xFF)
|
||||
@ -2050,8 +2047,9 @@ static void PlayerHandleChooseAction(u32 battler)
|
||||
{
|
||||
StringCopy(gStringVar1, COMPOUND_STRING("Partner will use:\n"));
|
||||
u32 move = gBattleMons[B_POSITION_PLAYER_RIGHT].moves[*(gBattleStruct->chosenMovePositions + B_POSITION_PLAYER_RIGHT)];
|
||||
StringAppend(gStringVar1, gMovesInfo[move].name);
|
||||
if (gMovesInfo[move].target == MOVE_TARGET_SELECTED)
|
||||
StringAppend(gStringVar1, GetMoveName(move));
|
||||
u32 moveTarget = GetBattlerMoveTargetType(B_POSITION_PLAYER_RIGHT, move);
|
||||
if (moveTarget == MOVE_TARGET_SELECTED)
|
||||
{
|
||||
if (gBattleStruct->aiChosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_OPPONENT_LEFT)
|
||||
StringAppend(gStringVar1, COMPOUND_STRING(" -{UP_ARROW}"));
|
||||
@ -2062,15 +2060,15 @@ static void PlayerHandleChooseAction(u32 battler)
|
||||
else if (gBattleStruct->aiChosenTarget[B_POSITION_PLAYER_RIGHT] == B_POSITION_PLAYER_RIGHT)
|
||||
StringAppend(gStringVar1, COMPOUND_STRING(" {DOWN_ARROW}-"));
|
||||
}
|
||||
else if (gMovesInfo[move].target == MOVE_TARGET_BOTH)
|
||||
else if (moveTarget == MOVE_TARGET_BOTH)
|
||||
{
|
||||
StringAppend(gStringVar1, COMPOUND_STRING(" {UP_ARROW}{UP_ARROW}"));
|
||||
}
|
||||
else if (gMovesInfo[move].target == MOVE_TARGET_FOES_AND_ALLY)
|
||||
else if (moveTarget == MOVE_TARGET_FOES_AND_ALLY)
|
||||
{
|
||||
StringAppend(gStringVar1, COMPOUND_STRING(" {V_D_ARROW}{UP_ARROW}"));
|
||||
}
|
||||
else if (gMovesInfo[move].target == MOVE_TARGET_ALL_BATTLERS)
|
||||
else if (moveTarget == MOVE_TARGET_ALL_BATTLERS)
|
||||
{
|
||||
StringAppend(gStringVar1, COMPOUND_STRING(" {V_D_ARROW}{V_D_ARROW}"));
|
||||
}
|
||||
|
||||
@ -353,10 +353,11 @@ static void PlayerPartnerHandleChooseMove(u32 battler)
|
||||
|
||||
chosenMoveId = gBattleStruct->aiMoveOrAction[battler];
|
||||
gBattlerTarget = gBattleStruct->aiChosenTarget[battler];
|
||||
u32 moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveId]);
|
||||
|
||||
if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED))
|
||||
if (moveTarget & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED))
|
||||
gBattlerTarget = battler;
|
||||
else if (gMovesInfo[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH)
|
||||
else if (moveTarget & MOVE_TARGET_BOTH)
|
||||
{
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
||||
if (gAbsentBattlerFlags & (1u << gBattlerTarget))
|
||||
|
||||
@ -1113,7 +1113,7 @@ void BtlController_EmitPrintString(u32 battler, u32 bufferId, u16 stringID)
|
||||
stringInfo->bakScriptPartyIdx = gBattleStruct->scriptPartyIdx;
|
||||
stringInfo->hpScale = gBattleStruct->hpScale;
|
||||
stringInfo->itemEffectBattler = gPotentialItemEffectBattler;
|
||||
stringInfo->moveType = gMovesInfo[gCurrentMove].type;
|
||||
stringInfo->moveType = GetMoveType(gCurrentMove);
|
||||
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
stringInfo->abilities[i] = gBattleMons[i].ability;
|
||||
@ -2542,7 +2542,10 @@ void BtlController_HandleDrawTrainerPic(u32 battler, u32 trainerPicId, bool32 is
|
||||
gSprites[gBattlerSpriteIds[battler]].x2 = DISPLAY_WIDTH;
|
||||
gSprites[gBattlerSpriteIds[battler]].sSpeedX = -2;
|
||||
}
|
||||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCB_TrainerSlideIn;
|
||||
if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless)
|
||||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCB_TrainerSpawn;
|
||||
else
|
||||
gSprites[gBattlerSpriteIds[battler]].callback = SpriteCB_TrainerSlideIn;
|
||||
|
||||
gBattlerControllerFuncs[battler] = Controller_WaitForTrainerPic;
|
||||
}
|
||||
|
||||
@ -1982,7 +1982,7 @@ static u8 *GetSideStatusValue(struct BattleDebugMenu *data, bool32 changeStatus,
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) |= SIDE_STATUS_DAMAGE_NON_TYPES;
|
||||
else
|
||||
*(u32 *)(data->modifyArrows.modifiedValPtr) &= ~SIDE_STATUS_DAMAGE_NON_TYPES;
|
||||
sideTimer->damageNonTypesType = gMovesInfo[gCurrentMove].type;
|
||||
sideTimer->damageNonTypesType = GetMoveType(gCurrentMove);
|
||||
}
|
||||
return &sideTimer->damageNonTypesTimer;
|
||||
case LIST_SIDE_RAINBOW:
|
||||
|
||||
@ -2395,13 +2395,13 @@ static int GetTypeEffectivenessPoints(int move, int targetSpecies, int mode)
|
||||
int defType1, defType2, defAbility, moveType;
|
||||
int typePower = TYPE_x1;
|
||||
|
||||
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || IS_MOVE_STATUS(move))
|
||||
if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || IsBattleMoveStatus(move))
|
||||
return 0;
|
||||
|
||||
defType1 = gSpeciesInfo[targetSpecies].types[0];
|
||||
defType2 = gSpeciesInfo[targetSpecies].types[1];
|
||||
defAbility = gSpeciesInfo[targetSpecies].abilities[0];
|
||||
moveType = gMovesInfo[move].type;
|
||||
moveType = GetMoveType(move);
|
||||
|
||||
if (defAbility == ABILITY_LEVITATE && moveType == TYPE_GROUND)
|
||||
{
|
||||
@ -3890,7 +3890,7 @@ static bool32 IsDomeHealingMove(u32 move)
|
||||
if (IsHealingMove(move))
|
||||
return TRUE;
|
||||
// Check extra effects not considered plain healing by AI
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_INGRAIN:
|
||||
case EFFECT_REFRESH:
|
||||
@ -3949,9 +3949,9 @@ static bool32 IsDomeRiskyMoveEffect(u32 effect)
|
||||
|
||||
static bool32 IsDomeLuckyMove(u32 move)
|
||||
{
|
||||
if (gMovesInfo[move].accuracy <= 50)
|
||||
if (GetMoveAccuracy(move) <= 50)
|
||||
return TRUE;
|
||||
switch(gMovesInfo[move].effect)
|
||||
switch(GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_COUNTER:
|
||||
case EFFECT_OHKO: // Technically redundant because of the above accuracy check
|
||||
@ -3982,10 +3982,10 @@ static bool32 IsDomePopularMove(u32 move)
|
||||
if (i == NUM_TECHNICAL_MACHINES + NUM_HIDDEN_MACHINES)
|
||||
return FALSE;
|
||||
// Filter in TMs/HMs
|
||||
if (gMovesInfo[move].power >= 90)
|
||||
if (GetMovePower(move) >= 90)
|
||||
return TRUE;
|
||||
|
||||
switch(gMovesInfo[move].effect)
|
||||
switch(GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_PROTECT:
|
||||
case EFFECT_MAT_BLOCK:
|
||||
@ -4000,7 +4000,7 @@ static bool32 IsDomePopularMove(u32 move)
|
||||
|
||||
static bool32 IsDomeStatusMoveEffect(u32 move)
|
||||
{
|
||||
switch(gMovesInfo[move].effect)
|
||||
switch(GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_SLEEP:
|
||||
case EFFECT_CONFUSE:
|
||||
@ -4294,24 +4294,26 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
|
||||
{
|
||||
for (k = 0; k < NUM_MOVE_POINT_TYPES; k++)
|
||||
{
|
||||
u16 move;
|
||||
u32 move;
|
||||
if (trainerId == TRAINER_FRONTIER_BRAIN)
|
||||
move = GetFrontierBrainMonMove(i, j);
|
||||
else if (trainerId == TRAINER_PLAYER)
|
||||
move = gSaveBlock2Ptr->frontier.domePlayerPartyData[i].moves[j];
|
||||
else
|
||||
move = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].moves[j];
|
||||
u32 effect = GetMoveEffect(move);
|
||||
u32 accuracy = GetMoveAccuracy(move);
|
||||
|
||||
switch (k)
|
||||
{
|
||||
case MOVE_POINTS_COMBO:
|
||||
allocatedArray[k] = IsDomeComboMoveEffect(gMovesInfo[move].effect) ? 1 : 0;
|
||||
allocatedArray[k] = IsDomeComboMoveEffect(effect) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_STAT_RAISE:
|
||||
allocatedArray[k] = IsStatRaisingEffect(gMovesInfo[move].effect) ? 1 : 0;
|
||||
allocatedArray[k] = IsStatRaisingEffect(effect) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_STAT_LOWER:
|
||||
allocatedArray[k] = IsStatLoweringEffect(gMovesInfo[move].effect) ? 1 : 0;
|
||||
allocatedArray[k] = IsStatLoweringEffect(effect) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_RARE:
|
||||
allocatedArray[k] = IsDomeRareMove(move) ? 1 : 0;
|
||||
@ -4320,22 +4322,22 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
|
||||
allocatedArray[k] = IsDomeHealingMove(move) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_RISKY:
|
||||
allocatedArray[k] = IsDomeRiskyMoveEffect(gMovesInfo[move].effect) ? 1 : 0;
|
||||
allocatedArray[k] = IsDomeRiskyMoveEffect(effect) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_STATUS:
|
||||
allocatedArray[k] = IsDomeStatusMoveEffect(move);
|
||||
break;
|
||||
case MOVE_POINTS_DMG:
|
||||
allocatedArray[k] = (!IS_MOVE_STATUS(move)) ? 1 : 0;
|
||||
allocatedArray[k] = (!IsBattleMoveStatus(move)) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_DEF:
|
||||
allocatedArray[k] = IsDomeDefensiveMoveEffect(gMovesInfo[move].effect) ? 1 : 0;
|
||||
allocatedArray[k] = IsDomeDefensiveMoveEffect(effect) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_ACCURATE:
|
||||
allocatedArray[k] = (gMovesInfo[move].accuracy == 0 || gMovesInfo[move].accuracy == 100) ? 1 : 0;
|
||||
allocatedArray[k] = (accuracy == 0 || accuracy == 100) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_POWERFUL:
|
||||
allocatedArray[k] = (gMovesInfo[move].power >= 100) ? 1 : 0;
|
||||
allocatedArray[k] = (GetMovePower(move) >= 100) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_POPULAR:
|
||||
allocatedArray[k] = IsDomePopularMove(move) ? 1 : 0;
|
||||
@ -4344,10 +4346,10 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
|
||||
allocatedArray[k] = IsDomeLuckyMove(move) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_STRONG:
|
||||
allocatedArray[k] = (gMovesInfo[move].power >= 90) ? 1 : 0;
|
||||
allocatedArray[k] = (GetMovePower(move) >= 90) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_LOW_PP:
|
||||
allocatedArray[k] = (gMovesInfo[move].pp <= 5) ? 1 : 0;
|
||||
allocatedArray[k] = (GetMovePP(move) <= 5) ? 1 : 0;
|
||||
break;
|
||||
case MOVE_POINTS_EFFECT:
|
||||
allocatedArray[k] = MoveIsAffectedBySheerForce(move);
|
||||
@ -5107,12 +5109,12 @@ static u16 GetWinningMove(int winnerTournamentId, int loserTournamentId, u8 roun
|
||||
else
|
||||
moveIds[i * MAX_MON_MOVES + j] = gFacilityTrainerMons[DOME_MONS[winnerTournamentId][i]].moves[j];
|
||||
|
||||
movePower = gMovesInfo[moveIds[i * MAX_MON_MOVES + j]].power;
|
||||
if (IS_MOVE_STATUS(moveIds[i * MAX_MON_MOVES + j]))
|
||||
movePower = GetMovePower(moveIds[i * MAX_MON_MOVES + j]);
|
||||
if (IsBattleMoveStatus(moveIds[i * MAX_MON_MOVES + j]))
|
||||
movePower = 40;
|
||||
else if (movePower == 1)
|
||||
movePower = 60;
|
||||
else if (gMovesInfo[moveIds[i * MAX_MON_MOVES + j]].effect == EFFECT_EXPLOSION)
|
||||
else if (GetMoveEffect(moveIds[i * MAX_MON_MOVES + j]) == EFFECT_EXPLOSION)
|
||||
movePower /= 2;
|
||||
|
||||
for (k = 0; k < FRONTIER_PARTY_SIZE; k++)
|
||||
|
||||
@ -240,7 +240,7 @@ bool32 IsMoveBlockedByMaxGuard(u32 move)
|
||||
bool32 IsMoveBlockedByDynamax(u32 move)
|
||||
{
|
||||
// TODO: Certain moves are banned in raids.
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_HEAT_CRASH:
|
||||
case EFFECT_LOW_KICK:
|
||||
@ -282,7 +282,7 @@ u16 GetMaxMove(u32 battler, u32 baseMove)
|
||||
{
|
||||
u32 moveType;
|
||||
SetTypeBeforeUsingMove(baseMove, battler);
|
||||
moveType = GetMoveType(baseMove);
|
||||
moveType = GetBattleMoveType(baseMove);
|
||||
|
||||
if (baseMove == MOVE_NONE) // for move display
|
||||
{
|
||||
@ -292,7 +292,7 @@ u16 GetMaxMove(u32 battler, u32 baseMove)
|
||||
{
|
||||
return MOVE_STRUGGLE;
|
||||
}
|
||||
else if (gMovesInfo[baseMove].category == DAMAGE_CATEGORY_STATUS)
|
||||
else if (GetMoveCategory(baseMove) == DAMAGE_CATEGORY_STATUS)
|
||||
{
|
||||
return MOVE_MAX_GUARD;
|
||||
}
|
||||
@ -320,7 +320,7 @@ u8 GetMaxMovePower(u32 move)
|
||||
{
|
||||
u8 tier;
|
||||
// G-Max Drum Solo, G-Max Hydrosnipe, and G-Max Fireball always have 160 base power.
|
||||
if (gMovesInfo[GetMaxMove(gBattlerAttacker, move)].argument == MAX_EFFECT_FIXED_POWER)
|
||||
if (GetMoveMaxEffect(GetMaxMove(gBattlerAttacker, move)) == MAX_EFFECT_FIXED_POWER)
|
||||
return 160;
|
||||
|
||||
// Exceptions to all other rules below:
|
||||
@ -333,8 +333,9 @@ u8 GetMaxMovePower(u32 move)
|
||||
}
|
||||
|
||||
tier = GetMaxPowerTier(move);
|
||||
if (gMovesInfo[move].type == TYPE_FIGHTING
|
||||
|| gMovesInfo[move].type == TYPE_POISON
|
||||
u32 moveType = GetMoveType(move);
|
||||
if (moveType == TYPE_FIGHTING
|
||||
|| moveType == TYPE_POISON
|
||||
|| move == MOVE_MULTI_ATTACK)
|
||||
{
|
||||
switch (tier)
|
||||
@ -369,9 +370,10 @@ u8 GetMaxMovePower(u32 move)
|
||||
|
||||
static u8 GetMaxPowerTier(u32 move)
|
||||
{
|
||||
if (gMovesInfo[move].strikeCount >= 2 && gMovesInfo[move].strikeCount <= 5)
|
||||
u32 strikeCount = GetMoveStrikeCount(move);
|
||||
if (strikeCount >= 2 && strikeCount <= 5)
|
||||
{
|
||||
switch(gMovesInfo[move].power)
|
||||
switch(GetMovePower(move))
|
||||
{
|
||||
case 0 ... 25: return MAX_POWER_TIER_2;
|
||||
case 26 ... 30: return MAX_POWER_TIER_3;
|
||||
@ -382,7 +384,7 @@ static u8 GetMaxPowerTier(u32 move)
|
||||
}
|
||||
}
|
||||
|
||||
switch (gMovesInfo[move].effect)
|
||||
switch (GetMoveEffect(move))
|
||||
{
|
||||
case EFFECT_BIDE:
|
||||
case EFFECT_SUPER_FANG:
|
||||
@ -418,7 +420,7 @@ static u8 GetMaxPowerTier(u32 move)
|
||||
case EFFECT_LOW_KICK:
|
||||
return MAX_POWER_TIER_7;
|
||||
case EFFECT_MULTI_HIT:
|
||||
switch(gMovesInfo[move].power)
|
||||
switch(GetMovePower(move))
|
||||
{
|
||||
case 0 ... 15: return MAX_POWER_TIER_1;
|
||||
case 16 ... 18: return MAX_POWER_TIER_2;
|
||||
@ -428,7 +430,7 @@ static u8 GetMaxPowerTier(u32 move)
|
||||
}
|
||||
}
|
||||
|
||||
switch (gMovesInfo[move].power)
|
||||
switch (GetMovePower(move))
|
||||
{
|
||||
case 0 ... 40: return MAX_POWER_TIER_1;
|
||||
case 45 ... 50: return MAX_POWER_TIER_2;
|
||||
@ -470,7 +472,7 @@ void ChooseDamageNonTypesString(u8 type)
|
||||
// Returns the status effect that should be applied by a G-Max Move.
|
||||
static u32 GetMaxMoveStatusEffect(u32 move)
|
||||
{
|
||||
u8 maxEffect = gMovesInfo[move].argument;
|
||||
u8 maxEffect = GetMoveMaxEffect(move);
|
||||
switch (maxEffect)
|
||||
{
|
||||
// Status 1
|
||||
@ -522,7 +524,7 @@ void BS_SetMaxMoveEffect(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
u16 effect = 0;
|
||||
u8 maxEffect = gMovesInfo[gCurrentMove].argument;
|
||||
u8 maxEffect = GetMoveMaxEffect(gCurrentMove);
|
||||
|
||||
// Don't continue if the move didn't land.
|
||||
if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
@ -541,7 +543,7 @@ void BS_SetMaxMoveEffect(void)
|
||||
if (!NoAliveMonsForEitherParty())
|
||||
{
|
||||
// Max Effects are ordered by stat ID.
|
||||
SET_STATCHANGER(gMovesInfo[gCurrentMove].argument, 1, FALSE);
|
||||
SET_STATCHANGER(maxEffect, 1, FALSE);
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies;
|
||||
effect++;
|
||||
@ -569,7 +571,7 @@ void BS_SetMaxMoveEffect(void)
|
||||
break;
|
||||
default:
|
||||
// Max Effects are ordered by stat ID.
|
||||
statId = gMovesInfo[gCurrentMove].argument - MAX_EFFECT_LOWER_ATTACK + 1;
|
||||
statId = maxEffect - MAX_EFFECT_LOWER_ATTACK + 1;
|
||||
break;
|
||||
}
|
||||
SET_STATCHANGER(statId, stage, TRUE);
|
||||
@ -618,7 +620,7 @@ void BS_SetMaxMoveEffect(void)
|
||||
case MAX_EFFECT_PSYCHIC_TERRAIN:
|
||||
{
|
||||
u32 statusFlag = 0;
|
||||
switch (gMovesInfo[gCurrentMove].argument)
|
||||
switch (GetMoveEffectArg_MoveProperty(gCurrentMove))
|
||||
{
|
||||
case MAX_EFFECT_MISTY_TERRAIN:
|
||||
statusFlag = STATUS_FIELD_MISTY_TERRAIN;
|
||||
@ -659,11 +661,12 @@ void BS_SetMaxMoveEffect(void)
|
||||
u8 side = GetBattlerSide(gBattlerTarget);
|
||||
if (!(gSideStatuses[side] & SIDE_STATUS_DAMAGE_NON_TYPES))
|
||||
{
|
||||
u32 moveType = GetMoveType(gCurrentMove);
|
||||
gSideStatuses[side] |= SIDE_STATUS_DAMAGE_NON_TYPES;
|
||||
gSideTimers[side].damageNonTypesTimer = 5; // damage is dealt for 4 turns, ends on 5th
|
||||
gSideTimers[side].damageNonTypesType = gMovesInfo[gCurrentMove].type;
|
||||
gSideTimers[side].damageNonTypesType = moveType;
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
ChooseDamageNonTypesString(gMovesInfo[gCurrentMove].type);
|
||||
ChooseDamageNonTypesString(moveType);
|
||||
gBattlescriptCurrInstr = BattleScript_DamageNonTypesStarts;
|
||||
effect++;
|
||||
}
|
||||
|
||||