diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 0a3eff0e43d2..88c5cabd28a0 100644 --- a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml +++ b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml index 4b8eec3a437f..e49c54e756ba 100644 --- a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml +++ b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index 54335ca5e40a..02bc0399b199 100644 --- a/.github/ISSUE_TEMPLATE/04_other_errors.yaml +++ b/.github/ISSUE_TEMPLATE/04_other_errors.yaml @@ -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 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index f083a2a23f65..9a04e86f2bf7 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,11 +1,12 @@ - + ## Description + ## Images diff --git a/CHANGELOG.md b/CHANGELOG.md index 13d6e4f4ebd0..963e05d7bcc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Makefile b/Makefile index 3548aa8cc94a..2631e22192fb 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,9 @@ HEADLESSELF = $(ROM_NAME:.gba=-test-headless.elf) # Pick our active variables ROM := $(ROM_NAME) +ifeq ($(TESTELF),$(MAKECMDGOALS)) + TEST := 1 +endif ifeq ($(TEST), 0) OBJ_DIR := $(OBJ_DIR_NAME) else @@ -80,9 +83,6 @@ endif ifeq ($(DEBUG),1) OBJ_DIR := $(OBJ_DIR_NAME_DEBUG) endif -ifeq ($(TESTELF),$(MAKECMDGOALS)) - TEST := 1 -endif ELF := $(ROM:.gba=.elf) MAP := $(ROM:.gba=.map) SYM := $(ROM:.gba=.sym) @@ -177,7 +177,7 @@ MAKEFLAGS += --no-print-directory # Delete files that weren't built properly .DELETE_ON_ERROR: -RULES_NO_SCAN += libagbsyscall clean clean-assets tidy tidymodern tidycheck generated clean-generated $(TESTELF) +RULES_NO_SCAN += libagbsyscall clean clean-assets tidy tidymodern tidycheck generated clean-generated .PHONY: all rom agbcc modern compare check debug .PHONY: $(RULES_NO_SCAN) @@ -351,6 +351,8 @@ $(C_BUILDDIR)/pokedex_plus_hgss.o: CFLAGS := -mthumb -mthumb-interwork -O2 -mabi # 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. @@ -425,8 +427,8 @@ $(OBJ_DIR)/sym_common.ld: sym_common.txt $(C_OBJS) $(wildcard common_syms/*.txt) $(OBJ_DIR)/sym_ewram.ld: sym_ewram.txt $(RAMSCRGEN) ewram_data $< ENGLISH > $@ -# NOTE: Depending on event_scripts.o is hacky, but we want to depend on everything event_scripts.s depends on without having to alter scaninc -$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(DATA_ASM_BUILDDIR)/event_scripts.o +TEACHABLE_DEPS := $(shell find data/ -type f -name '*.inc') $(INCLUDE_DIRS)/constants/tms_hms.h $(C_SUBDIR)/pokemon.c +$(DATA_SRC_SUBDIR)/pokemon/teachable_learnsets.h: $(TEACHABLE_DEPS) python3 $(TOOLS_DIR)/learnset_helpers/teachable.py # Linker script diff --git a/README.md b/README.md index 277dae2be785..70317fac5c05 100644 --- a/README.md +++ b/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. diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 48920a04a2c1..d748135e3c30 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -478,9 +478,10 @@ .byte \battler .endm - .macro switchinanim battler:req, dontClearSubstitute:req + .macro switchinanim battler:req, dontClearTransform:req, dontClearSubstitute:req .byte 0x4e .byte \battler + .byte \dontClearTransform .byte \dontClearSubstitute .endm @@ -1520,8 +1521,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 @@ -2337,11 +2338,11 @@ .endm .macro swapsidestatuses - various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES + callnative BS_CourtChangeSwapSideStatuses .endm .macro swapstats stat:req - various BS_ATTACKER, VARIOUS_SWAP_STATS + callnative BS_SwapStats .byte \stat .endm diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 1a0177970257..b9c5d875b3eb 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -251,15 +251,26 @@ .endm @ Calls the native C function stored at func. - .macro callnative func:req + @ 'callnative's should set 'requests_effects=1' if the native + @ contains a call to 'Script_RequestEffects', which allows them + @ to be analyzed by 'RunScriptImmediatelyUntilEffect'. + .macro callnative func:req, requests_effects=0 .byte 0x23 + .if \requests_effects == 0 .4byte \func + .else + .4byte \func + ROM_SIZE + .endif .endm @ Replaces the script with the function stored at func. Execution returns to the bytecode script when func returns TRUE. - .macro gotonative func:req + .macro gotonative func:req, requests_effects=0 .byte 0x24 + .if \requests_effects == 0 .4byte \func + .else + .4byte \func + ROM_SIZE + .endif .endm @ Calls a function listed in the table in data/specials.inc. @@ -996,10 +1007,10 @@ @ Gives the player a Pokémon of the specified species and level, and allows to customize extra parameters. @ VAR_RESULT will be set to MON_GIVEN_TO_PARTY, MON_GIVEN_TO_PC, or MON_CANT_GIVE depending on the outcome. - .macro givemon species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, ggMaxFactor, teraType - callnative ScrCmd_createmon + .macro givemon species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, gmaxFactor, teraType, dmaxLevel + callnative ScrCmd_createmon, requests_effects=1 .byte 0 - .byte 6 @ PARTY_SIZE - assign to first empty slot + .byte PARTY_SIZE @ assign to first empty slot .set givemon_flags, 0 .2byte \species .2byte \level @@ -1025,8 +1036,9 @@ .ifnb \move3; .set givemon_flags, givemon_flags | (1 << 19); .endif .ifnb \move4; .set givemon_flags, givemon_flags | (1 << 20); .endif .ifnb \isShiny; .set givemon_flags, givemon_flags | (1 << 21); .endif - .ifnb \ggMaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif + .ifnb \gmaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif .ifnb \teraType; .set givemon_flags, givemon_flags | (1 << 23); .endif + .ifnb \dmaxLevel; .set givemon_flags, givemon_flags | (1 << 24); .endif .4byte givemon_flags .ifnb \item; .2byte \item; .endif .ifnb \ball; .2byte \ball; .endif @@ -1050,14 +1062,15 @@ .ifnb \move3; .2byte \move3; .endif .ifnb \move4; .2byte \move4; .endif .ifnb \isShiny; .2byte \isShiny; .endif - .ifnb \ggMaxFactor; .2byte \ggMaxFactor; .endif + .ifnb \gmaxFactor; .2byte \gmaxFactor; .endif .ifnb \teraType; .2byte \teraType; .endif + .ifnb \dmaxLevel; .2byte \dmaxLevel; .endif .endm @ creates a mon for a given party and slot @ otherwise - .macro createmon side:req, slot:req, species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, ggMaxFactor, teraType - callnative ScrCmd_createmon + .macro createmon side:req, slot:req, species:req, level:req, item, ball, nature, abilityNum, gender, hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv, hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv, move1, move2, move3, move4, isShiny, gmaxFactor, teraType, dmaxLevel + callnative ScrCmd_createmon, requests_effects=1 .byte \side @ 0 - player, 1 - opponent .byte \slot @ 0-5 .set givemon_flags, 0 @@ -1085,8 +1098,9 @@ .ifnb \move3; .set givemon_flags, givemon_flags | (1 << 19); .endif .ifnb \move4; .set givemon_flags, givemon_flags | (1 << 20); .endif .ifnb \isShiny; .set givemon_flags, givemon_flags | (1 << 21); .endif - .ifnb \ggMaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif + .ifnb \gmaxFactor; .set givemon_flags, givemon_flags | (1 << 22); .endif .ifnb \teraType; .set givemon_flags, givemon_flags | (1 << 23); .endif + .ifnb \dmaxLevel; .set givemon_flags, givemon_flags | (1 << 24); .endif .4byte givemon_flags .ifnb \item; .2byte \item; .endif .ifnb \ball; .2byte \ball; .endif @@ -1110,8 +1124,9 @@ .ifnb \move3; .2byte \move3; .endif .ifnb \move4; .2byte \move4; .endif .ifnb \isShiny; .2byte \isShiny; .endif - .ifnb \ggMaxFactor; .2byte \ggMaxFactor; .endif + .ifnb \gmaxFactor; .2byte \gmaxFactor; .endif .ifnb \teraType; .2byte \teraType; .endif + .ifnb \dmaxLevel; .2byte \dmaxLevel; .endif .endm @ Gives the player an Egg of the specified species. @@ -2103,7 +2118,7 @@ .endm .macro setdynamicaifunc func:req - callnative ScriptSetDynamicAiFunc + callnative ScriptSetDynamicAiFunc, requests_effects=1 .4byte \func .endm @@ -2112,7 +2127,7 @@ @ The rest of the arguments are the stat change values to each stat. @ For example, giving the first opponent +1 to atk and -2 to speed would be: settotemboost B_POSITION_OPPONENT_LEFT, 1, 0, -2 .macro settotemboost battler:req, atk=0,def=0,speed=0,spatk=0,spdef=0,acc=0,evas=0 - callnative ScriptSetTotemBoost + callnative ScriptSetTotemBoost, requests_effects=1 .2byte \battler .2byte \atk .2byte \def @@ -2183,21 +2198,21 @@ .macro ai_vs_ai_battle trainer1:req, trainer2:req setflag B_FLAG_AI_VS_AI_BATTLE setvar VAR_0x8004, \trainer1 - callnative CreateTrainerPartyForPlayer + callnative CreateTrainerPartyForPlayer, requests_effects=1 trainerbattle_no_intro \trainer2, NULL .endm @ Sets VAR_RESULT to TRUE if stat can be hyper trained, or to @ FALSE otherwise. .macro canhypertrain stat:req, slot:req - callnative CanHyperTrain + callnative CanHyperTrain, requests_effects=1 .byte \stat .2byte \slot .endm @ Hyper Trains a stat. .macro hypertrain stat:req, slot:req - callnative HyperTrain + callnative HyperTrain, requests_effects=1 .byte \stat .2byte \slot .endm @@ -2205,7 +2220,7 @@ @ Sets VAR_RESULT to TRUE if the Pokemon has the Gigantamax Factor, @ or to FALSE otherwise. .macro hasgigantamaxfactor slot:req - callnative HasGigantamaxFactor + callnative HasGigantamaxFactor, requests_effects=1 .2byte \slot .endm @@ -2213,7 +2228,7 @@ @ Fails for Melmetal (vanilla behavior). @ Sets VAR_RESULT to TRUE if it succeeds, and FALSE otherwise. .macro togglegigantamaxfactor slot:req - callnative ToggleGigantamaxFactor + callnative ToggleGigantamaxFactor, requests_effects=1 .2byte \slot .endm @@ -2251,27 +2266,27 @@ @ Inflicts \status1 to the Pokémon in \slot. @ If \slot is greater or equal than PARTY_SIZE, the status is inflicted on each of the Player's Pokémon. .macro setstatus1 status1:req, slot:req - callnative Script_SetStatus1 + callnative Script_SetStatus1, requests_effects=1 .2byte \status1 .2byte \slot .endm @ Sets VAR_RESULT to the Pokémon in \slot's Tera Type .macro checkteratype slot:req - callnative CheckTeraType + callnative CheckTeraType, requests_effects=1 .2byte \slot .endm @ Sets the Pokémon in \slot's Tera Type .macro setteratype type:req, slot:req - callnative SetTeraType + callnative SetTeraType, requests_effects=1 .byte \type .2byte \slot .endm @ Saves species and forms of Daycare Pokémon to specific vars. Saves the amount of Daycare mon to VAR_RESULT. .macro getdaycaregfx varSpecies1:req varSpecies2:req varForm1:req varForm2:req - callnative GetDaycareGraphics + callnative GetDaycareGraphics, requests_effects=1 .2byte \varSpecies1 .2byte \varSpecies2 .2byte \varForm1 @@ -2280,12 +2295,12 @@ @ Plays the cry of the first alive party member. .macro playfirstmoncry - callnative PlayFirstMonCry + callnative PlayFirstMonCry, requests_effects=1 .endm @ Buffers the nickname of the first alive party member. .macro bufferlivemonnickname out:req - callnative BufferFirstLiveMonNickname + callnative BufferFirstLiveMonNickname, requests_effects=1 .byte \out .endm @@ -2296,13 +2311,13 @@ @ Checks if Field move is being used by the current follower. .macro isfollowerfieldmoveuser var:req - callnative IsFollowerFieldMoveUser + callnative IsFollowerFieldMoveUser, requests_effects=1 .2byte \var .endm @ Saves the direction from where source object event would need to turn to to face the target into the specified var. .macro getdirectiontoface var:req, sourceId:req, targetId:req - callnative GetDirectionToFaceScript + callnative GetDirectionToFaceScript, requests_effects=1 .2byte \var .byte \sourceId .byte \targetId @@ -2311,50 +2326,50 @@ @ set the wild double battle flag @ can be used in conjunection with createmon to set up a wild battle with 2 player mons vs. 1 enemy mon .macro setwilddoubleflag - callnative ScriptSetDoubleBattleFlag + callnative ScriptSetDoubleBattleFlag, requests_effects=1 .endm @ When OW_USE_FAKE_RTC and OW_FLAG_PAUSE_TIME is assigned, this macro will stop the flow of time. .macro pausefakertc - callnative Script_PauseFakeRtc + callnative Script_PauseFakeRtc, requests_effects=1 .endm @ When OW_USE_FAKE_RTC and OW_FLAG_PAUSE_TIME is assigned, this macro will resume the flow of time. .macro resumefakertc - callnative Script_ResumeFakeRtc + callnative Script_ResumeFakeRtc, requests_effects=1 .endm @ When OW_USE_FAKE_RTC and OW_FLAG_PAUSE_TIME is assigned, this macro will resume the flow of time if paused, and stop the flow of time otherwise. .macro togglefakertc - callnative Script_ToggleFakeRtc + callnative Script_ToggleFakeRtc, requests_effects=1 .endm @ ============================ @ @ ITEM DESCRIPTION HEADER MACROS @ Used with OW_SHOW_ITEM_DESCRIPTIONS config .macro showitemdescription - callnative ScriptShowItemDescription + callnative ScriptShowItemDescription, requests_effects=1 .byte 0 .endm .macro showberrydescription - callnative ScriptShowItemDescription + callnative ScriptShowItemDescription, requests_effects=1 .byte 1 .endm .macro hideitemdescription - callnative ScriptHideItemDescription + callnative ScriptHideItemDescription, requests_effects=1 .endm @ Remove all of specified item from the player's bag and return the number of removed items to VAR_RESULT .macro removeallitem itemId:req - callnative ScrCmd_removeallitem + callnative ScrCmd_removeallitem, requests_effects=1 .2byte \itemId .endm @ Stores the position of the given object in destX and destY. Mode CURRENT_POSITION will take the object's current position. Mode TEMPLATE_POSITION will take the object's template position. .macro getobjectxy localId:req, posType:req, destX:req, destY:req - callnative ScrCmd_getobjectxy + callnative ScrCmd_getobjectxy, request_effects=1 .2byte \localId .2byte \posType .2byte \destX @@ -2362,7 +2377,7 @@ .endm .macro getobjecttemplatexy localId:req, posType = TEMPLATE_POSITION, destX:req, destY:req - callnative ScrCmd_getobjectxy + callnative ScrCmd_getobjectxy, request_effects=1 .2byte \localId .2byte \posType .2byte \destX @@ -2370,7 +2385,7 @@ .endm .macro getobjectcurrentxy localId:req, posType = CURRENT_POSITION, destX:req, destY:req - callnative ScrCmd_getobjectxy + callnative ScrCmd_getobjectxy, request_effects=1 .2byte \localId .2byte \posType .2byte \destX @@ -2379,7 +2394,7 @@ @ Return TRUE to dest if there is an object at the position x and y. .macro checkobjectat x:req, y:req, dest = VAR_RESULT - callnative ScrCmd_checkobjectat + callnative ScrCmd_checkobjectat, request_effects=1 .2byte \x .2byte \y .2byte \dest @@ -2387,28 +2402,28 @@ @ Returns the state of the Pokedex Seen Flag to VAR_RESULT for the Pokemon with speciesId .macro getseenmon species:req - callnative Scrcmd_getsetpokedexflag + callnative Scrcmd_getsetpokedexflag, request_effects=1 .2byte \species .2byte FLAG_GET_SEEN .endm @ Returns the state of the Pokedex Caught Flag to VAR_RESULT for the Pokemon with speciesId .macro getcaughtmon species:req - callnative Scrcmd_getsetpokedexflag + callnative Scrcmd_getsetpokedexflag, request_effects=1 .2byte \species .2byte FLAG_GET_CAUGHT .endm @ Sets the Pokedex Seen Flag for the Pokemon with speciesId .macro setseenmon species:req - callnative Scrcmd_getsetpokedexflag + callnative Scrcmd_getsetpokedexflag, request_effects=1 .2byte \species .2byte FLAG_SET_SEEN .endm @ Sets the Pokedex Caught Flag for the Pokemon with speciesId .macro setcaughtmon species:req - callnative Scrcmd_getsetpokedexflag + callnative Scrcmd_getsetpokedexflag, request_effects=1 .2byte \species .2byte FLAG_SET_CAUGHT .endm @@ -2418,10 +2433,10 @@ .if \mode == OPEN_PARTY_SCREEN special ChoosePartyMon waitstate - callnative Scrcmd_checkspecies_choose + callnative Scrcmd_checkspecies_choose, request_effects=1 .2byte \speciesId .else - callnative Scrcmd_checkspecies + callnative Scrcmd_checkspecies, request_effects=1 .2byte \speciesId .endif .endm @@ -2432,8 +2447,85 @@ @ Gets the facing direction of a given event object and stores it in the variable dest. .macro getobjectfacingdirection localId:req, dest:req - callnative Scrcmd_getobjectfacingdirection + callnative Scrcmd_getobjectfacingdirection, request_effects=1 .2byte \localId .2byte \dest .endm + .macro increasedifficulty + callnative Script_IncreaseDifficulty, requests_effects=1 + .endm + + .macro decreasedifficulty + callnative Script_DecreaseDifficulty, requests_effects=1 + .endm + + .macro getdifficulty var:req + callnative Script_GetDifficulty, requests_effects=1 + .endm + + .macro setdifficulty difficulty:req + callnative Script_SetDifficulty, requests_effects=1 + .byte \difficulty + .endm + + @ Makes the trainer unable to see the player if executed. + @ This is a no-op if the player interacts with the trainer. + .macro cant_see_if, condition:req + callnative Script_EndTrainerCanSeeIf, requests_effects=1 + .byte \condition + .endm + + .macro cant_see + cant_see_if_unset 0 @ flag 0 is always FALSE. + .endm + + .macro cant_see_if_unset, flag:req + checkflag \flag + cant_see_if FALSE + .endm + + .macro cant_see_if_set, flag:req + checkflag \flag + cant_see_if TRUE + .endm + + .macro cant_see_if_trainerflag_unset, trainer:req + checktrainerflag \trainer + cant_see_if FALSE + .endm + + .macro cant_see_if_trainerflag_set, trainer:req + checktrainerflag \trainer + cant_see_if TRUE + .endm + + .macro cant_see_if_lt, a:req, b:req + compare \a, \b + cant_see_if 0 + .endm + + .macro cant_see_if_eq, a:req, b:req + compare \a, \b + cant_see_if 1 + .endm + + .macro cant_see_if_gt, a:req, b:req + compare \a, \b + cant_see_if 2 + .endm + + .macro cant_see_if_le, a:req, b:req + compare \a, \b + cant_see_if 3 + .endm + + .macro cant_see_if_ge, a:req, b:req + compare \a, \b + cant_see_if 4 + .endm + + .macro cant_see_if_ne, a:req, b:req + compare \a, \b + cant_see_if 5 + .endm diff --git a/constants/gba_constants.inc b/constants/gba_constants.inc index 9f51b0f02b02..febb1244d043 100644 --- a/constants/gba_constants.inc +++ b/constants/gba_constants.inc @@ -29,6 +29,9 @@ .set OAM, 0x7000000 + .set ROM, 0x8000000 + .set ROM_SIZE, 0x2000000 + .set SOUND_INFO_PTR, 0x3007FF0 .set INTR_CHECK, 0x3007FF8 .set INTR_VECTOR, 0x3007FFC diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index e2b76524a876..b5f83b2d2309 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -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 @@ -668,22 +661,22 @@ gBattleAnimMove_LuckyChant:: monbg ANIM_DEF_PARTNER setalpha 12, 8 playsewithpan SE_M_PETAL_DANCE, SOUND_PAN_ATTACKER - createsprite gLuckyChantBigStarsSpriteTemplate, 2, 4, 0, -18, 8, 140 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, 16, -18, 8, 100 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, -16, -18, 8, 100 + createsprite gLuckyChantBigStarsSpriteTemplate, ANIM_ATTACKER, 2, 0, -18, 8, 140 + createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 16, -18, 8, 100 + createsprite gLuckyChantSmallStarsSpriteTemplate, 2, -16, -18, 8, 100 delay 15 - createsprite gLuckyChantBigStarsSpriteTemplate 2, 4, 0, -18, 8, 140 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, 32, -18, 8, 100 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, -32, -18, 8, 100 + createsprite gLuckyChantBigStarsSpriteTemplate ANIM_ATTACKER, 2, 0, -18, 8, 140 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, 32, -18, 8, 100 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, -32, -18, 8, 100 delay 15 - createsprite gLuckyChantBigStarsSpriteTemplate 2, 4, 0, -18, 8, 140 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, 24, -18, 8, 100 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, -18, -18, 8, 100 + createsprite gLuckyChantBigStarsSpriteTemplate ANIM_ATTACKER, 2, 0, -18, 8, 140 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, 24, -18, 8, 100 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, -18, -18, 8, 100 delay 30 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, 16, -18, 0, 100 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, -16, -18, 0, 100 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, 16, -18, 0, 100 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, -16, -18, 0, 100 delay 30 - createsprite gLuckyChantSmallStarsSpriteTemplate, 2, 4, 20, -16, 14, 80 + createsprite gLuckyChantSmallStarsSpriteTemplate, ANIM_ATTACKER, 2, 20, -16, 14, 80 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER blendoff @@ -831,7 +824,7 @@ gBattleAnimMove_Punishment:: monbg ANIM_TARGET setalpha 12, 8 playsewithpan 155, SOUND_PAN_TARGET - createsprite gPunishmentSpriteTemplate, 2, 4, 0, 0, 1, 0 + createsprite gPunishmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 0 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 6, 1 waitforvisualfinish clearmonbg ANIM_TARGET @@ -841,7 +834,7 @@ gBattleAnimMove_Punishment:: monbg ANIM_TARGET setalpha 12, 8 playsewithpan SE_M_DOUBLE_SLAP, SOUND_PAN_TARGET - createsprite gPunishmentImpactSpriteTemplate 2, 4, 0, 0, 1, 2 + createsprite gPunishmentImpactSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 6, 1 waitforvisualfinish clearmonbg ANIM_TARGET @@ -855,33 +848,33 @@ gBattleAnimMove_LastResort:: waitbgfadein loadspritegfx ANIM_TAG_IMPACT playsewithpan SE_M_SWIFT, SOUND_PAN_ATTACKER - createsprite gComplexPaletteBlendSpriteTemplate, 2, 7, 2, 4, 2, RGB_WHITE, 10, 0, 0 + createsprite gComplexPaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 2, 4, 2, RGB_WHITE, 10, 0, 0 waitforvisualfinish delay 10 playsewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER waitplaysewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER, 8 createvisualtask AnimTask_TranslateMonEllipticalRespectSide, 2, ANIM_ATTACKER, 18, 6, 2, 4 waitforvisualfinish - createsprite gSimplePaletteBlendSpriteTemplate, 2, 5, 1, 0, 16, 16, RGB_WHITE - createsprite gSlideMonToOffsetSpriteTemplate, 2, 5, 0, 20, 0, 0, 4 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_TARGET, 2, 1, 0, 16, 16, RGB_WHITE + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 0, 20, 0, 0, 4 delay 3 waitforvisualfinish playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, 132, 4, -10, 0, 1, 0 - createsprite gSlideMonToOffsetSpriteTemplate, 2, 5, 1, -32, 0, 0, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 132, -10, 0, 1, 0 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 1, -32, 0, 0, 3 waitforvisualfinish - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 4, 8, -256, ANIM_ATTACKER, 0 - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 4, 8, -256, ANIM_TARGET, 0 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_ATTACKER, 0 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_TARGET, 0 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_ATTACKER, 4, 0, 12, 1 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 4, 0, 12, 1 - createsprite gSimplePaletteBlendSpriteTemplate, 2, 5, 1, 2, 16, 0, RGB_WHITE + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_TARGET, 2, 1, 2, 16, 0, RGB_WHITE waitforvisualfinish - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 4, 8, -256, ANIM_ATTACKER, 1 - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 4, 8, -256, ANIM_TARGET, 1 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_ATTACKER, 1 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 8, -256, ANIM_TARGET, 1 waitforvisualfinish - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 0, 0, 5 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 5 delay 3 - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 1, 0, 7 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 2, 1, 0, 7 waitforvisualfinish call UnsetHighSpeedBg end @@ -903,14 +896,14 @@ gBattleAnimMove_WorrySeed:: gBattleAnimMove_SuckerPunch:: loadspritegfx ANIM_TAG_POISON_JAB loadspritegfx ANIM_TAG_IMPACT - createsprite gSlideMonToOffsetSpriteTemplate, 2, 5, 0, 20, 0, 0, 4 - createsprite gSuckerPunchSpriteTemplate, 130, 6, -18, 5, 40, 8, 160, 0 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 20, 0, 0, 4 + createsprite gSuckerPunchSpriteTemplate, ANIM_TARGET, 130, -18, 5, 40, 8, 160, 0 delay 4 - createsprite gBasicHitSplatSpriteTemplate, 130, 4, -8, 8, 1, 2 - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 4, 6, 384, ANIM_TARGET, 2 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 2 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 6, 384, ANIM_TARGET, 2 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET waitforvisualfinish - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 0, 1, 4 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 0, 1, 4 end gBattleAnimMove_ToxicSpikes:: @@ -986,28 +979,28 @@ gBattleAnimGeneral_AquaRingHeal:: createvisualtask AnimTask_ShakeMon, 5, ANIM_ATTACKER, 0, 2, 23, 1 delay 5 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 10, 10, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 10, 10, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, -15, 0, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, -15, 0, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 20, 10, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 20, 10, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 0, -10, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 0, -10, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, -10, 15, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, -10, 15, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 25, 20, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 25, 20, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, -20, 20, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, -20, 20, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 12, 0, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 12, 0, 25, 0 setalpha 8, 8 playsewithpan SE_M_MILK_DRINK, SOUND_PAN_ATTACKER createsprite gGuardRingSpriteTemplate, 2, 0 @@ -1017,7 +1010,7 @@ gBattleAnimGeneral_AquaRingHeal:: createsprite gGuardRingSpriteTemplate, 2, 0 waitforvisualfinish playsewithpan SE_SHINY, SOUND_PAN_ATTACKER - createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_ATK_SIDE, 0, 2, 10, RGB_WHITE + createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_ATK_SIDE, 0, 2, 0, 10, RGB_WHITE waitforvisualfinish clearmonbg ANIM_ATK_PARTNER blendoff @@ -1027,7 +1020,7 @@ gBattleAnimMove_MagnetRise:: loadspritegfx ANIM_TAG_IMPACT loadspritegfx ANIM_TAG_SPARK_2 delay 0 - createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), -31, 1, 5, 5, RGB(31, 31, 20) + createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), 0, 1, 5, 5, RGB(31, 31, 20) playsewithpan SE_M_THUNDERBOLT2, SOUND_PAN_ATTACKER createvisualtask AnimTask_WindUpLunge, 5, ANIM_ATTACKER, -12, 4, 10, 10, 12, 6 createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, ANIM_ATTACKER, 1, 0 @@ -1052,11 +1045,11 @@ gBattleAnimMove_MagnetRise:: delay 0 createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 238, 24, 165, 10, ANIM_ATTACKER, 1, 1 delay 0 - createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), -31, 1, 0, 0, RGB(31, 31, 20) + createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), 0, 1, 0, 0, RGB(31, 31, 20) delay 20 - createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), -31, 1, 7, 7, RGB(31, 31, 20) + createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), 0, 1, 7, 7, RGB(31, 31, 20) waitforvisualfinish - createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), -31, 1, 0, 0, RGB(31, 31, 20) + createvisualtask AnimTask_BlendColorCycle, 2, (F_PAL_BG | F_PAL_BATTLERS), 0, 1, 0, 0, RGB(31, 31, 20) waitforvisualfinish end @@ -1097,33 +1090,33 @@ gBattleAnimMove_FlareBlitz:: createvisualtask AnimTask_ShakeMon2, 2, ANIM_TARGET, 4, 0, 22, 1 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 0, 0, 1, 0 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, 192, 176, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 192, 176, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 24, 8, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, -192, 240, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, -192, 240, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, -24, -16, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, 192, -160, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 192, -160, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 8, 4, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, -192, -112, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, -192, -112, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, -16, 19, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, 160, 48, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 160, 48, 40 playsewithpan SE_M_COMET_PUNCH, +63 delay 5 createsprite gBasicHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 18, -18, 1, 0 createvisualtask AnimTask_BlendMonInAndOut, 3, ANIM_TARGET, RGB_RED, 12, 1, 1 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, -224, -32, 40 - createsprite gFireSpreadSpriteTemplate, 0x81, 0, 10, 112, -128, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, -224, -32, 40 + createsprite gFireSpreadSpriteTemplate, ANIM_TARGET, 129, 0, 10, 112, -128, 40 playsewithpan SE_M_COMET_PUNCH, +63 createvisualtask AnimTask_BlendBattleAnimPal, 10, 4, 2, 0, 0, RGB_BLACK playsewithpan SE_M_COMET_PUNCH, +63 @@ -1145,10 +1138,10 @@ gBattleAnimMove_ForcePalm:: splitbgprio ANIM_TARGET setalpha 12, 8 playsewithpan SE_M_DOUBLE_TEAM, SOUND_PAN_TARGET - createsprite gKarateChopSpriteTemplate, 2, 8, -16, 0, 0, 0, 10, 1, 3, 0 + createsprite gKarateChopSpriteTemplate, ANIM_TARGET, 2, -16, 0, 0, 0, 10, 1, 3, 0 waitforvisualfinish playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET - createsprite gForcePalmSpriteTemplate 3, 4, 0, 0, 1, 2 + createsprite gForcePalmSpriteTemplate, ANIM_TARGET 3, 0, 0, 1, 2 createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 4, 0, 6, 1 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -1358,45 +1351,45 @@ gBattleAnimMove_AquaTail:: createvisualtask AnimTask_ShakeMon, 5, ANIM_ATTACKER, 0, 2, 23, 1 delay 5 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 10, 10, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 10, 10, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, -16, 0, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, -16, 0, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 20, 10, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 20, 10, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 0, -10, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 0, -10, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, -10, 15, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, -10, 15, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 25, 20, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 25, 20, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, -20, 20, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, -20, 20, 25, 0 delay 4 playsewithpan SE_M_CRABHAMMER, SOUND_PAN_ATTACKER - createsprite gSmallBubblePairSpriteTemplate, 2, 4, 12, 0, 25, 0 + createsprite gSmallBubblePairSpriteTemplate, ANIM_ATTACKER, 2, 12, 0, 25, 0 waitforvisualfinish loadspritegfx ANIM_TAG_SLAM_HIT_2 loadspritegfx ANIM_TAG_IMPACT - createsprite gHorizontalLungeSpriteTemplate, 2, 2, 4, 6 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 4 playsewithpan SE_M_VITAL_THROW, SOUND_PAN_TARGET - createsprite gAquaTailKnockOffSpriteTemplate, 130, 2, -16, -16 + createsprite gAquaTailKnockOffSpriteTemplate, ANIM_ATTACKER, 130, -16, -16 delay 8 - createsprite gComplexPaletteBlendSpriteTemplate, 2, 7, 31, 5, 1, RGB_WHITE, 10, 0, 0 - createsprite gAquaTailHitSpriteTemplate, 131, 4, 0, 0, 1, 2 + createsprite gComplexPaletteBlendSpriteTemplate, ANIM_TARGET, 2, 31, 5, 1, RGB_WHITE, 10, 0, 0 + createsprite gAquaTailHitSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 2 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET - createsprite gSlideMonToOffsetSpriteTemplate, 2, 5, 1, -12, 10, 0, 3 - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 0, 0, 5 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, ANIM_TARGET, -12, 10, 0, 3 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, ANIM_ATTACKER, 0, 5 delay 3 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 0, 3, 6, 1 delay 5 - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 1, 0, 6 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 2, ANIM_TARGET, 0, 6 delay 10 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -1520,7 +1513,7 @@ gBattleAnimMove_DragonPulse:: createsoundtask SoundTask_LoopSEAdjustPanning, SE_M_PSYBEAM2, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 3, 4, 0, 15 call DragonPulseParticle call DragonPulseParticle - createvisualtask AnimTask_SwayMon, 5, 0, 6, 51200, 4, ANIM_TARGET + createvisualtask AnimTask_SwayMon, ANIM_TARGET, 0, 6, 2048, 4, ANIM_TARGET createvisualtask AnimTask_BlendColorCycle, 2, F_PAL_TARGET, 2, 2, 0, 12, RGB(30, 10, 13) call DragonPulseParticle call DragonPulseParticle @@ -1539,7 +1532,7 @@ gBattleAnimMove_DragonPulse:: clearmonbg ANIM_TARGET end DragonPulseParticle: - createsprite gDragonPulseSpriteTemplate, 130, 6, 16, 0, 0, 0, 13, 0 + createsprite gDragonPulseSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 13, 0 delay 4 return @@ -1548,24 +1541,24 @@ gBattleAnimMove_DragonRush:: loadspritegfx ANIM_TAG_IMPACT loadspritegfx ANIM_TAG_ROCKS loadspritegfx ANIM_TAG_RED_HEART - createsprite gHorizontalLungeSpriteTemplate, 2, 2, 4, 6 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 4 playsewithpan SE_M_VITAL_THROW, SOUND_PAN_TARGET - createsprite gDragonRushSpriteTemplate, 131, 2, -16, -16 + createsprite gDragonRushSpriteTemplate, ANIM_ATTACKER, 131, -16, -16 delay 8 - createsprite gComplexPaletteBlendSpriteTemplate, 2, 7, 31, 5, 1, RGB_WHITE, 10, 0, 0 - createsprite gBasicHitSplatSpriteTemplate, 3, 4, 0, 0, 1, 1 - createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 5, 1 + createsprite gComplexPaletteBlendSpriteTemplate, ANIM_TARGET, 2, 31, 5, 1, RGB_WHITE, 10, 0, 0 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 3, 0, 0, 1, 1 + createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 5, 1 waitforvisualfinish playsewithpan 131, SOUND_PAN_TARGET - createsprite gRockFragmentSpriteTemplate, 2, 6, 0, 0, 20, 24, 14, 2 - createsprite gRockFragmentSpriteTemplate, 2, 6, 5, 0, -20, 24, 14, 1 - createsprite gRockFragmentSpriteTemplate, 2, 6, 0, 5, 20, -24, 14, 2 - createsprite gRockFragmentSpriteTemplate, 2, 6, -5, 0, 20, 24, 14, 2 - createsprite gRockFragmentSpriteTemplate, 2, 6, 0, -5, 30, 18, 8, 2 - createsprite gRockFragmentSpriteTemplate, 2, 6, 0, 0, 30, -18, 8, 2 - createsprite gRockFragmentSpriteTemplate, 2, 6, 0, 0, -30, 18, 8, 2 - createsprite gRockFragmentSpriteTemplate, 2, 6, 0, 0, -30, -18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 5, 0, -20, 24, 14, 1 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 5, 20, -24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, -5, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, -5, 30, 18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, 30, -18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, -30, 18, 8, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 2, 0, 0, -30, -18, 8, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 3, 7, 1 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -1716,24 +1709,24 @@ gBattleAnimMove_EarthPower:: playsewithpan SE_M_EARTHQUAKE, SOUND_PAN_TARGET delay 40 loopsewithpan 145, SOUND_PAN_TARGET 11, 3 - createvisualtask AnimTask_ShakeMon, 5, 5, ANIM_TARGET, 0, 3, 25, 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 194, 3, 1, 5, 0 + createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 3, 25, 1 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, 5, 0 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 194, 3, 1, -10, -15 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, -10, -15 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 130, 3, 1, 0, 25 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 130, 1, 0, 25 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 194, 3, 1, 15, 5 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, 15, 5 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 194, 3, 1, -25, 0 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, -25, 0 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 130, 3, 1, 30, 30 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 130, 1, 30, 30 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 130, 3, 1, -27, 25 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 130, 1, -27, 25 delay 1 - createsprite gDragonRageFirePlumeSpriteTemplate, 194, 3, 1, 0, 8 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_TARGET, 194, 1, 0, 8 waitforvisualfinish - createsprite gSlideMonToOriginalPosSpriteTemplate, 194, 3, 0, 0, 4 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 194, 0, 0, 4 waitforvisualfinish end @@ -1742,12 +1735,12 @@ gBattleAnimMove_Switcheroo:: waitbgfadein loadspritegfx ANIM_TAG_ITEM_BAG loadspritegfx ANIM_TAG_SPEED_DUST - createsprite gTrickBagSpriteTemplate, 2, 2, -39, 80 - createsprite gTrickBagSpriteTemplate, 2, 2, -39, 208 + createsprite gTrickBagSpriteTemplate, ANIM_ATTACKER, 2, -39, 80 + createsprite gTrickBagSpriteTemplate, ANIM_ATTACKER, 2, -39, 208 delay 16 playsewithpan SE_M_SKETCH, 0 - createvisualtask AnimTask_StretchTargetUp, 3, 0 - createvisualtask AnimTask_StretchAttackerUp, 3, 0 + createvisualtask AnimTask_StretchTargetUp, 3 + createvisualtask AnimTask_StretchAttackerUp, 3 delay 30 playsewithpan SE_M_DOUBLE_TEAM, 0 delay 24 @@ -1794,17 +1787,17 @@ GigaImpactContinuity: delay 11 createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 26, 0, 0, 5 delay 6 - createsprite gBasicHitSplatSpriteTemplate, 4, 4, -10, 0, 1, 0 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 4, -10, 0, 1, 0 playsewithpan SE_M_MEGA_KICK2, SOUND_PAN_TARGET delay 1 - createsprite gSlideMonToOffsetSpriteTemplate 2, 5, 1, -16, 0, 0, 4 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 1, -16, 0, 0, 4 waitforvisualfinish createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 4, 0, 12, 1 waitforvisualfinish delay 2 - createsprite gSlideMonToOriginalPosSpriteTemplate 2, 3, 0, 0, 5 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, ANIM_ATTACKER, 0, 5 delay 3 - createsprite gSlideMonToOriginalPosSpriteTemplate 2, 3, 1, 0, 6 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 2, ANIM_TARGET, 0, 6 waitforvisualfinish clearmonbg ANIM_DEF_PARTNER blendoff @@ -1820,7 +1813,7 @@ gBattleAnimMove_NastyPlot:: createvisualtask AnimTask_FadeScreenToWhite, 5 waitbgfadein delay 8 - createsprite gQuestionMarkSpriteTemplate, 20, 0 + createsprite gQuestionMarkSpriteTemplate, ANIM_ATTACKER, 20, 0 playsewithpan SE_M_METRONOME, SOUND_PAN_ATTACKER delay 54 loopsewithpan SE_M_METRONOME, SOUND_PAN_ATTACKER, 16, 3 @@ -1886,17 +1879,17 @@ gBattleAnimMove_Avalanche:: loadspritegfx ANIM_TAG_ROCKS loadspritegfx ANIM_TAG_ICE_CHUNK monbg ANIM_DEF_PARTNER - createsprite gShakeMonOrTerrainSpriteTemplate, 2, 4, 7, 1, 11, 1 - createsprite gAvalancheSpriteTemplate, 130, 4, -5, 1, -5, 1 + createsprite gShakeMonOrTerrainSpriteTemplate, ANIM_TARGET, 2, 7, 1, 11, 1 + createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 130, 4, -5, 1, -5, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET delay 2 - createsprite gAvalancheSpriteTemplate, 130, 4, 5, 0, 6, 1 + createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 130, 5, 0, 6, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET delay 2 - createsprite gAvalancheSpriteTemplate, 130, 4, 19, 1, 10, 1 + createsprite gAvalancheSpriteTemplate, ANIM_TARGET, 130, 19, 1, 10, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET delay 2 - createsprite gAvalancheSpriteTemplate 130, 4, -17, 2, -20, 1 + createsprite gAvalancheSpriteTemplate ANIM_TARGET, 130, -17, 2, -20, 1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 5, 50, 1 createvisualtask AnimTask_ShakeMon, 2, ANIM_DEF_PARTNER, 0, 5, 50, 1 @@ -2190,8 +2183,8 @@ gBattleAnimMove_PsychoCut:: loadspritegfx ANIM_TAG_CROSS_IMPACT monbg ANIM_ATK_PARTNER createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_CROSS_IMPACT, 0, 9, 9, RGB_PURPLE - createvisualtask AnimTask_SwayMon, 5, 0, 6, 2048, 2, ANIM_ATTACKER - createsprite gPsychoCutSpiralSpriteTemplate, 2, 4, 0, 0, 0, 0 + createvisualtask AnimTask_SwayMon, ANIM_ATTACKER, 0, 6, 2048, 2, ANIM_ATTACKER + createsprite gPsychoCutSpiralSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 0, 0 createvisualtask AnimTask_BlendBattleAnimPal, 1, 1, 2, 0, 4, RGB_BLACK createvisualtask AnimTask_BlendBattleAnimPal, 1, 2, 2, 0, 10, RGB(20, 12, 23) delay 30 @@ -2217,28 +2210,28 @@ gBattleAnimMove_ZenHeadbutt:: loadspritegfx ANIM_TAG_WATER_IMPACT monbg ANIM_ATTACKER setalpha 12, 8 - createsprite gSimplePaletteBlendSpriteTemplate, 2, 5, 1, 2, 0, 4, 0 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 2, 0, 4, 0 waitforvisualfinish - createsprite gZenHeadbuttSpriteTemplate, 66, 1, 0 + createsprite gZenHeadbuttSpriteTemplate, ANIM_ATTACKER, 66, 0 delay 18 playsewithpan SE_M_MORNING_SUN, SOUND_PAN_ATTACKER waitforvisualfinish delay 2 playsewithpan SE_M_HEADBUTT, SOUND_PAN_ATTACKER loadspritegfx ANIM_TAG_IMPACT - createsprite gBowMonSpriteTemplate, 2, 1, 0 + createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 1, 0 playsewithpan SE_M_HEADBUTT, SOUND_PAN_ATTACKER waitforvisualfinish delay 2 - createsprite gBowMonSpriteTemplate, 2, 1, 1 + createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 1, 1 waitforvisualfinish createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_ATTACKER, 2, 0, 4, 1 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 5, 0, 6, 1 - createsprite gBowMonSpriteTemplate, 2, 1, 2 - createsprite gAquaTailHitSpriteTemplate, 131, 4, 0, 0, 1, 1 + createsprite gBowMonSpriteTemplate, ANIM_ATTACKER, 1, 2 + createsprite gAquaTailHitSpriteTemplate, ANIM_TARGER, 131, 0, 0, 1, 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET waitforvisualfinish - createsprite gSimplePaletteBlendSpriteTemplate, 2, 5, 1, 4, 4, 0, 0 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 4, 4, 0, 0 clearmonbg ANIM_ATTACKER blendoff delay 1 @@ -2253,22 +2246,22 @@ gBattleAnimMove_MirrorShot:: createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 0, 10, RGB_WHITEALPHA createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_IMPACT, 0, 12, 12, RGB(21, 21, 21) waitforvisualfinish - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGER, 131, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGER, 131, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGER, 131, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGER, 131, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGER, 131, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 3 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 2 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGER, 131, 1, 2 createvisualtask SoundTask_PlaySE1WithPanning, 5, SE_M_VITAL_THROW2, SOUND_PAN_TARGET waitforvisualfinish createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 10, 0, RGB_WHITEALPHA @@ -2327,25 +2320,25 @@ gBattleAnimMove_RockClimb:: setalpha 12, 8 createvisualtask AnimTask_Rollout, 2, 0 waitforvisualfinish - createvisualtask AnimTask_ShakeTargetBasedOnMovePowerOrDmg, 2, 5, 0, 1, 30, 1, RGB(0, 16, 1) - createsprite gBasicHitSplatSpriteTemplate, 131, 4, -15, 8, 1, 1 + createvisualtask AnimTask_ShakeTargetBasedOnMovePowerOrDmg, 2, 0, 1, 30, 1, RGB(0, 16, 1) + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -15, 8, 1, 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET delay 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, 131, 4, -5, -12, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -5, -12, 1, 1 delay 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, 131, 4, 0, -32, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 0, -32, 1, 1 delay 1 playsewithpan SE_M_VITAL_THROW2, SOUND_PAN_TARGET - createsprite gBasicHitSplatSpriteTemplate, 131, 4, 5, -52, 1, 1 - createsprite gSlideMonToOffsetSpriteTemplate, 2, 5, 1, -25, 16, 1, 4 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 5, -52, 1, 1 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_TARGET, 2, 1, -25, 16, 1, 4 delay 4 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 0, 3, 6, 1 delay 30 - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 0, 0, 6 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 6 delay 4 - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 1, 0, 6 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_TARGET, 2, 1, 0, 6 clearmonbg ANIM_DEF_PARTNER blendoff end @@ -2390,7 +2383,7 @@ gBattleAnimMove_DracoMeteor:: loadspritegfx ANIM_TAG_FAIRY_LOCK_CHAINS @Gray Colour loadspritegfx ANIM_TAG_WATER_GUN @Sparkles Trail loadspritegfx ANIM_TAG_FIRE_PLUME @Eruption - createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 1, 0, 12, 0x2C41 + createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 1, 0, 12, RGB(1, 2, 11) createvisualtask AnimTask_BlendParticle, 5, ANIM_TAG_WATER_GUN, 0, 10, 10, RGB_PURPLE @;Purple monbg ANIM_TARGET setalpha 12, 8 @@ -2402,72 +2395,72 @@ gBattleAnimMove_DracoMeteor:: call DracoMeteor2 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0x28, 0x20 @; For Meteor 1 - createvisualtask AnimTask_HorizontalShake, 5, 3, 5, 2, 0x1 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 40, 32 @; For Meteor 1 + createvisualtask AnimTask_HorizontalShake, 5, 5, 2, 1 delay 7 call DracoMeteor3 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0xFFF8, 0x20 @; For Meteor 2 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, -8, 32 @; For Meteor 2 delay 7 call DracoMeteor4 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0x15, 0x20 @; For Meteor 3 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 21, 32 @; For Meteor 3 delay 7 call DracoMeteor1 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0xFFF8, 0x20 @; For Meteor 4 - createvisualtask AnimTask_HorizontalShake, 5, 3, 5, 2, 0x1 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, -8, 32 @; For Meteor 4 + createvisualtask AnimTask_HorizontalShake, 5, 5, 2, 1 delay 7 call DracoMeteor2 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0x28, 0x20 @; For Meteor 1 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 40, 32 @; For Meteor 1 delay 7 call DracoMeteor3 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0x15, 0x20 @; For Meteor 3 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 21, 32 @; For Meteor 3 delay 15 playsewithpan SE_M_ROCK_THROW, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMon, 5, ANIM_TARGET, 0, 7, 4, 2 - createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 0x15, 0x20 @; For Meteor 3 + createsprite gDragonRageFirePlumeSpriteTemplate, ANIM_ATTACKER, 2, ANIM_TARGET, 21, 32 @; For Meteor 3 createvisualtask AnimTask_HorizontalShake, 5, ANIM_TARGET, 2, 1 delay 7 - createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 1, 12, 0, 0x2C41 + createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_BG, 1, 12, 0, RGB(1, 2, 11) waitforvisualfinish clearmonbg ANIM_TARGET blendoff end DracoMeteor1: - createsprite gDracoMeteorRocksSpriteTemplate 0x83, 5, 0xffd0, 0xffc0, 0x28, 0x20, 0x19 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -48, -64, 40, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xffd0, 0xffc0, 0x28, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -48, -64, 40, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xffd0, 0xffc0, 0x28, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -48, -64, 40, 32, 25 return DracoMeteor2: - createsprite gDracoMeteorRocksSpriteTemplate 0x83, 5, 0xff90, 0xffc0, 0xFFF8, 0x20, 0x19 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -112, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xff90, 0xffc0, 0xFFF8, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -112, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xff90, 0xffc0, 0xFFF8, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -112, -64, -8, 32, 25 return DracoMeteor3: - createsprite gDracoMeteorRocksSpriteTemplate 0x83, 5, 0xffb0, 0xffc0, 0x18, 0x20, 0x19 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, 24, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xffb0, 0xffc0, 0x18, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, 24, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xffb0, 0xffc0, 0x18, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, 24, 32, 25 return DracoMeteor4: - createsprite gDracoMeteorRocksSpriteTemplate 0x83, 5, 0xffb0, 0xffc0, 0xFFF8, 0x20, 0x19 + createsprite gDracoMeteorRocksSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xffb0, 0xffc0, 0xFFF8, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, -8, 32, 25 delay 2 - createsprite gDracoMeteorTailSpriteTemplate 0x83, 5, 0xffb0, 0xffc0, 0xFFF8, 0x20, 0x19 + createsprite gDracoMeteorTailSpriteTemplate, ANIM_ATTACKER, 131, -80, -64, -8, 32, 25 return gBattleAnimMove_Discharge:: @@ -2583,14 +2576,14 @@ gBattleAnimMove_LavaPlume:: createvisualtask AnimTask_ShakeMon2, 2, ANIM_DEF_PARTNER, 1, 0, 32, 1 createvisualtask AnimTask_ShakeMon2, 2, ANIM_ATK_PARTNER, 1, 0, 32, 1 waitforvisualfinish - createsprite gLavaPlumeSpriteTemplate, 130, 1, 0 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 32 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 64 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 96 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 128 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 160 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 192 - createsprite gLavaPlumeSpriteTemplate, 130, 1, 224 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 0 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 32 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 64 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 96 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 128 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 160 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 192 + createsprite gLavaPlumeSpriteTemplate, ANIM_ATTACKER, 130, 224 playsewithpan SE_M_SACRED_FIRE, SOUND_PAN_ATTACKER waitforvisualfinish end @@ -2733,36 +2726,36 @@ RockWrecker_1: createvisualtask AnimTask_StartSlidingBg, 5, -1024, 0, 0, -1 loadspritegfx ANIM_TAG_ROCKS loadspritegfx ANIM_TAG_IMPACT - createsprite gHorizontalLungeSpriteTemplate, 2, 2, 4, 6 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 3 playsewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER - createsprite gRockBlastRockSpriteTemplate, 130, 6, 16, 0, 0, 0, 25, 257 + createsprite gRockBlastRockSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 25, 257 waitforvisualfinish - createsprite gBasicHitSplatSpriteTemplate, 131, 4, 0, 0, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 1 playsewithpan SE_M_ROCK_THROW SOUND_PAN_TARGET - createsprite gRockFragmentSpriteTemplate, 130, 6, 0, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 130, 0, 0, 20, 24, 14, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 5, 1 - createsprite gRockFragmentSpriteTemplate, 130, 6, 5, 0, -20, 24, 14, 1 - createsprite gRockFragmentSpriteTemplate, 130, 6, 0, 5, 20, -18, 14, 2 - createsprite gRockFragmentSpriteTemplate, 130, 6, -5, 0, -20, -18, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 130, 5, 0, -20, 24, 14, 1 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 130, 0, 5, 20, -18, 14, 2 + createsprite gRockFragmentSpriteTemplate, ANIM_TARGET, 130, -5, 0, -20, -18, 14, 2 waitforvisualfinish call UnsetPsychicBg end RockWrecker_2: loadspritegfx ANIM_TAG_ROCKS loadspritegfx ANIM_TAG_IMPACT - createsprite gHorizontalLungeSpriteTemplate, 2, 2, 4, 6 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 6 delay 3 playsewithpan SE_M_SWAGGER, SOUND_PAN_ATTACKER - createsprite gRockBlastRockSpriteTemplate, 130, 6, 16, 0, 0, 0, 25, 257 + createsprite gRockBlastRockSpriteTemplate, ANIM_ATTACKER, 130, 16, 0, 0, 0, 25, 257 waitforvisualfinish - createsprite gBasicHitSplatSpriteTemplate, 131, 4, 0, 0, 1, 1 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 0, 0, 1, 1 playsewithpan SE_M_ROCK_THROW SOUND_PAN_TARGET - createsprite gRockFragmentSpriteTemplate 130, 6, 0, 0, 20, 24, 14, 2 + createsprite gRockFragmentSpriteTemplate ANIM_TARGET, 130, 0, 0, 20, 24, 14, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 5, 1 - createsprite gRockFragmentSpriteTemplate 130, 6, 5, 0, -20, 24, 14, 1 - createsprite gRockFragmentSpriteTemplate 130, 6, 0, 5, 20, -18, 14, 2 - createsprite gRockFragmentSpriteTemplate 130, 6, -5, 0, -20, -18, 14, 2 + createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 130, 5, 0, -20, 24, 14, 1 + createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 130, 0, 5, 20, -18, 14, 2 + createsprite gRockFragmentSpriteTemplate ANIM_ATTACKER, 130, -5, 0, -20, -18, 14, 2 waitforvisualfinish call UnsetPsychicBg end @@ -2792,7 +2785,7 @@ gBattleAnimMove_GunkShot:: splitbgprio ANIM_TARGET setalpha 12, 8 call SetGunkShotBG - createvisualtask AnimTask_ShakeMon, 5, 5, ANIM_ATTACKER, 0, 2, 40, 1 + createvisualtask AnimTask_ShakeMon, 5, ANIM_ATTACKER, 0, 2, 40, 1 delay 6 panse SE_M_HYDRO_PUMP, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 2, 0 createvisualtask AnimTask_StartSinAnimTimer, 5, 1, 100 @@ -2824,16 +2817,16 @@ gBattleAnimMove_GunkShot:: blendoff end GunkShotParticles: - createsprite gGunkShoParticlesSpriteTemplate, 3, 4, 10, 10, 0, 16 - createsprite gGunkShoParticlesSpriteTemplate, 3, 4, 10, 10, 0, -16 + createsprite gGunkShoParticlesSpriteTemplate, ANIM_ATTACKER, 3, 10, 10, 0, 16 + createsprite gGunkShoParticlesSpriteTemplate, ANIM_ATTACKER, 3, 10, 10, 0, -16 delay 1 - createsprite gGunkShoParticlesSpriteTemplate, 3, 4, 10, 10, 0, 16 - createsprite gGunkShoParticlesSpriteTemplate, 3, 4, 10, 10, 0, -16 + createsprite gGunkShoParticlesSpriteTemplate, ANIM_ATTACKER, 3, 10, 10, 0, 16 + createsprite gGunkShoParticlesSpriteTemplate, ANIM_ATTACKER, 3, 10, 10, 0, -16 delay 1 return GunkShotImpact: - createsprite gGunkShotImpactSpriteTemplate, 4, 4, 0, 15, 1, 1 - createsprite gGunkShotImpactSpriteTemplate, 4, 4, 0, -15, 1, 1 + createsprite gGunkShotImpactSpriteTemplate, ANIM_TARGET, 4, 0, 15, 1, 1 + createsprite gGunkShotImpactSpriteTemplate, ANIM_TARGET, 4, 0, -15, 1, 1 return SetGunkShotBG: fadetobg BG_GUNK_SHOT @@ -2867,16 +2860,16 @@ gBattleAnimMove_MagnetBomb:: loadspritegfx ANIM_TAG_SPARK_2 delay 0 playsewithpan 119, 192 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 32, 24, 190, 12, 0, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 32, 24, 190, 12, 0, 1, 0 delay 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 80, 24, 22, 12, 0, 1, 0 - createsprite gSparkElectricitySpriteTemplate, 0, 7, 156, 24, 121, 13, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 80, 24, 22, 12, 0, 1, 0 + createsprite gSparkElectricitySpriteTemplate, ANIM_ATTACKER, 0, 156, 24, 121, 13, 0, 1, 1 delay 0 playsewithpan 119, 192 - createsprite gSparkElectricitySpriteTemplate 0, 7, 100, 24, 60, 10, 0, 1, 0 - createsprite gSparkElectricitySpriteTemplate 0, 7, 170, 24, 42, 11, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate ANIM_ATTACKER, 0, 100, 24, 60, 10, 0, 1, 0 + createsprite gSparkElectricitySpriteTemplate ANIM_ATTACKER, 0, 170, 24, 42, 11, 0, 1, 1 delay 0 - createsprite gSparkElectricitySpriteTemplate 0, 7, 238, 24, 165, 10, 0, 1, 1 + createsprite gSparkElectricitySpriteTemplate ANIM_ATTACKER, 0, 238, 24, 165, 10, 0, 1, 1 delay 0 loadspritegfx ANIM_TAG_RED_ORB playsewithpan 152, SOUND_PAN_ATTACKER @@ -2908,22 +2901,22 @@ gBattleAnimMove_MagnetBomb:: loadspritegfx ANIM_TAG_GRAY_SMOKE loadspritegfx ANIM_TAG_BLACK_BALL playsewithpan 177, 63 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, 8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, 8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, -8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, 8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, -8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 0 waitforvisualfinish playsewithpan 177, 63 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, 8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, 8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, -8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, 8, -8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, 8, -8, 1, 0 delay 2 - createsprite gOctazookaSmokeSpriteTemplate, 130, 4, -8, 8, 1, 0 + createsprite gOctazookaSmokeSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 0 waitforvisualfinish end @@ -2931,55 +2924,55 @@ gBattleAnimMove_StoneEdge:: loadspritegfx ANIM_TAG_STONE_EDGE loadspritegfx ANIM_TAG_IMPACT playsewithpan SE_M_ROCK_THROW SOUND_PAN_TARGET - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 28, 528, 30, 13, 50, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 528, 30, 13, 50, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 32, 480, 20, 16, -46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 32, 480, 20, 16, -46, 1 delay 2 loopsewithpan 131, SOUND_PAN_TARGET 24, 3 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 33, 576, 20, 8, 42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 576, 20, 8, 42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 31, 400, 25, 11, -42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 31, 400, 25, 11, -42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 28, 512, 25, 16, 46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 512, 25, 16, 46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 33, 464, 30, 15, 49, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 464, 30, 15, 49, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 28, 528, 30, 13, 50, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 528, 30, 13, 50, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 32, 480, 20, 16, -46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 32, 480, 20, 16, -46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 33, 576, 20, 8, 42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 576, 20, 8, 42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 31, 400, 25, 11, -42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 31, 400, 25, 11, -42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 28, 512, 25, 16, 46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 512, 25, 16, 46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 33, 464, 30, 15, 49, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 464, 30, 15, 49, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 28, 528, 30, 13, 50, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 528, 30, 13, 50, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 32, 480, 20, 16, -46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 32, 480, 20, 16, -46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 33, 576, 20, 8, 42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 576, 20, 8, 42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 31, 400, 25, 11, -42, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 31, 400, 25, 11, -42, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 28, 512, 25, 16, 46, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 28, 512, 25, 16, 46, 1 delay 2 - createsprite gStoneEdgeSpriteTemplate, 130, 7, 0, 33, 464, 30, 15, 49, 1 + createsprite gStoneEdgeSpriteTemplate, ANIM_TARGET, 130, 0, 33, 464, 30, 15, 49, 1 delay 2 - createsprite gBasicHitSplatSpriteTemplate, 131, 4, -32, -16, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -32, -16, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 3, 0, 12, 1 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_DEF_PARTNER, 3, 0, 12, 1 delay 4 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gRandomPosHitSplatSpriteTemplate, 131, 2, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gBasicHitSplatSpriteTemplate, 131, 4, 32, 20, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 32, 20, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -2989,14 +2982,14 @@ gBattleAnimMove_StoneEdge:: gBattleAnimMove_Captivate:: loadspritegfx ANIM_TAG_MAGENTA_HEART loadspritegfx ANIM_TAG_SPARKLE_2 - createvisualtask AnimTask_RockMonBackAndForth, 5, ANIM_DEF_PARTNER, 0, 2, 0 - createsprite gMagentaHeartSpriteTemplate, 3, 2, 0, 20 + createvisualtask AnimTask_RockMonBackAndForth, 5, ANIM_ATTACKER, 2, 0 + createsprite gMagentaHeartSpriteTemplate, ANIM_ATTACKER, 3, 0, 20 playsewithpan SE_M_CHARM, SOUND_PAN_ATTACKER delay 15 - createsprite gMagentaHeartSpriteTemplate, 3, 2, -20, 20 + createsprite gMagentaHeartSpriteTemplate, ANIM_ATTACKER, 3, -20, 20 playsewithpan SE_M_CHARM, SOUND_PAN_ATTACKER delay 15 - createsprite gMagentaHeartSpriteTemplate, 3, 2, 20, 20 + createsprite gMagentaHeartSpriteTemplate, ANIM_ATTACKER, 3, 20, 20 playsewithpan 228, SOUND_PAN_ATTACKER call GrantingStarsEffect waitforvisualfinish @@ -3022,14 +3015,14 @@ gBattleAnimMove_StealthRock:: gBattleAnimMove_GrassKnot:: loadspritegfx ANIM_TAG_RAZOR_LEAF loadspritegfx ANIM_TAG_IMPACT - createsprite gSlideMonToOffsetSpriteTemplate, 2, 5, 0, 20, 0, 0, 4 - createsprite gGrassKnotSpriteTemplate, 130, 6, -18, 19, 40, 8, 160, 0 + createsprite gSlideMonToOffsetSpriteTemplate, ANIM_ATTACKER, 2, 0, 20, 0, 0, 4 + createsprite gGrassKnotSpriteTemplate, ANIM_TARGET, 130, -18, 19, 40, 8, 160, 0 delay 4 - createsprite gBasicHitSplatSpriteTemplate, 130, 4, -8, 8, 1, 2 - createvisualtask AnimTask_RotateMonSpriteToSide, 2, 4, 6, 384, ANIM_TARGET, 2 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 130, -8, 8, 1, 2 + createvisualtask AnimTask_RotateMonSpriteToSide, 2, 6, 384, ANIM_TARGET, 2 playsewithpan SE_M_VITAL_THROW2 SOUND_PAN_TARGET waitforvisualfinish - createsprite gSlideMonToOriginalPosSpriteTemplate, 2, 3, 0, 1, 4 + createsprite gSlideMonToOriginalPosSpriteTemplate, ANIM_ATTACKER, 2, 0, 1, 4 end gBattleAnimMove_Chatter:: @@ -3295,10 +3288,10 @@ gBattleAnimMove_AquaJet:: loadspritegfx ANIM_TAG_ROUND_SHADOW loadspritegfx ANIM_TAG_SPLASH playsewithpan SE_M_HEADBUTT, SOUND_PAN_ATTACKER - createsprite gDiveBallSpriteTemplate, 2, 4, 0, 0, 13, 336 + createsprite gDiveBallSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, 13, 336 waitforvisualfinish playsewithpan SE_M_DIVE, SOUND_PAN_ATTACKER - createsprite gDiveWaterSplashSpriteTemplate, 3, 1, 0 + createsprite gDiveWaterSplashSpriteTemplate, ANIM_ATTACKER, 3, 0 call DiveSetUpWaterDroplets call DiveSetUpWaterDroplets call DiveSetUpWaterDroplets @@ -3309,7 +3302,7 @@ gBattleAnimMove_AquaJet:: monbg ANIM_DEF_PARTNER setalpha 12, 8 playsewithpan SE_M_EXPLOSION, SOUND_PAN_TARGET - createsprite gDiveWaterSplashSpriteTemplate, 131, 1, 1 + createsprite gDiveWaterSplashSpriteTemplate, ANIM_TARGET, 131, 1 call DiveAttackWaterDroplets call DiveAttackWaterDroplets call DiveAttackWaterDroplets @@ -3351,18 +3344,18 @@ gBattleAnimMove_AttackOrder:: createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 20, 255, 15, 32, 0 createsprite gAttackOrderParticleSpriteTemplate, ANIM_TARGET, 5, 110, 10, 8, 32, 20 waitforvisualfinish - createsprite gBasicHitSplatSpriteTemplate 131, 4, -32, -16, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, -32, -16, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 3, 0, 12, 1 createvisualtask AnimTask_ShakeMonInPlace, 2, ANIM_TARGET, 3, 0, 12, 1 delay 4 - createsprite gRandomPosHitSplatSpriteTemplate 131, 2, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gRandomPosHitSplatSpriteTemplate 131, 2, 1, 3 + createsprite gRandomPosHitSplatSpriteTemplate, ANIM_TARGET, 131, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 4 - createsprite gBasicHitSplatSpriteTemplate 131, 4, 32, 20, 1, 3 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 131, 32, 20, 1, 3 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET waitforvisualfinish clearmonbg ANIM_DEF_PARTNER @@ -3376,26 +3369,26 @@ gBattleAnimMove_DefendOrder:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET playsewithpan SE_M_SWEET_SCENT, SOUND_PAN_TARGET - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 120, 70, 5, 70, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 70, 5, 70, 30 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 55, 6, 60, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 6, 60, 25 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 60, 7, 60, 30 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 55, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 60, 7, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 100, 50, 4, 50, 26 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 100, 50, 4, 50, 26 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 105, 25, 8, 60, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 25, 8, 60, 20 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 40, 10, 48, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 40, 10, 48, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 120, 30, 6, 45, 25 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 35, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 30, 6, 45, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 35, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 105, 20, 8, 40, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 20, 8, 40, 0 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 20, 255, 15, 32, 0 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 110, 10, 8, 32, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 20, 255, 15, 32, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 110, 10, 8, 32, 20 waitforvisualfinish loadspritegfx ANIM_TAG_BLUE_STAR waitforvisualfinish @@ -3413,26 +3406,26 @@ gBattleAnimMove_HealOrder:: monbg ANIM_DEF_PARTNER splitbgprio ANIM_TARGET playsewithpan SE_M_SWEET_SCENT, SOUND_PAN_TARGET - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 120, 70, 5, 70, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 70, 5, 70, 30 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 55, 6, 60, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 6, 60, 25 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 60, 7, 60, 30 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 55, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 60, 7, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 55, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 100, 50, 4, 50, 26 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 100, 50, 4, 50, 26 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 105, 25, 8, 60, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 25, 8, 60, 20 delay 1 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 40, 10, 48, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 40, 10, 48, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 120, 30, 6, 45, 25 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 115, 35, 10, 60, 30 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 120, 30, 6, 45, 25 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 115, 35, 10, 60, 30 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 105, 20, 8, 40, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 105, 20, 8, 40, 0 delay 3 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 20, 255, 15, 32, 0 - createsprite gAttackOrderParticleSpriteTemplate, 130, 5, 110, 10, 8, 32, 20 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 20, 255, 15, 32, 0 + createsprite gAttackOrderParticleSpriteTemplate, ANIM_ATTACKER, 130, 110, 10, 8, 32, 20 waitforvisualfinish loadspritegfx ANIM_TAG_BLUE_STAR waitforvisualfinish @@ -3469,16 +3462,16 @@ gBattleAnimMove_DoubleHit:: loadspritegfx ANIM_TAG_IMPACT monbg ANIM_TARGET setalpha 12, 8 - createsprite gHorizontalLungeSpriteTemplate, 2, 2, 4, 4 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 4 delay 6 - createsprite gBasicHitSplatSpriteTemplate, 2, 4, 0, 0, 1, 2 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 6, 1 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 8 waitforvisualfinish - createsprite gHorizontalLungeSpriteTemplate, 2, 2, 4, 4 + createsprite gHorizontalLungeSpriteTemplate, ANIM_ATTACKER, 2, 4, 4 delay 6 - createsprite gBasicHitSplatSpriteTemplate, 2, 4, 0, 0, 1, 2 + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, 0, 0, 1, 2 createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 3, 0, 6, 1 playsewithpan SE_M_COMET_PUNCH, SOUND_PAN_TARGET delay 8 @@ -3567,33 +3560,33 @@ gBattleAnimMove_LunarDance:: loadspritegfx ANIM_TAG_GREEN_SPARKLE loadspritegfx ANIM_TAG_HOLLOW_ORB setalpha 0, 16 - createsprite gSimplePaletteBlendSpriteTemplate, 2, 5, 1, 1, 0, 16, 0 + createsprite gSimplePaletteBlendSpriteTemplate, ANIM_ATTACKER, 2, 1, 1, 0, 16, 0 waitforvisualfinish - createsprite gMoonSpriteTemplate, 2, 2, 120, 56 - createvisualtask AnimTask_AlphaFadeIn, 3, 5, 0, 16, 16, 0, 1 + createsprite gMoonSpriteTemplate, ANIM_ATTACKER, 2, 120, 56 + createvisualtask AnimTask_AlphaFadeIn, 3, 0, 16, 16, 0, 1 playsewithpan 211, 0 delay 30 - createsprite gMoonlightSparkleSpriteTemplate, 40, 2, -12, 0 + createsprite gMoonlightSparkleSpriteTemplate, ANIM_ATTACKER, 40, -12, 0 delay 30 - createsprite gMoonlightSparkleSpriteTemplate, 40, 2, -18, 0 + createsprite gMoonlightSparkleSpriteTemplate, ANIM_ATTACKER, 40, -18, 0 delay 30 - createsprite gMoonlightSparkleSpriteTemplate, 40, 2, 21, 0 + createsprite gMoonlightSparkleSpriteTemplate, ANIM_ATTACKER, 40, 21, 0 delay 30 - createsprite gMoonlightSparkleSpriteTemplate, 40, 2, 0, 0 + createsprite gMoonlightSparkleSpriteTemplate, ANIM_ATTACKER, 40, 0, 0 delay 30 - createsprite gMoonlightSparkleSpriteTemplate, 40, 2, 10, 0 + createsprite gMoonlightSparkleSpriteTemplate, ANIM_ATTACKER, 40, 10, 0 delay 20 createvisualtask AnimTask_MoonlightEndFade, 2, 0 createvisualtask AnimTask_DragonDanceWaver, 5, 0 playsewithpan 203, SOUND_PAN_ATTACKER delay 8 - createvisualtask AnimTask_BlendPalInAndOutByTag, 5, 5, ANIM_TAG_HOLLOW_ORB, RGB(0, 0, 19), 14, 0, 3 - createsprite gDragonDanceOrbSpriteTemplate, 2, 1, 0 - createsprite gDragonDanceOrbSpriteTemplate, 2, 1, 43 - createsprite gDragonDanceOrbSpriteTemplate, 2, 1, 85 - createsprite gDragonDanceOrbSpriteTemplate, 2, 1, 128 - createsprite gDragonDanceOrbSpriteTemplate, 2, 1, 170 - createsprite gDragonDanceOrbSpriteTemplate, 2, 1, 213 + createvisualtask AnimTask_BlendPalInAndOutByTag, 5, ANIM_TAG_HOLLOW_ORB, RGB(0, 0, 19), 14, 0, 3 + createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 0 + createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 43 + createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 85 + createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 128 + createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 170 + createsprite gDragonDanceOrbSpriteTemplate, ANIM_ATTACKER, 2, 213 delay 30 playsewithpan 203, SOUND_PAN_ATTACKER delay 30 @@ -3774,7 +3767,7 @@ gBattleAnimMove_OminousWind:: monbg ANIM_DEF_PARTNER @bankBG_over_partnerBG delay 0 - createvisualtask AnimTask_BlendBattleAnimPalExclude, 10, 5, 1, 0, 0, 0, 0 + createvisualtask AnimTask_BlendBattleAnimPalExclude, 10, 1, 0, 0, 0, 0 delay 0 createvisualtask AnimTask_GetAttackerSide, 2, 0 jumpargeq 7, 1, OminousWindFadeToBg diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 0b3008747256..42cef5cc7ddd 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -272,7 +272,7 @@ BattleScript_EffectChillyReception:: jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_RAIN_PRIMAL, BattleScript_EffectChillyReceptionBlockedByPrimalRain jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_STRONG_WINDS, BattleScript_EffectChillyReceptionBlockedByStrongWinds call BattleScript_EffectChillyReceptionPlayAnimation - setfieldweather ENUM_WEATHER_SNOW + setfieldweather BATTLE_WEATHER_SNOW call BattleScript_MoveWeatherChangeRet goto BattleScript_MoveSwitch BattleScript_EffectChillyReceptionPlayAnimation: @@ -330,7 +330,7 @@ BattleScript_MoveSwitchOpenPartyScreen:: printstring STRINGID_EMPTYSTRING3 waitmessage 1 printstring STRINGID_SWITCHINMON - switchinanim BS_ATTACKER, TRUE + switchinanim BS_ATTACKER, FALSE, TRUE waitstate switchineffects BS_ATTACKER BattleScript_MoveSwitchEnd: @@ -415,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:: @@ -477,7 +477,7 @@ BattleScript_EffectRevivalBlessingSendOut: getswitchedmondata BS_SCRIPTING switchindataupdate BS_SCRIPTING hpthresholds BS_SCRIPTING - switchinanim BS_SCRIPTING, FALSE + switchinanim BS_SCRIPTING, FALSE, FALSE waitstate switchineffects BS_SCRIPTING goto BattleScript_MoveEnd @@ -2398,7 +2398,7 @@ BattleScript_EffectHealingWish:: trytoclearprimalweather flushtextbox printstring STRINGID_SWITCHINMON - switchinanim BS_ATTACKER, TRUE + switchinanim BS_ATTACKER, FALSE, TRUE waitstate switchineffects BS_ATTACKER .endif @@ -4273,7 +4273,7 @@ BattleScript_EffectSandstorm:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setfieldweather ENUM_WEATHER_SANDSTORM + setfieldweather BATTLE_WEATHER_SANDSTORM goto BattleScript_MoveWeatherChange BattleScript_EffectRollout:: @@ -4408,7 +4408,7 @@ BattleScript_EffectBatonPass:: trytoclearprimalweather flushtextbox printstring STRINGID_SWITCHINMON - switchinanim BS_ATTACKER, TRUE + switchinanim BS_ATTACKER, FALSE, TRUE waitstate switchineffects BS_ATTACKER goto BattleScript_MoveEnd @@ -4439,7 +4439,7 @@ BattleScript_EffectRainDance:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setfieldweather ENUM_WEATHER_RAIN + setfieldweather BATTLE_WEATHER_RAIN BattleScript_MoveWeatherChange:: attackanimation waitanimation @@ -4457,7 +4457,7 @@ BattleScript_EffectSunnyDay:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setfieldweather ENUM_WEATHER_SUN + setfieldweather BATTLE_WEATHER_SUN goto BattleScript_MoveWeatherChange BattleScript_ExtremelyHarshSunlightWasNotLessened: @@ -4816,7 +4816,7 @@ BattleScript_EffectHail:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setfieldweather ENUM_WEATHER_HAIL + setfieldweather BATTLE_WEATHER_HAIL goto BattleScript_MoveWeatherChange BattleScript_EffectTorment:: @@ -5512,7 +5512,7 @@ BattleScript_FaintedMonTryChoose: flushtextbox printstring STRINGID_SWITCHINMON hidepartystatussummary BS_ATTACKER - switchinanim BS_ATTACKER, 0 + switchinanim BS_ATTACKER, FALSE, FALSE waitstate setbyte sSHIFT_SWITCHED, 1 BattleScript_FaintedMonSendOutNew: @@ -5524,7 +5524,7 @@ BattleScript_FaintedMonSendOutNew: flushtextbox printstring STRINGID_SWITCHINMON hidepartystatussummary BS_FAINTED - switchinanim BS_FAINTED, FALSE + switchinanim BS_FAINTED, FALSE, FALSE waitstate resetplayerfainted trytrainerslidelastonmsg BS_FAINTED @@ -5558,7 +5558,7 @@ BattleScript_HandleFaintedMonLoop:: flushtextbox printstring STRINGID_SWITCHINMON hidepartystatussummary BS_FAINTED - switchinanim BS_FAINTED, FALSE + switchinanim BS_FAINTED, FALSE, FALSE waitstate switchineffects BS_FAINTED_MULTIPLE_1 jumpifbytenotequal gBattlerFainted, gBattlersCount, BattleScript_HandleFaintedMonLoop @@ -5774,7 +5774,7 @@ BattleScript_DoSwitchOut:: flushtextbox printstring STRINGID_SWITCHINMON hidepartystatussummary BS_ATTACKER - switchinanim BS_ATTACKER, FALSE + switchinanim BS_ATTACKER, FALSE, FALSE waitstate switchineffects BS_ATTACKER moveendcase MOVEEND_STATUS_IMMUNITY_ABILITIES @@ -5822,20 +5822,18 @@ BattleScript_LearnedNewMove:: BattleScript_LearnMoveReturn:: return -BattleScript_RainContinuesOrEnds:: - printfromtable gRainContinuesStringIds +BattleScript_WeatherContinues:: + printfromtable gWeatherTurnStringIds waitmessage B_WAIT_TIME_LONG - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_RAIN_STOPPED, BattleScript_RainContinuesOrEndsEnd - playanimation BS_ATTACKER, B_ANIM_RAIN_CONTINUES -BattleScript_RainContinuesOrEndsEnd:: + playanimation_var BS_ATTACKER, sB_ANIM_ARG1 + setbyte gBattleCommunication, 0 call BattleScript_ActivateWeatherAbilities end2 -BattleScript_DamagingWeatherContinues:: - printfromtable gSandStormHailSnowContinuesStringIds +BattleScript_WeatherFaded:: + printfromtable gWeatherEndsStringIds waitmessage B_WAIT_TIME_LONG - playanimation_var BS_ATTACKER, sB_ANIM_ARG1 - setbyte gBattleCommunication, 0 + call BattleScript_ActivateWeatherAbilities end2 BattleScript_DamagingWeather:: @@ -5845,6 +5843,12 @@ BattleScript_DamagingWeather:: hitanimation BS_SCRIPTING goto BattleScript_DoTurnDmg +BattleScript_FogEnded_Ret:: + printstring STRINGID_FOGLIFTED + waitmessage B_WAIT_TIME_LONG + call BattleScript_ActivateWeatherAbilities + return + BattleScript_IceBodyHeal:: call BattleScript_AbilityPopUpScripting playanimation BS_SCRIPTING, B_ANIM_SIMPLE_HEAL @@ -5854,42 +5858,6 @@ BattleScript_IceBodyHeal:: waitmessage B_WAIT_TIME_LONG end2 -BattleScript_SandStormHailSnowEnds:: - printfromtable gSandStormHailSnowEndStringIds - waitmessage B_WAIT_TIME_LONG - call BattleScript_ActivateWeatherAbilities - end2 - -BattleScript_SunlightContinues:: - printstring STRINGID_SUNLIGHTSTRONG - waitmessage B_WAIT_TIME_LONG - playanimation BS_ATTACKER, B_ANIM_SUN_CONTINUES - call BattleScript_ActivateWeatherAbilities - end2 - -BattleScript_SunlightFaded:: - printstring STRINGID_SUNLIGHTFADED - waitmessage B_WAIT_TIME_LONG - call BattleScript_ActivateWeatherAbilities - end2 - -BattleScript_FogContinues:: - printstring STRINGID_FOGISDEEP - waitmessage B_WAIT_TIME_LONG - playanimation BS_ATTACKER, B_ANIM_FOG_CONTINUES - call BattleScript_ActivateWeatherAbilities - end2 - -BattleScript_FogEnded_Ret:: - printstring STRINGID_FOGLIFTED - waitmessage B_WAIT_TIME_LONG - call BattleScript_ActivateWeatherAbilities - return - -BattleScript_FogEnded:: - call BattleScript_FogEnded_Ret - end2 - BattleScript_OverworldStatusStarts:: printfromtable gStartingStatusStringIds waitmessage B_WAIT_TIME_LONG @@ -5899,8 +5867,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:: @@ -6061,7 +6028,7 @@ BattleScript_RoarSuccessSwitch:: switchindataupdate BS_TARGET trytoclearprimalweather flushtextbox - switchinanim BS_TARGET, FALSE + switchinanim BS_TARGET, FALSE, FALSE waitstate printstring STRINGID_PKMNWASDRAGGEDOUT switchineffects BS_TARGET @@ -7560,13 +7527,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 @@ -7631,7 +7593,7 @@ BattleScript_EmergencyExitNoPopUp:: switchindataupdate BS_TARGET hpthresholds BS_TARGET printstring STRINGID_SWITCHINMON - switchinanim BS_TARGET, TRUE + switchinanim BS_TARGET, FALSE, TRUE waitstate switchineffects BS_TARGET BattleScript_EmergencyExitRet: @@ -8338,7 +8300,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 @@ -9461,7 +9422,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 @@ -9594,7 +9555,7 @@ BattleScript_EjectButtonActivates:: trytoclearprimalweather flushtextbox printstring 0x3 - switchinanim BS_SCRIPTING 0x1 + switchinanim BS_SCRIPTING, FALSE, TRUE waitstate switchineffects BS_SCRIPTING BattleScript_EjectButtonEnd: @@ -9611,13 +9572,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 @@ -9965,7 +9919,7 @@ BattleScript_DynamaxBegins:: returnatktoball pause B_WAIT_TIME_SHORT returntoball BS_SCRIPTING, TRUE - switchinanim BS_SCRIPTING, TRUE + switchinanim BS_SCRIPTING, TRUE, TRUE updatedynamax playanimation BS_SCRIPTING, B_ANIM_DYNAMAX_GROWTH waitanimation @@ -10049,7 +10003,7 @@ BattleScript_EffectSnow:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setfieldweather ENUM_WEATHER_SNOW + setfieldweather BATTLE_WEATHER_SNOW goto BattleScript_MoveWeatherChange BattleScript_SleepClauseBlocked:: diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index aa9f1da36936..bd87dbf3ef95 100644 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -75,7 +75,7 @@ BattleScript_ItemRestoreHP_Party:: return BattleScript_ItemRestoreHP_SendOutRevivedBattler: - switchinanim BS_SCRIPTING, FALSE + switchinanim BS_SCRIPTING, FALSE, FALSE waitstate switchineffects BS_SCRIPTING end diff --git a/data/event_scripts.s b/data/event_scripts.s index 513bd3f590a3..71bc884308b6 100644 --- a/data/event_scripts.s +++ b/data/event_scripts.s @@ -20,6 +20,7 @@ #include "constants/contest.h" #include "constants/daycare.h" #include "constants/decorations.h" +#include "constants/difficulty.h" #include "constants/easy_chat.h" #include "constants/event_objects.h" #include "constants/event_object_movement.h" @@ -1151,3 +1152,4 @@ EventScript_VsSeekerChargingDone:: .include "data/scripts/follower.inc" .include "data/text/save.inc" .include "data/text/birch_speech.inc" + .include "data/scripts/dexnav.inc" diff --git a/data/field_effect_scripts.s b/data/field_effect_scripts.s index baa0ddb5037f..042525223224 100644 --- a/data/field_effect_scripts.s +++ b/data/field_effect_scripts.s @@ -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 diff --git a/data/script_cmd_table.inc b/data/script_cmd_table.inc index 711b118cc6ef..61046e6cb47d 100644 --- a/data/script_cmd_table.inc +++ b/data/script_cmd_table.inc @@ -1,234 +1,245 @@ +@ 'requests_effects' should be set to 1 if the command contains a call +@ to 'Script_RequestEffects', which allows it to be analyzed with +@ 'RunScriptImmediatelyUntilEffect'. +.macro cmd func:req, requests_effects=0 + .if \requests_effects == 0 + .4byte \func + .else + .4byte \func + ROM_SIZE + .endif +.endm + .align 2 gScriptCmdTable:: - .4byte ScrCmd_nop @ 0x00 - .4byte ScrCmd_nop1 @ 0x01 - .4byte ScrCmd_end @ 0x02 - .4byte ScrCmd_return @ 0x03 - .4byte ScrCmd_call @ 0x04 - .4byte ScrCmd_goto @ 0x05 - .4byte ScrCmd_goto_if @ 0x06 - .4byte ScrCmd_call_if @ 0x07 - .4byte ScrCmd_gotostd @ 0x08 - .4byte ScrCmd_callstd @ 0x09 - .4byte ScrCmd_gotostd_if @ 0x0a - .4byte ScrCmd_callstd_if @ 0x0b - .4byte ScrCmd_returnram @ 0x0c - .4byte ScrCmd_endram @ 0x0d - .4byte ScrCmd_setmysteryeventstatus @ 0x0e - .4byte ScrCmd_loadword @ 0x0f - .4byte ScrCmd_loadbyte @ 0x10 - .4byte ScrCmd_setptr @ 0x11 - .4byte ScrCmd_loadbytefromptr @ 0x12 - .4byte ScrCmd_setptrbyte @ 0x13 - .4byte ScrCmd_copylocal @ 0x14 - .4byte ScrCmd_copybyte @ 0x15 - .4byte ScrCmd_setvar @ 0x16 - .4byte ScrCmd_addvar @ 0x17 - .4byte ScrCmd_subvar @ 0x18 - .4byte ScrCmd_copyvar @ 0x19 - .4byte ScrCmd_setorcopyvar @ 0x1a - .4byte ScrCmd_compare_local_to_local @ 0x1b - .4byte ScrCmd_compare_local_to_value @ 0x1c - .4byte ScrCmd_compare_local_to_ptr @ 0x1d - .4byte ScrCmd_compare_ptr_to_local @ 0x1e - .4byte ScrCmd_compare_ptr_to_value @ 0x1f - .4byte ScrCmd_compare_ptr_to_ptr @ 0x20 - .4byte ScrCmd_compare_var_to_value @ 0x21 - .4byte ScrCmd_compare_var_to_var @ 0x22 - .4byte ScrCmd_callnative @ 0x23 - .4byte ScrCmd_gotonative @ 0x24 - .4byte ScrCmd_special @ 0x25 - .4byte ScrCmd_specialvar @ 0x26 - .4byte ScrCmd_waitstate @ 0x27 - .4byte ScrCmd_delay @ 0x28 - .4byte ScrCmd_setflag @ 0x29 - .4byte ScrCmd_clearflag @ 0x2a - .4byte ScrCmd_checkflag @ 0x2b - .4byte ScrCmd_initclock @ 0x2c - .4byte ScrCmd_dotimebasedevents @ 0x2d - .4byte ScrCmd_gettime @ 0x2e - .4byte ScrCmd_playse @ 0x2f - .4byte ScrCmd_waitse @ 0x30 - .4byte ScrCmd_playfanfare @ 0x31 - .4byte ScrCmd_waitfanfare @ 0x32 - .4byte ScrCmd_playbgm @ 0x33 - .4byte ScrCmd_savebgm @ 0x34 - .4byte ScrCmd_fadedefaultbgm @ 0x35 - .4byte ScrCmd_fadenewbgm @ 0x36 - .4byte ScrCmd_fadeoutbgm @ 0x37 - .4byte ScrCmd_fadeinbgm @ 0x38 - .4byte ScrCmd_warp @ 0x39 - .4byte ScrCmd_warpsilent @ 0x3a - .4byte ScrCmd_warpdoor @ 0x3b - .4byte ScrCmd_warphole @ 0x3c - .4byte ScrCmd_warpteleport @ 0x3d - .4byte ScrCmd_setwarp @ 0x3e - .4byte ScrCmd_setdynamicwarp @ 0x3f - .4byte ScrCmd_setdivewarp @ 0x40 - .4byte ScrCmd_setholewarp @ 0x41 - .4byte ScrCmd_getplayerxy @ 0x42 - .4byte ScrCmd_getpartysize @ 0x43 - .4byte ScrCmd_additem @ 0x44 - .4byte ScrCmd_removeitem @ 0x45 - .4byte ScrCmd_checkitemspace @ 0x46 - .4byte ScrCmd_checkitem @ 0x47 - .4byte ScrCmd_checkitemtype @ 0x48 - .4byte ScrCmd_addpcitem @ 0x49 - .4byte ScrCmd_checkpcitem @ 0x4a - .4byte ScrCmd_adddecoration @ 0x4b - .4byte ScrCmd_removedecoration @ 0x4c - .4byte ScrCmd_checkdecor @ 0x4d - .4byte ScrCmd_checkdecorspace @ 0x4e - .4byte ScrCmd_applymovement @ 0x4f - .4byte ScrCmd_applymovementat @ 0x50 - .4byte ScrCmd_waitmovement @ 0x51 - .4byte ScrCmd_waitmovementat @ 0x52 - .4byte ScrCmd_removeobject @ 0x53 - .4byte ScrCmd_removeobjectat @ 0x54 - .4byte ScrCmd_addobject @ 0x55 - .4byte ScrCmd_addobjectat @ 0x56 - .4byte ScrCmd_setobjectxy @ 0x57 - .4byte ScrCmd_showobjectat @ 0x58 - .4byte ScrCmd_hideobjectat @ 0x59 - .4byte ScrCmd_faceplayer @ 0x5a - .4byte ScrCmd_turnobject @ 0x5b - .4byte ScrCmd_trainerbattle @ 0x5c - .4byte ScrCmd_dotrainerbattle @ 0x5d - .4byte ScrCmd_gotopostbattlescript @ 0x5e - .4byte ScrCmd_gotobeatenscript @ 0x5f - .4byte ScrCmd_checktrainerflag @ 0x60 - .4byte ScrCmd_settrainerflag @ 0x61 - .4byte ScrCmd_cleartrainerflag @ 0x62 - .4byte ScrCmd_setobjectxyperm @ 0x63 - .4byte ScrCmd_copyobjectxytoperm @ 0x64 - .4byte ScrCmd_setobjectmovementtype @ 0x65 - .4byte ScrCmd_waitmessage @ 0x66 - .4byte ScrCmd_message @ 0x67 - .4byte ScrCmd_closemessage @ 0x68 - .4byte ScrCmd_lockall @ 0x69 - .4byte ScrCmd_lock @ 0x6a - .4byte ScrCmd_releaseall @ 0x6b - .4byte ScrCmd_release @ 0x6c - .4byte ScrCmd_waitbuttonpress @ 0x6d - .4byte ScrCmd_yesnobox @ 0x6e - .4byte ScrCmd_multichoice @ 0x6f - .4byte ScrCmd_multichoicedefault @ 0x70 - .4byte ScrCmd_multichoicegrid @ 0x71 - .4byte ScrCmd_drawbox @ 0x72 - .4byte ScrCmd_erasebox @ 0x73 - .4byte ScrCmd_drawboxtext @ 0x74 - .4byte ScrCmd_showmonpic @ 0x75 - .4byte ScrCmd_hidemonpic @ 0x76 - .4byte ScrCmd_showcontestpainting @ 0x77 - .4byte ScrCmd_braillemessage @ 0x78 - .4byte ScrCmd_nop1 @ 0x79 - .4byte ScrCmd_giveegg @ 0x7a - .4byte ScrCmd_setmonmove @ 0x7b - .4byte ScrCmd_checkpartymove @ 0x7c - .4byte ScrCmd_bufferspeciesname @ 0x7d - .4byte ScrCmd_bufferleadmonspeciesname @ 0x7e - .4byte ScrCmd_bufferpartymonnick @ 0x7f - .4byte ScrCmd_bufferitemname @ 0x80 - .4byte ScrCmd_bufferdecorationname @ 0x81 - .4byte ScrCmd_buffermovename @ 0x82 - .4byte ScrCmd_buffernumberstring @ 0x83 - .4byte ScrCmd_bufferstdstring @ 0x84 - .4byte ScrCmd_bufferstring @ 0x85 - .4byte ScrCmd_pokemart @ 0x86 - .4byte ScrCmd_pokemartdecoration @ 0x87 - .4byte ScrCmd_pokemartdecoration2 @ 0x88 - .4byte ScrCmd_playslotmachine @ 0x89 - .4byte ScrCmd_setberrytree @ 0x8a - .4byte ScrCmd_choosecontestmon @ 0x8b - .4byte ScrCmd_startcontest @ 0x8c - .4byte ScrCmd_showcontestresults @ 0x8d - .4byte ScrCmd_contestlinktransfer @ 0x8e - .4byte ScrCmd_random @ 0x8f - .4byte ScrCmd_addmoney @ 0x90 - .4byte ScrCmd_removemoney @ 0x91 - .4byte ScrCmd_checkmoney @ 0x92 - .4byte ScrCmd_showmoneybox @ 0x93 - .4byte ScrCmd_hidemoneybox @ 0x94 - .4byte ScrCmd_updatemoneybox @ 0x95 - .4byte ScrCmd_getpokenewsactive @ 0x96 - .4byte ScrCmd_fadescreen @ 0x97 - .4byte ScrCmd_fadescreenspeed @ 0x98 - .4byte ScrCmd_setflashlevel @ 0x99 - .4byte ScrCmd_animateflash @ 0x9a - .4byte ScrCmd_messageautoscroll @ 0x9b - .4byte ScrCmd_dofieldeffect @ 0x9c - .4byte ScrCmd_setfieldeffectargument @ 0x9d - .4byte ScrCmd_waitfieldeffect @ 0x9e - .4byte ScrCmd_setrespawn @ 0x9f - .4byte ScrCmd_checkplayergender @ 0xa0 - .4byte ScrCmd_playmoncry @ 0xa1 - .4byte ScrCmd_setmetatile @ 0xa2 - .4byte ScrCmd_resetweather @ 0xa3 - .4byte ScrCmd_setweather @ 0xa4 - .4byte ScrCmd_doweather @ 0xa5 - .4byte ScrCmd_setstepcallback @ 0xa6 - .4byte ScrCmd_setmaplayoutindex @ 0xa7 - .4byte ScrCmd_setobjectsubpriority @ 0xa8 - .4byte ScrCmd_resetobjectsubpriority @ 0xa9 - .4byte ScrCmd_createvobject @ 0xaa - .4byte ScrCmd_turnvobject @ 0xab - .4byte ScrCmd_opendoor @ 0xac - .4byte ScrCmd_closedoor @ 0xad - .4byte ScrCmd_waitdooranim @ 0xae - .4byte ScrCmd_setdooropen @ 0xaf - .4byte ScrCmd_setdoorclosed @ 0xb0 - .4byte ScrCmd_addelevmenuitem @ 0xb1 - .4byte ScrCmd_showelevmenu @ 0xb2 - .4byte ScrCmd_checkcoins @ 0xb3 - .4byte ScrCmd_addcoins @ 0xb4 - .4byte ScrCmd_removecoins @ 0xb5 - .4byte ScrCmd_setwildbattle @ 0xb6 - .4byte ScrCmd_dowildbattle @ 0xb7 - .4byte ScrCmd_setvaddress @ 0xb8 - .4byte ScrCmd_vgoto @ 0xb9 - .4byte ScrCmd_vcall @ 0xba - .4byte ScrCmd_vgoto_if @ 0xbb - .4byte ScrCmd_vcall_if @ 0xbc - .4byte ScrCmd_vmessage @ 0xbd - .4byte ScrCmd_vbuffermessage @ 0xbe - .4byte ScrCmd_vbufferstring @ 0xbf - .4byte ScrCmd_showcoinsbox @ 0xc0 - .4byte ScrCmd_hidecoinsbox @ 0xc1 - .4byte ScrCmd_updatecoinsbox @ 0xc2 - .4byte ScrCmd_incrementgamestat @ 0xc3 - .4byte ScrCmd_setescapewarp @ 0xc4 - .4byte ScrCmd_waitmoncry @ 0xc5 - .4byte ScrCmd_bufferboxname @ 0xc6 - .4byte ScrCmd_nop1 @ 0xc7 - .4byte ScrCmd_nop1 @ 0xc8 - .4byte ScrCmd_nop1 @ 0xc9 - .4byte ScrCmd_nop1 @ 0xca - .4byte ScrCmd_nop1 @ 0xcb - .4byte ScrCmd_nop1 @ 0xcc - .4byte ScrCmd_setmodernfatefulencounter @ 0xcd - .4byte ScrCmd_checkmodernfatefulencounter @ 0xce - .4byte ScrCmd_trywondercardscript @ 0xcf - .4byte ScrCmd_nop1 @ 0xd0 - .4byte ScrCmd_warpspinenter @ 0xd1 - .4byte ScrCmd_setmonmetlocation @ 0xd2 - .4byte ScrCmd_moverotatingtileobjects @ 0xd3 - .4byte ScrCmd_turnrotatingtileobjects @ 0xd4 - .4byte ScrCmd_initrotatingtilepuzzle @ 0xd5 - .4byte ScrCmd_freerotatingtilepuzzle @ 0xd6 - .4byte ScrCmd_warpmossdeepgym @ 0xd7 - .4byte ScrCmd_selectapproachingtrainer @ 0xd8 - .4byte ScrCmd_lockfortrainer @ 0xd9 - .4byte ScrCmd_closebraillemessage @ 0xda - .4byte ScrCmd_messageinstant @ 0xdb - .4byte ScrCmd_fadescreenswapbuffers @ 0xdc - .4byte ScrCmd_buffertrainerclassname @ 0xdd - .4byte ScrCmd_buffertrainername @ 0xde - .4byte ScrCmd_pokenavcall @ 0xdf - .4byte ScrCmd_warpwhitefade @ 0xe0 - .4byte ScrCmd_buffercontestname @ 0xe1 - .4byte ScrCmd_bufferitemnameplural @ 0xe2 - .4byte ScrCmd_dynmultichoice @ 0xe3 - .4byte ScrCmd_dynmultipush @ 0xe4 + cmd ScrCmd_nop, requests_effects=1 @ 0x00 + cmd ScrCmd_nop1, requests_effects=1 @ 0x01 + cmd ScrCmd_end, requests_effects=1 @ 0x02 + cmd ScrCmd_return, requests_effects=1 @ 0x03 + cmd ScrCmd_call, requests_effects=1 @ 0x04 + cmd ScrCmd_goto, requests_effects=1 @ 0x05 + cmd ScrCmd_goto_if, requests_effects=1 @ 0x06 + cmd ScrCmd_call_if, requests_effects=1 @ 0x07 + cmd ScrCmd_gotostd, requests_effects=1 @ 0x08 + cmd ScrCmd_callstd, requests_effects=1 @ 0x09 + cmd ScrCmd_gotostd_if, requests_effects=1 @ 0x0a + cmd ScrCmd_callstd_if, requests_effects=1 @ 0x0b + cmd ScrCmd_returnram, requests_effects=1 @ 0x0c + cmd ScrCmd_endram, requests_effects=1 @ 0x0d + cmd ScrCmd_setmysteryeventstatus, requests_effects=1 @ 0x0e + cmd ScrCmd_loadword, requests_effects=1 @ 0x0f + cmd ScrCmd_loadbyte, requests_effects=1 @ 0x10 + cmd ScrCmd_setptr, requests_effects=1 @ 0x11 + cmd ScrCmd_loadbytefromptr, requests_effects=1 @ 0x12 + cmd ScrCmd_setptrbyte, requests_effects=1 @ 0x13 + cmd ScrCmd_copylocal, requests_effects=1 @ 0x14 + cmd ScrCmd_copybyte, requests_effects=1 @ 0x15 + cmd ScrCmd_setvar, requests_effects=1 @ 0x16 + cmd ScrCmd_addvar, requests_effects=1 @ 0x17 + cmd ScrCmd_subvar, requests_effects=1 @ 0x18 + cmd ScrCmd_copyvar, requests_effects=1 @ 0x19 + cmd ScrCmd_setorcopyvar, requests_effects=1 @ 0x1a + cmd ScrCmd_compare_local_to_local, requests_effects=1 @ 0x1b + cmd ScrCmd_compare_local_to_value, requests_effects=1 @ 0x1c + cmd ScrCmd_compare_local_to_ptr, requests_effects=1 @ 0x1d + cmd ScrCmd_compare_ptr_to_local, requests_effects=1 @ 0x1e + cmd ScrCmd_compare_ptr_to_value, requests_effects=1 @ 0x1f + cmd ScrCmd_compare_ptr_to_ptr, requests_effects=1 @ 0x20 + cmd ScrCmd_compare_var_to_value, requests_effects=1 @ 0x21 + cmd ScrCmd_compare_var_to_var, requests_effects=1 @ 0x22 + cmd ScrCmd_callnative, requests_effects=1 @ 0x23 + cmd ScrCmd_gotonative, requests_effects=1 @ 0x24 + cmd ScrCmd_special, requests_effects=1 @ 0x25 + cmd ScrCmd_specialvar, requests_effects=1 @ 0x26 + cmd ScrCmd_waitstate, requests_effects=1 @ 0x27 + cmd ScrCmd_delay, requests_effects=1 @ 0x28 + cmd ScrCmd_setflag, requests_effects=1 @ 0x29 + cmd ScrCmd_clearflag, requests_effects=1 @ 0x2a + cmd ScrCmd_checkflag, requests_effects=1 @ 0x2b + cmd ScrCmd_initclock, requests_effects=1 @ 0x2c + cmd ScrCmd_dotimebasedevents, requests_effects=1 @ 0x2d + cmd ScrCmd_gettime, requests_effects=1 @ 0x2e + cmd ScrCmd_playse, requests_effects=1 @ 0x2f + cmd ScrCmd_waitse, requests_effects=1 @ 0x30 + cmd ScrCmd_playfanfare, requests_effects=1 @ 0x31 + cmd ScrCmd_waitfanfare, requests_effects=1 @ 0x32 + cmd ScrCmd_playbgm, requests_effects=1 @ 0x33 + cmd ScrCmd_savebgm, requests_effects=1 @ 0x34 + cmd ScrCmd_fadedefaultbgm, requests_effects=1 @ 0x35 + cmd ScrCmd_fadenewbgm, requests_effects=1 @ 0x36 + cmd ScrCmd_fadeoutbgm, requests_effects=1 @ 0x37 + cmd ScrCmd_fadeinbgm, requests_effects=1 @ 0x38 + cmd ScrCmd_warp, requests_effects=1 @ 0x39 + cmd ScrCmd_warpsilent, requests_effects=1 @ 0x3a + cmd ScrCmd_warpdoor, requests_effects=1 @ 0x3b + cmd ScrCmd_warphole, requests_effects=1 @ 0x3c + cmd ScrCmd_warpteleport, requests_effects=1 @ 0x3d + cmd ScrCmd_setwarp, requests_effects=1 @ 0x3e + cmd ScrCmd_setdynamicwarp, requests_effects=1 @ 0x3f + cmd ScrCmd_setdivewarp, requests_effects=1 @ 0x40 + cmd ScrCmd_setholewarp, requests_effects=1 @ 0x41 + cmd ScrCmd_getplayerxy, requests_effects=1 @ 0x42 + cmd ScrCmd_getpartysize, requests_effects=1 @ 0x43 + cmd ScrCmd_additem, requests_effects=1 @ 0x44 + cmd ScrCmd_removeitem, requests_effects=1 @ 0x45 + cmd ScrCmd_checkitemspace, requests_effects=1 @ 0x46 + cmd ScrCmd_checkitem, requests_effects=1 @ 0x47 + cmd ScrCmd_checkitemtype, requests_effects=1 @ 0x48 + cmd ScrCmd_addpcitem, requests_effects=1 @ 0x49 + cmd ScrCmd_checkpcitem, requests_effects=1 @ 0x4a + cmd ScrCmd_adddecoration, requests_effects=1 @ 0x4b + cmd ScrCmd_removedecoration, requests_effects=1 @ 0x4c + cmd ScrCmd_checkdecor, requests_effects=1 @ 0x4d + cmd ScrCmd_checkdecorspace, requests_effects=1 @ 0x4e + cmd ScrCmd_applymovement, requests_effects=1 @ 0x4f + cmd ScrCmd_applymovementat, requests_effects=1 @ 0x50 + cmd ScrCmd_waitmovement, requests_effects=1 @ 0x51 + cmd ScrCmd_waitmovementat, requests_effects=1 @ 0x52 + cmd ScrCmd_removeobject, requests_effects=1 @ 0x53 + cmd ScrCmd_removeobjectat, requests_effects=1 @ 0x54 + cmd ScrCmd_addobject, requests_effects=1 @ 0x55 + cmd ScrCmd_addobjectat, requests_effects=1 @ 0x56 + cmd ScrCmd_setobjectxy, requests_effects=1 @ 0x57 + cmd ScrCmd_showobjectat, requests_effects=1 @ 0x58 + cmd ScrCmd_hideobjectat, requests_effects=1 @ 0x59 + cmd ScrCmd_faceplayer, requests_effects=1 @ 0x5a + cmd ScrCmd_turnobject, requests_effects=1 @ 0x5b + cmd ScrCmd_trainerbattle, requests_effects=1 @ 0x5c + cmd ScrCmd_dotrainerbattle, requests_effects=1 @ 0x5d + cmd ScrCmd_gotopostbattlescript, requests_effects=1 @ 0x5e + cmd ScrCmd_gotobeatenscript, requests_effects=1 @ 0x5f + cmd ScrCmd_checktrainerflag, requests_effects=1 @ 0x60 + cmd ScrCmd_settrainerflag, requests_effects=1 @ 0x61 + cmd ScrCmd_cleartrainerflag, requests_effects=1 @ 0x62 + cmd ScrCmd_setobjectxyperm, requests_effects=1 @ 0x63 + cmd ScrCmd_copyobjectxytoperm, requests_effects=1 @ 0x64 + cmd ScrCmd_setobjectmovementtype, requests_effects=1 @ 0x65 + cmd ScrCmd_waitmessage, requests_effects=1 @ 0x66 + cmd ScrCmd_message, requests_effects=1 @ 0x67 + cmd ScrCmd_closemessage, requests_effects=1 @ 0x68 + cmd ScrCmd_lockall, requests_effects=1 @ 0x69 + cmd ScrCmd_lock, requests_effects=1 @ 0x6a + cmd ScrCmd_releaseall, requests_effects=1 @ 0x6b + cmd ScrCmd_release, requests_effects=1 @ 0x6c + cmd ScrCmd_waitbuttonpress, requests_effects=1 @ 0x6d + cmd ScrCmd_yesnobox, requests_effects=1 @ 0x6e + cmd ScrCmd_multichoice, requests_effects=1 @ 0x6f + cmd ScrCmd_multichoicedefault, requests_effects=1 @ 0x70 + cmd ScrCmd_multichoicegrid, requests_effects=1 @ 0x71 + cmd ScrCmd_drawbox, requests_effects=1 @ 0x72 + cmd ScrCmd_erasebox, requests_effects=1 @ 0x73 + cmd ScrCmd_drawboxtext, requests_effects=1 @ 0x74 + cmd ScrCmd_showmonpic, requests_effects=1 @ 0x75 + cmd ScrCmd_hidemonpic, requests_effects=1 @ 0x76 + cmd ScrCmd_showcontestpainting, requests_effects=1 @ 0x77 + cmd ScrCmd_braillemessage, requests_effects=1 @ 0x78 + cmd ScrCmd_nop1, requests_effects=1 @ 0x79 + cmd ScrCmd_giveegg, requests_effects=1 @ 0x7a + cmd ScrCmd_setmonmove, requests_effects=1 @ 0x7b + cmd ScrCmd_checkpartymove, requests_effects=1 @ 0x7c + cmd ScrCmd_bufferspeciesname, requests_effects=1 @ 0x7d + cmd ScrCmd_bufferleadmonspeciesname, requests_effects=1 @ 0x7e + cmd ScrCmd_bufferpartymonnick, requests_effects=1 @ 0x7f + cmd ScrCmd_bufferitemname, requests_effects=1 @ 0x80 + cmd ScrCmd_bufferdecorationname, requests_effects=1 @ 0x81 + cmd ScrCmd_buffermovename, requests_effects=1 @ 0x82 + cmd ScrCmd_buffernumberstring, requests_effects=1 @ 0x83 + cmd ScrCmd_bufferstdstring, requests_effects=1 @ 0x84 + cmd ScrCmd_bufferstring, requests_effects=1 @ 0x85 + cmd ScrCmd_pokemart, requests_effects=1 @ 0x86 + cmd ScrCmd_pokemartdecoration, requests_effects=1 @ 0x87 + cmd ScrCmd_pokemartdecoration2, requests_effects=1 @ 0x88 + cmd ScrCmd_playslotmachine, requests_effects=1 @ 0x89 + cmd ScrCmd_setberrytree, requests_effects=1 @ 0x8a + cmd ScrCmd_choosecontestmon, requests_effects=1 @ 0x8b + cmd ScrCmd_startcontest, requests_effects=1 @ 0x8c + cmd ScrCmd_showcontestresults, requests_effects=1 @ 0x8d + cmd ScrCmd_contestlinktransfer, requests_effects=1 @ 0x8e + cmd ScrCmd_random, requests_effects=1 @ 0x8f + cmd ScrCmd_addmoney, requests_effects=1 @ 0x90 + cmd ScrCmd_removemoney, requests_effects=1 @ 0x91 + cmd ScrCmd_checkmoney, requests_effects=1 @ 0x92 + cmd ScrCmd_showmoneybox, requests_effects=1 @ 0x93 + cmd ScrCmd_hidemoneybox, requests_effects=1 @ 0x94 + cmd ScrCmd_updatemoneybox, requests_effects=1 @ 0x95 + cmd ScrCmd_getpokenewsactive, requests_effects=1 @ 0x96 + cmd ScrCmd_fadescreen, requests_effects=1 @ 0x97 + cmd ScrCmd_fadescreenspeed, requests_effects=1 @ 0x98 + cmd ScrCmd_setflashlevel, requests_effects=1 @ 0x99 + cmd ScrCmd_animateflash, requests_effects=1 @ 0x9a + cmd ScrCmd_messageautoscroll, requests_effects=1 @ 0x9b + cmd ScrCmd_dofieldeffect, requests_effects=1 @ 0x9c + cmd ScrCmd_setfieldeffectargument, requests_effects=1 @ 0x9d + cmd ScrCmd_waitfieldeffect, requests_effects=1 @ 0x9e + cmd ScrCmd_setrespawn, requests_effects=1 @ 0x9f + cmd ScrCmd_checkplayergender, requests_effects=1 @ 0xa0 + cmd ScrCmd_playmoncry, requests_effects=1 @ 0xa1 + cmd ScrCmd_setmetatile, requests_effects=1 @ 0xa2 + cmd ScrCmd_resetweather, requests_effects=1 @ 0xa3 + cmd ScrCmd_setweather, requests_effects=1 @ 0xa4 + cmd ScrCmd_doweather, requests_effects=1 @ 0xa5 + cmd ScrCmd_setstepcallback, requests_effects=1 @ 0xa6 + cmd ScrCmd_setmaplayoutindex, requests_effects=1 @ 0xa7 + cmd ScrCmd_setobjectsubpriority, requests_effects=1 @ 0xa8 + cmd ScrCmd_resetobjectsubpriority, requests_effects=1 @ 0xa9 + cmd ScrCmd_createvobject, requests_effects=1 @ 0xaa + cmd ScrCmd_turnvobject, requests_effects=1 @ 0xab + cmd ScrCmd_opendoor, requests_effects=1 @ 0xac + cmd ScrCmd_closedoor, requests_effects=1 @ 0xad + cmd ScrCmd_waitdooranim, requests_effects=1 @ 0xae + cmd ScrCmd_setdooropen, requests_effects=1 @ 0xaf + cmd ScrCmd_setdoorclosed, requests_effects=1 @ 0xb0 + cmd ScrCmd_addelevmenuitem, requests_effects=1 @ 0xb1 + cmd ScrCmd_showelevmenu, requests_effects=1 @ 0xb2 + cmd ScrCmd_checkcoins, requests_effects=1 @ 0xb3 + cmd ScrCmd_addcoins, requests_effects=1 @ 0xb4 + cmd ScrCmd_removecoins, requests_effects=1 @ 0xb5 + cmd ScrCmd_setwildbattle, requests_effects=1 @ 0xb6 + cmd ScrCmd_dowildbattle, requests_effects=1 @ 0xb7 + cmd ScrCmd_setvaddress, requests_effects=1 @ 0xb8 + cmd ScrCmd_vgoto, requests_effects=1 @ 0xb9 + cmd ScrCmd_vcall, requests_effects=1 @ 0xba + cmd ScrCmd_vgoto_if, requests_effects=1 @ 0xbb + cmd ScrCmd_vcall_if, requests_effects=1 @ 0xbc + cmd ScrCmd_vmessage, requests_effects=1 @ 0xbd + cmd ScrCmd_vbuffermessage, requests_effects=1 @ 0xbe + cmd ScrCmd_vbufferstring, requests_effects=1 @ 0xbf + cmd ScrCmd_showcoinsbox, requests_effects=1 @ 0xc0 + cmd ScrCmd_hidecoinsbox, requests_effects=1 @ 0xc1 + cmd ScrCmd_updatecoinsbox, requests_effects=1 @ 0xc2 + cmd ScrCmd_incrementgamestat, requests_effects=1 @ 0xc3 + cmd ScrCmd_setescapewarp, requests_effects=1 @ 0xc4 + cmd ScrCmd_waitmoncry, requests_effects=1 @ 0xc5 + cmd ScrCmd_bufferboxname, requests_effects=1 @ 0xc6 + cmd ScrCmd_nop1, requests_effects=1 @ 0xc7 + cmd ScrCmd_nop1, requests_effects=1 @ 0xc8 + cmd ScrCmd_nop1, requests_effects=1 @ 0xc9 + cmd ScrCmd_nop1, requests_effects=1 @ 0xca + cmd ScrCmd_nop1, requests_effects=1 @ 0xcb + cmd ScrCmd_nop1, requests_effects=1 @ 0xcc + cmd ScrCmd_setmodernfatefulencounter, requests_effects=1 @ 0xcd + cmd ScrCmd_checkmodernfatefulencounter, requests_effects=1 @ 0xce + cmd ScrCmd_trywondercardscript, requests_effects=1 @ 0xcf + cmd ScrCmd_nop1, requests_effects=1 @ 0xd0 + cmd ScrCmd_warpspinenter, requests_effects=1 @ 0xd1 + cmd ScrCmd_setmonmetlocation, requests_effects=1 @ 0xd2 + cmd ScrCmd_moverotatingtileobjects, requests_effects=1 @ 0xd3 + cmd ScrCmd_turnrotatingtileobjects, requests_effects=1 @ 0xd4 + cmd ScrCmd_initrotatingtilepuzzle, requests_effects=1 @ 0xd5 + cmd ScrCmd_freerotatingtilepuzzle, requests_effects=1 @ 0xd6 + cmd ScrCmd_warpmossdeepgym, requests_effects=1 @ 0xd7 + cmd ScrCmd_selectapproachingtrainer, requests_effects=1 @ 0xd8 + cmd ScrCmd_lockfortrainer, requests_effects=1 @ 0xd9 + cmd ScrCmd_closebraillemessage, requests_effects=1 @ 0xda + cmd ScrCmd_messageinstant, requests_effects=1 @ 0xdb + cmd ScrCmd_fadescreenswapbuffers, requests_effects=1 @ 0xdc + cmd ScrCmd_buffertrainerclassname, requests_effects=1 @ 0xdd + cmd ScrCmd_buffertrainername, requests_effects=1 @ 0xde + cmd ScrCmd_pokenavcall, requests_effects=1 @ 0xdf + cmd ScrCmd_warpwhitefade, requests_effects=1 @ 0xe0 + cmd ScrCmd_buffercontestname, requests_effects=1 @ 0xe1 + cmd ScrCmd_bufferitemnameplural, requests_effects=1 @ 0xe2 + cmd ScrCmd_dynmultichoice, requests_effects=1 @ 0xe3 + cmd ScrCmd_dynmultipush, requests_effects=1 @ 0xe4 gScriptCmdTableEnd:: .4byte ScrCmd_nop diff --git a/data/scripts/dexnav.inc b/data/scripts/dexnav.inc new file mode 100644 index 000000000000..698f5019360c --- /dev/null +++ b/data/scripts/dexnav.inc @@ -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!$" diff --git a/data/scripts/field_move_scripts.inc b/data/scripts/field_move_scripts.inc index 0a7660b4cee6..f1bd3618e18e 100644 --- a/data/scripts/field_move_scripts.inc +++ b/data/scripts/field_move_scripts.inc @@ -385,6 +385,18 @@ EventScript_UseDig:: lockall goto EventScript_DigCommon + +EventScript_CutGrassCommon: + isfollowerfieldmoveuser VAR_0x8004 + setfieldeffectargument 3, VAR_0x8004 @ skip pose if true + dofieldeffect FLDEFF_USE_CUT_ON_GRASS + waitstate + +@ Use Cut grass from party menu +EventScript_UseCutGrass:: + lockall + goto EventScript_CutGrassCommon + Text_CantDive: .string "The sea is deep here. A POKéMON\n" .string "may be able to go underwater.$" diff --git a/data/scripts/trainer_script.inc b/data/scripts/trainer_script.inc index c0998aef8e34..aad79334ab63 100644 --- a/data/scripts/trainer_script.inc +++ b/data/scripts/trainer_script.inc @@ -20,3 +20,9 @@ EventScript_GotoTrainerScript:: gotobeatenscript releaseall end + +EventScript_ObjectApproachPlayer:: + lock + special DoTrainerApproach + waitstate + gotonative LoadTrainerObjectScript diff --git a/data/specials.inc b/data/specials.inc index 4d2bea3d33f4..9bf373449123 100644 --- a/data/specials.inc +++ b/data/specials.inc @@ -1,9 +1,16 @@ -.macro def_special ptr +@ 'requests_effects' should be set to 1 if the special contains a call +@ to 'Script_RequestEffects', which allows it to be analyzed with +@ 'RunScriptImmediatelyUntilEffect'. +.macro def_special ptr:req, requests_effects=0 .global SPECIAL_\ptr .set SPECIAL_\ptr, __special__ .set __special__, __special__ + 1 + .if \requests_effects == 0 .4byte \ptr - .endm + .else + .4byte \ptr + ROM_SIZE + .endif +.endm .set __special__, 0 .align 2 @@ -297,7 +304,7 @@ gSpecials:: def_special WaitWeather def_special BufferEReaderTrainerName def_special GetSlotMachineId - def_special GetPlayerFacingDirection + def_special GetPlayerFacingDirection, requests_effects=TRUE def_special FoundAbandonedShipRoom1Key def_special FoundAbandonedShipRoom2Key def_special FoundAbandonedShipRoom4Key diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 21584f3ad758..fb10d5b26598 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -20,6 +20,7 @@ - [How to use the Testing System](tutorials/how_to_testing_system.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) @@ -68,4 +69,5 @@ - [Version 0.9.0](changelogs/0.9.x/0.9.0.md) - [Team Procedures]() - [How to make an Expansion version](team_procedures/expansion_versions.md) - - [Scope Guidelines](scope.md) + - [Release Schedule and Process](team_procedures/schedule.md) + - [Scope Guidelines](team_procedures/scope.md) diff --git a/docs/changelogs/1.10.x/1.10.1.md b/docs/changelogs/1.10.x/1.10.1.md new file mode 100644 index 000000000000..4eb4ea8e0dc2 --- /dev/null +++ b/docs/changelogs/1.10.x/1.10.1.md @@ -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 + + + diff --git a/docs/install/windows/WSL.md b/docs/install/windows/WSL.md index 9534966488e4..a5dcbb4bbc8c 100644 --- a/docs/install/windows/WSL.md +++ b/docs/install/windows/WSL.md @@ -12,13 +12,13 @@ If you want the best performance and least amount of issues with Windows interfe 2. Once the process finishes, restart your machine. ### WSL1 -3a. Open Windows Powershell **as Administrator** again (after restarting), and run the following command to configure Ubuntu to use WSL1. +3. Open Windows Powershell **as Administrator** again (after restarting), and run the following command to configure Ubuntu to use WSL1. ```powershell wsl --set-version Ubuntu 1 ``` ### WSL2 -3a. Open Windows Powershell **as Administrator** again (after restarting), and run the following command to configure Ubuntu to use WSL2. +3. Open Windows Powershell **as Administrator** again (after restarting), and run the following command to configure Ubuntu to use WSL2. ```powershell wsl --set-version Ubuntu 2 diff --git a/docs/scope.md b/docs/scope.md deleted file mode 100644 index 1bec4f2db7a2..000000000000 --- a/docs/scope.md +++ /dev/null @@ -1,54 +0,0 @@ -# Document Purpose - -This document is a guide for contributors and Senate to decide if a feature is within "scope" for pokeemerald-expansion. If a feature is not in scope, then it should not be merged. Even if an opened PR is within scope, this does not mean it will be merged, as acceptance criteria will often come down to the details of the implementation. - -# Definitions - -* **Showdown Supported (SS)**: A core series game who's metagame can be played on Showdown. - * Notably, this is every [core series game](https://bulbapedia.bulbagarden.net/wiki/Core_series#List_of_core_series_games) except Pokémon Legends: Arceus. -* **Base Expansion Version**: "A .gba file built from an unmodified `master` or `upcoming` branch of `pokeemerald-expansion`. -* **Vanilla Emerald Version**: A .gba file built from an unmodified `master` branch of pret's `pokeemerald`. - -# Guidelines - -A pull request meets the scope criteria if: -* The feature does not belong to a category considered “not in scope” AND -* The feature belongs to a category considered “in scope” - -## In Scope Categories - -1. **SS Species:** Adds Species that have appeared in a Showdown-supported title -2. **SS Moves:** Adds Moves and Move Animations that have appeared in a Showdown-supported title -3. **SS Abilities:** Adds Abilities that have appeared in a Showdown-supported title -4. **SS Items:** Adds Items that have appeared in a Showdown-supported title -5. **SS Gimmicks:** Adds Gimmicks that have appeared in a Showdown-supported title -6. **SS Battle Types:** Adds Special Battle Types that have appeared in a Showdown-supported title -7. **SS Battle Mechanics:** Adds mechanical battle changes that have appeared in a Showdown-supported title -8. **Improve Battle AI:** Improve the Battle AI in a way that allows it to approach the skill and capability of a human competitive player -9. **Base Link Compatibility:** Link compatibility with base -10. **SS Overworld / Menu Updates:** Replicate overworld or menu changes from Showdown-supported Pokémon titles -11. **Speed Up:** Speed up the player experience of features found in base -12. **Compression:** Automatically compress assets -13. **Novel Experience:** Adds a novel experience included in another Showdown Supported title -15. **Helper Features:** Eases the addition or inclusion of any of the aforementioned - -## Not In Scope Categories - -1. **Non-SS Species**: Adds Species that have NOT appeared in a Showdown-supported title -2. **Non-SS Moves**: Adds Moves and Move Animations that have NOT appeared in a Showdown-supported title -3. **Non-SS Abilities**: Adds Abilities that have NOT appeared in a Showdown-supported title -4. **Non-SS Items**: Adds Items that have NOT appeared in a Showdown-supported title -5. **Non-SS Gimmicks**: Adds Gimmicks that have NOT appeared in a Showdown-supported title -6. **Non-SS Battle Types**: Adds Special Battle Types that have NOT appeared in a Showdown-supported title -7. **Duplicate Feature UI**: Adds functionality that duplicates the core functionality of an existing vanilla feature -8. **Vanilla Link Compatibility**: Link compatibility with vanilla - -## Discussion Required Categories - -Pull Requests that fall into this category should be brought up to maintainers, who will discuss and vote as to whether or not the feature is considered in scope. Considerations for acceptance may include invasiveness of implementation, popularity, ease of maintenance, etc. - -1. **Developer Ease of Use:** Lowers barrier of entry for developers to use existing behavior -2. **Fangame Features:** Adds a popular feature from other fangames -3. **Popular Non-SS Features:** Exceptions can be made for uniquely popular or requested features (Drowsy, PLA Legend Plate, etc.) -4. **External Program**: External programs like poryscript, porymoves, etc. - diff --git a/docs/team_procedures/schedule.md b/docs/team_procedures/schedule.md new file mode 100644 index 000000000000..c23d8a51050b --- /dev/null +++ b/docs/team_procedures/schedule.md @@ -0,0 +1,51 @@ +# Release Schedule and Process + +## Version Lifecycle + +### Minor Release (90 days to next Minor Release) +`upcoming` and `master` are synchronized. Minor Release should occur once every three months. Maintainers can vote to do extra Minor Releases for special cases, but this should be considered highly irregular. + +### Patch Release (60 / 30 days to the next Minor Release) +Releases that focus primarily on bugfixes or improvements to the test system. Patch Releases should occur AT LEAST once a month, but can be more frequent than that. + +### Big Feature Freeze (30 days to the next Minor Release) +PRs with the Github label [`type: big feature`](https://github.com/rh-hideout/pokeemerald-expansion/issues?q=sort%3Aupdated-desc+is%3Aopen+label%3A%22type%3A+big+feature%22) will NOT be merged until after the next Minor Release. + +### Merge Freeze (14 days to the next Minor Release) +PRs that DO NOT have the Github labels [`bugfix`](https://github.com/rh-hideout/pokeemerald-expansion/issues?q=sort%3Aupdated-desc+label%3Abugfix) or [`type: cleanup`](https://github.com/rh-hideout/pokeemerald-expansion/issues?q=sort%3Aupdated-desc+label%3A%22type%3A+cleanup%22+) will NOT be merged until after the next Minor Release. + + +### Sample Schedule +| Major | Minor | Patch | Type | Goal Date | +| ----- | ----- | ----- | ------------------ | ----------- | +| 2 | 1 | 0 | Minor | Dec 1 2025 | +| 2 | 1 | 1 | Patch | Dec 31 2025 | +| 2 | 1 | 2 | Patch | Jan 30 2026 | +| 2 | 1 | 2 | Big Feature Freeze | Jan 30 2026 | +| 2 | 1 | 2 | Merge Freeze | Feb 15 2026 | +| 2 | 1 | 3 | Patch | Mar 1 2026 | +| 2 | 2 | 0 | Minor | Mar 1 2026 | + +--- + +## What is a "Big Feature"? +* If the original owner of the PR thinks a feature should be labeled a Big Feature, it is, no questions asked +* If a reviewer thinks a PR is a Big Feature, then it is +* If the two disagree, it can be discussed in a PR thread, and can ultimately be resolved with a Maintainer vote. + +### How To Identify a Big Feature +* **Big diffs**: It's easy for something to go unnoticed in review when it's a tiny part of a massive diff. +* **High-impact**: High-impact changes are harder to review because they often have consequences that aren't obvious to the reviewer. We catch these consequences from users who use upcoming reporting them. +* **Subjective**: Subjective changes are more likely to have differences of opinions between senate members. +* **Pervasive**: The PR touches several different parts of the codebase or is involved in several different parts of the codebase, even if those elements are small. + +--- + +## Release Blocking and Milestones +When an issue or PR is assigned to a [milestone on Github](https://github.com/rh-hideout/pokeemerald-expansion/milestones) by a Maintainer, that means it is "Blocking". If another Maintainer agrees with this, then that version cannot be released until that issue is resolved or PR is merged. + +This designation should be reserved for instances where an existing feature on `upcoming` or `master` is broken and causing problems for users or players. + +Blocking issues or PRs can be deferred to future releases but should be discussed with the Maintainers that assigned the designation in the first place. + +If a version's milestone does not have any issues or PRs assigned to it, that version should be [released](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/docs/team_procedures/expansion_versions.md) as close to the goal date as possible. diff --git a/docs/team_procedures/scope.md b/docs/team_procedures/scope.md new file mode 100644 index 000000000000..e3c736c1cce7 --- /dev/null +++ b/docs/team_procedures/scope.md @@ -0,0 +1,69 @@ +# Document Purpose + +This document is a guide for contributors and Senate to decide if a feature is within "scope" for pokeemerald-expansion. "Scope" in this case comprises a list of features and concepts that could be merged if an appropriate implementation is submitted. If a feature is not in scope, then it should not be merged. Even if an opened PR is within scope, this does not mean it will be merged, as acceptance criteria will often come down to the details of the implementation. + +# Definitions + +* **Showdown Supported (SS)**: A core series game who's metagame can be played on Showdown. + * Includes every [core series game](https://bulbapedia.bulbagarden.net/wiki/Core_series#List_of_core_series_games) except Pokémon Legends: Arceus. + * Does not include [spin-off games](https://bulbapedia.bulbagarden.net/wiki/Spin-off_Pokémon_games) such as Pokémon Colosseum, Pokémon XD, Pokémon Trozei!, etc. +* **Base Expansion Version**: "A .gba file built from an unmodified `master` or `upcoming` branch of `pokeemerald-expansion`. +* **Vanilla Emerald Version**: A .gba file built from an unmodified `master` branch of pret's `pokeemerald`. + +# Guidelines + +A pull request meets the scope criteria if: +* The feature does not belong to a category considered “not in scope” AND +* The feature belongs to a category considered “in scope” + +## In Scope Categories + +1. **SS Species**: Adds Species that have appeared in a Showdown-supported title. Includes follower sprites for all defined species including battle-only ones (ie. Megas) +2. **SS Moves**: Adds Moves and Move Animations that have appeared in a Showdown-supported title +3. **SS Abilities**: Adds Abilities that have appeared in a Showdown-supported title +4. **SS Items**: Adds Items that have appeared in a Showdown-supported title +5. **SS Gimmicks**: Adds Gimmicks that have appeared in a Showdown-supported title (Dynamax, Mega Evolution, etc.) +6. **SS Battle Types**: Adds Special Battle Types that have appeared in a Showdown-supported title (Triple battles, etc.) +7. **SS Battle Mechanics**: Adds mechanical battle changes that have appeared in a Showdown-supported title, and allow developers to choose which generation suits them where applicable +8. **Battle AI Behaviour**: Improvements towards the capability of a human competitive player, and unique or interesting behaviours otherwise +9. **Base Link Compatibility**: The ability for two Base Expansion Version's to connect, trade, and battle one another +10. **SS Overworld Features**: Add overworld changes / additions from Showdown-supported Pokémon titles (followers, raids, sideways stairs, etc.) +11. **SS Menu Features**: Add menu changes / additions from Showdown-supported Pokémon titles (type effectivness indicator, PC functions, etc.) +12. **Speed Up**: Optimize code to run more efficiently, take up less space, and work better overall to improves the developer and / or player experience +13. **Compression**: Reduces the size of graphic or sound assets, etc. Includes automatic compression +14. **Novel Experience**: Adds a novel experience included in another Showdown Supported title (poffins, fishing minigames, etc.) +15. **Helper Features**: Eases the addition or inclusion of any of the aforementioned, or facilitates developer ease of use + +## Not In Scope Categories + +1. **Non-SS Species**: Adds Species that have NOT appeared in a Showdown-supported title (Fakemon, CAP Pokémon, etc.) +2. **Non-SS Moves**: Adds Moves and Move Animations that have NOT appeared in a Showdown-supported title +3. **Non-SS Abilities**: Adds Abilities that have NOT appeared in a Showdown-supported title +4. **Non-SS Items**: Adds Items that have NOT appeared in a Showdown-supported title +5. **Non-SS Gimmicks**: Adds Gimmicks that have NOT appeared in a Showdown-supported title (Showdown's Other Metagames, etc.) +6. **Non-SS Battle Types**: Adds Special Battle Types that have NOT appeared in a Showdown-supported title +7. **Overworld Maps**: Adds overworld maps from either Showdown-supported titles or non-Showdown-supported titles +8. **Duplicate UIs**: Adds additional user interface that covers the same functionality of an existing feature (HGSS Pokédex, BW Summary Screen, etc.) +9. **Vanilla Link Compatibility**: The ability for Base Expansion Version and Vanilla Emerald Version to connect, trade, and battle one another + +## Discussion Required Categories + +Pull Requests that fall into this category are not in scope by default and should be brought up to maintainers, who will discuss and vote as to whether or not the feature is considered in scope. Considerations for acceptance may include invasiveness of implementation, popularity, ease of maintenance, etc. + +1. **Developer Ease of Use**: Lowers barrier of entry for developers to use existing behavior +2. **Fangame Features**: Adds a popular feature from other fangames +3. **Popular Non-SS Features**: Exceptions can be made for uniquely popular or requested features (Drowsy, PLA Legend Plate, etc.) +4. **External Program**: External programs like poryscript, porymoves, etc. + +## Workflow for Proposed Feature Scope Discussion +For the contributor: +- Make a thread for the feature on Discord +- Describe how the feature fits into this scope document, and why you feel it should be considered +- Optionally include either a draft PR or describe in some detail the proposed implementation. Non-mandatory, but implementation invasiveness, maintenance cost, etc. are major considerations, so use your judgement. The senate may ask for this information during discussion. + +For the senate: +- Make a senate thread for the discussion +- Make and pin a two-week voting poll +- Discuss, conclude, and cast votes before the two-week deadline +- Inform contributor as to the results and reasons in their thread +- Amend this scope document if necessary diff --git a/docs/tutorials/ai_flags.md b/docs/tutorials/ai_flags.md index fcad6ed34fc8..0d685f3e0a77 100644 --- a/docs/tutorials/ai_flags.md +++ b/docs/tutorials/ai_flags.md @@ -67,7 +67,7 @@ AI will generally behave more recklessly. This AI enables the following behaviou * Switch offensively mid battle rather than defensively (if using `AI_FLAG_SMART_MON_CHOICES`) * Prioritize Explosion moves -## `AI_FLAG_PREFER_STRONGEST_MOVE` +## `AI_FLAG_TRY_TO_2HKO` Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player. Keep in mind that this is a weaker form of `AI_FLAG_TRY_TO_FAINT` at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs. @@ -168,3 +168,6 @@ AI will always switch out after a KO in exactly party order as defined in the tr ## `AI_FLAG_WEIGH_ABILITY_PREDICTION` AI will predict the player's ability based to its aiRating. Without this flag the AI randomly assumes an ability with an even distribution between all possible abilities until one is confirmed. With this flag, it instead guesses proportionally to each ability's aiRating, making it far more likely to guess an ability like Water Absorb than Damp if both are options. + +## `AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE` +AI will add score to its highest damaging move, regardless of accuracy or secondary effects. Replaces deprecated `AI_FLAG_PREFER_STRONGEST_MOVE`. diff --git a/docs/tutorials/how_to_new_move.md b/docs/tutorials/how_to_new_move.md index 9ddc09b904b7..e3a2eb0a12a3 100644 --- a/docs/tutorials/how_to_new_move.md +++ b/docs/tutorials/how_to_new_move.md @@ -28,7 +28,7 @@ Let's look at an example: ```c [MOVE_THUNDER_SHOCK] = { - .name = HANDLE_EXPANDED_MOVE_NAME("ThunderShock", "Thunder Shock"), + .name = COMPOUND_STRING("Thunder Shock"), .description = COMPOUND_STRING( "An electrical attack that\n" "may paralyze the foe."), @@ -51,7 +51,7 @@ Let's look at an example: .contestComboMoves = {COMBO_STARTER_CHARGE}, }, ``` -The `HANDLE_EXPANDED_MOVE_NAME` allows the usage of a name of extended character length, so long as the `B_EXPANDED_MOVE_NAMES` is set to `TRUE`, whereas by default it's limited in Gen 3 to 12 characters. Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`. +Most of the fields here are obvious, but the two important ones for determining what a move actually *does* are `effect` and `additionalEffects`. The `effect` represents how the move actually works when called in battle - it can be a two turn move, or a move that only works if the target is holding an item, for example. How each effect works is pretty much unique, but the way a move of a particular effect is executed is defined by a script [`data/battle_scripts_1.s`](#databattle_scripts_1s), and any *variable* characteristics such as typing or power are defined in either [`src/battle_script_commands.c`](#srcbattle_script_commandsc) or [`src/battle_util.c`](#srcbattle_utilc), depending on the effect. The vast majority of non-status moves are simply `EFFECT_HIT`, in that they deal damage and apply `additionalEffects` (if defined). diff --git a/docs/tutorials/how_to_new_pokemon_1_10_0.md b/docs/tutorials/how_to_new_pokemon_1_10_0.md index f6eaedee9996..4d836fc7d3e5 100644 --- a/docs/tutorials/how_to_new_pokemon_1_10_0.md +++ b/docs/tutorials/how_to_new_pokemon_1_10_0.md @@ -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 diff --git a/docs/tutorials/how_to_new_pokemon_1_9_0.md b/docs/tutorials/how_to_new_pokemon_1_9_0.md index e64f8e6e667f..aad333287371 100644 --- a/docs/tutorials/how_to_new_pokemon_1_9_0.md +++ b/docs/tutorials/how_to_new_pokemon_1_9_0.md @@ -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 diff --git a/docs/tutorials/how_to_testing_system.md b/docs/tutorials/how_to_testing_system.md index c573dfbbf7f6..da11944e2502 100644 --- a/docs/tutorials/how_to_testing_system.md +++ b/docs/tutorials/how_to_testing_system.md @@ -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` diff --git a/graphics/dexnav/captured_all.png b/graphics/dexnav/captured_all.png new file mode 100644 index 000000000000..2ed8b40ca982 Binary files /dev/null and b/graphics/dexnav/captured_all.png differ diff --git a/graphics/dexnav/cursor.png b/graphics/dexnav/cursor.png new file mode 100644 index 000000000000..0b64cf95b870 Binary files /dev/null and b/graphics/dexnav/cursor.png differ diff --git a/graphics/dexnav/gui.pal b/graphics/dexnav/gui.pal new file mode 100644 index 000000000000..77939a5aba0b --- /dev/null +++ b/graphics/dexnav/gui.pal @@ -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 diff --git a/graphics/dexnav/gui_tilemap.bin b/graphics/dexnav/gui_tilemap.bin new file mode 100644 index 000000000000..0f62abbef9ce Binary files /dev/null and b/graphics/dexnav/gui_tilemap.bin differ diff --git a/graphics/dexnav/gui_tiles.png b/graphics/dexnav/gui_tiles.png new file mode 100644 index 000000000000..4e3327b8eee2 Binary files /dev/null and b/graphics/dexnav/gui_tiles.png differ diff --git a/graphics/dexnav/hidden.png b/graphics/dexnav/hidden.png new file mode 100644 index 000000000000..2ad2e22e08d0 Binary files /dev/null and b/graphics/dexnav/hidden.png differ diff --git a/graphics/dexnav/hidden_search.png b/graphics/dexnav/hidden_search.png new file mode 100644 index 000000000000..d462ddef9311 Binary files /dev/null and b/graphics/dexnav/hidden_search.png differ diff --git a/graphics/dexnav/no_data.png b/graphics/dexnav/no_data.png new file mode 100644 index 000000000000..a26515b5b17e Binary files /dev/null and b/graphics/dexnav/no_data.png differ diff --git a/graphics/dexnav/owned_icon.png b/graphics/dexnav/owned_icon.png new file mode 100644 index 000000000000..fdc5ef71130b Binary files /dev/null and b/graphics/dexnav/owned_icon.png differ diff --git a/graphics/dexnav/star.png b/graphics/dexnav/star.png new file mode 100644 index 000000000000..5d4b034a45fc Binary files /dev/null and b/graphics/dexnav/star.png differ diff --git a/graphics/dexnav/vision.png b/graphics/dexnav/vision.png new file mode 100644 index 000000000000..74b6a14eed3e Binary files /dev/null and b/graphics/dexnav/vision.png differ diff --git a/graphics/field_effects/palettes/cave_dust.pal b/graphics/field_effects/palettes/cave_dust.pal new file mode 100644 index 000000000000..ed31236c4e36 --- /dev/null +++ b/graphics/field_effects/palettes/cave_dust.pal @@ -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 diff --git a/graphics/field_effects/pics/cave_dust.png b/graphics/field_effects/pics/cave_dust.png new file mode 100644 index 000000000000..1f477c7803d4 Binary files /dev/null and b/graphics/field_effects/pics/cave_dust.png differ diff --git a/graphics/pokemon/furfrou/dandy_trim/anim_front.png b/graphics/pokemon/furfrou/dandy/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/anim_front.png rename to graphics/pokemon/furfrou/dandy/anim_front.png diff --git a/graphics/pokemon/furfrou/dandy_trim/back.png b/graphics/pokemon/furfrou/dandy/back.png similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/back.png rename to graphics/pokemon/furfrou/dandy/back.png diff --git a/graphics/pokemon/furfrou/dandy_trim/icon.png b/graphics/pokemon/furfrou/dandy/icon.png similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/icon.png rename to graphics/pokemon/furfrou/dandy/icon.png diff --git a/graphics/pokemon/furfrou/dandy_trim/normal.pal b/graphics/pokemon/furfrou/dandy/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/normal.pal rename to graphics/pokemon/furfrou/dandy/normal.pal diff --git a/graphics/pokemon/furfrou/dandy_trim/overworld.png b/graphics/pokemon/furfrou/dandy/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/overworld.png rename to graphics/pokemon/furfrou/dandy/overworld.png diff --git a/graphics/pokemon/furfrou/dandy_trim/overworld_normal.pal b/graphics/pokemon/furfrou/dandy/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/dandy/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/dandy_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/dandy/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/dandy/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/dandy_trim/shiny.pal b/graphics/pokemon/furfrou/dandy/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/dandy_trim/shiny.pal rename to graphics/pokemon/furfrou/dandy/shiny.pal diff --git a/graphics/pokemon/furfrou/debutante_trim/anim_front.png b/graphics/pokemon/furfrou/debutante/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/anim_front.png rename to graphics/pokemon/furfrou/debutante/anim_front.png diff --git a/graphics/pokemon/furfrou/debutante_trim/back.png b/graphics/pokemon/furfrou/debutante/back.png similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/back.png rename to graphics/pokemon/furfrou/debutante/back.png diff --git a/graphics/pokemon/furfrou/debutante_trim/icon.png b/graphics/pokemon/furfrou/debutante/icon.png similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/icon.png rename to graphics/pokemon/furfrou/debutante/icon.png diff --git a/graphics/pokemon/furfrou/debutante_trim/normal.pal b/graphics/pokemon/furfrou/debutante/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/normal.pal rename to graphics/pokemon/furfrou/debutante/normal.pal diff --git a/graphics/pokemon/furfrou/debutante_trim/overworld.png b/graphics/pokemon/furfrou/debutante/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/overworld.png rename to graphics/pokemon/furfrou/debutante/overworld.png diff --git a/graphics/pokemon/furfrou/debutante_trim/overworld_normal.pal b/graphics/pokemon/furfrou/debutante/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/debutante/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/debutante_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/debutante/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/debutante/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/debutante_trim/shiny.pal b/graphics/pokemon/furfrou/debutante/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/debutante_trim/shiny.pal rename to graphics/pokemon/furfrou/debutante/shiny.pal diff --git a/graphics/pokemon/furfrou/diamond_trim/anim_front.png b/graphics/pokemon/furfrou/diamond/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/anim_front.png rename to graphics/pokemon/furfrou/diamond/anim_front.png diff --git a/graphics/pokemon/furfrou/diamond_trim/back.png b/graphics/pokemon/furfrou/diamond/back.png similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/back.png rename to graphics/pokemon/furfrou/diamond/back.png diff --git a/graphics/pokemon/furfrou/diamond_trim/icon.png b/graphics/pokemon/furfrou/diamond/icon.png similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/icon.png rename to graphics/pokemon/furfrou/diamond/icon.png diff --git a/graphics/pokemon/furfrou/diamond_trim/normal.pal b/graphics/pokemon/furfrou/diamond/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/normal.pal rename to graphics/pokemon/furfrou/diamond/normal.pal diff --git a/graphics/pokemon/furfrou/diamond_trim/overworld.png b/graphics/pokemon/furfrou/diamond/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/overworld.png rename to graphics/pokemon/furfrou/diamond/overworld.png diff --git a/graphics/pokemon/furfrou/diamond_trim/overworld_normal.pal b/graphics/pokemon/furfrou/diamond/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/diamond/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/diamond_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/diamond/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/diamond/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/diamond_trim/shiny.pal b/graphics/pokemon/furfrou/diamond/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/diamond_trim/shiny.pal rename to graphics/pokemon/furfrou/diamond/shiny.pal diff --git a/graphics/pokemon/furfrou/heart_trim/anim_front.png b/graphics/pokemon/furfrou/heart/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/anim_front.png rename to graphics/pokemon/furfrou/heart/anim_front.png diff --git a/graphics/pokemon/furfrou/heart_trim/back.png b/graphics/pokemon/furfrou/heart/back.png similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/back.png rename to graphics/pokemon/furfrou/heart/back.png diff --git a/graphics/pokemon/furfrou/heart_trim/icon.png b/graphics/pokemon/furfrou/heart/icon.png similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/icon.png rename to graphics/pokemon/furfrou/heart/icon.png diff --git a/graphics/pokemon/furfrou/heart_trim/normal.pal b/graphics/pokemon/furfrou/heart/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/normal.pal rename to graphics/pokemon/furfrou/heart/normal.pal diff --git a/graphics/pokemon/furfrou/heart_trim/overworld.png b/graphics/pokemon/furfrou/heart/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/overworld.png rename to graphics/pokemon/furfrou/heart/overworld.png diff --git a/graphics/pokemon/furfrou/heart_trim/overworld_normal.pal b/graphics/pokemon/furfrou/heart/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/heart/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/heart_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/heart/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/heart/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/heart_trim/shiny.pal b/graphics/pokemon/furfrou/heart/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/heart_trim/shiny.pal rename to graphics/pokemon/furfrou/heart/shiny.pal diff --git a/graphics/pokemon/furfrou/kabuki_trim/anim_front.png b/graphics/pokemon/furfrou/kabuki/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/anim_front.png rename to graphics/pokemon/furfrou/kabuki/anim_front.png diff --git a/graphics/pokemon/furfrou/kabuki_trim/back.png b/graphics/pokemon/furfrou/kabuki/back.png similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/back.png rename to graphics/pokemon/furfrou/kabuki/back.png diff --git a/graphics/pokemon/furfrou/kabuki_trim/icon.png b/graphics/pokemon/furfrou/kabuki/icon.png similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/icon.png rename to graphics/pokemon/furfrou/kabuki/icon.png diff --git a/graphics/pokemon/furfrou/kabuki_trim/normal.pal b/graphics/pokemon/furfrou/kabuki/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/normal.pal rename to graphics/pokemon/furfrou/kabuki/normal.pal diff --git a/graphics/pokemon/furfrou/kabuki_trim/overworld.png b/graphics/pokemon/furfrou/kabuki/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/overworld.png rename to graphics/pokemon/furfrou/kabuki/overworld.png diff --git a/graphics/pokemon/furfrou/kabuki_trim/overworld_normal.pal b/graphics/pokemon/furfrou/kabuki/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/kabuki/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/kabuki_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/kabuki/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/kabuki/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/kabuki_trim/shiny.pal b/graphics/pokemon/furfrou/kabuki/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/kabuki_trim/shiny.pal rename to graphics/pokemon/furfrou/kabuki/shiny.pal diff --git a/graphics/pokemon/furfrou/la_reine_trim/anim_front.png b/graphics/pokemon/furfrou/la_reine/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/anim_front.png rename to graphics/pokemon/furfrou/la_reine/anim_front.png diff --git a/graphics/pokemon/furfrou/la_reine_trim/back.png b/graphics/pokemon/furfrou/la_reine/back.png similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/back.png rename to graphics/pokemon/furfrou/la_reine/back.png diff --git a/graphics/pokemon/furfrou/la_reine_trim/icon.png b/graphics/pokemon/furfrou/la_reine/icon.png similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/icon.png rename to graphics/pokemon/furfrou/la_reine/icon.png diff --git a/graphics/pokemon/furfrou/la_reine_trim/normal.pal b/graphics/pokemon/furfrou/la_reine/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/normal.pal rename to graphics/pokemon/furfrou/la_reine/normal.pal diff --git a/graphics/pokemon/furfrou/la_reine_trim/overworld.png b/graphics/pokemon/furfrou/la_reine/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/overworld.png rename to graphics/pokemon/furfrou/la_reine/overworld.png diff --git a/graphics/pokemon/furfrou/la_reine_trim/overworld_normal.pal b/graphics/pokemon/furfrou/la_reine/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/la_reine/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/la_reine_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/la_reine/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/la_reine/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/la_reine_trim/shiny.pal b/graphics/pokemon/furfrou/la_reine/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/la_reine_trim/shiny.pal rename to graphics/pokemon/furfrou/la_reine/shiny.pal diff --git a/graphics/pokemon/furfrou/matron_trim/anim_front.png b/graphics/pokemon/furfrou/matron/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/anim_front.png rename to graphics/pokemon/furfrou/matron/anim_front.png diff --git a/graphics/pokemon/furfrou/matron_trim/back.png b/graphics/pokemon/furfrou/matron/back.png similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/back.png rename to graphics/pokemon/furfrou/matron/back.png diff --git a/graphics/pokemon/furfrou/matron_trim/icon.png b/graphics/pokemon/furfrou/matron/icon.png similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/icon.png rename to graphics/pokemon/furfrou/matron/icon.png diff --git a/graphics/pokemon/furfrou/matron_trim/normal.pal b/graphics/pokemon/furfrou/matron/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/normal.pal rename to graphics/pokemon/furfrou/matron/normal.pal diff --git a/graphics/pokemon/furfrou/matron_trim/overworld.png b/graphics/pokemon/furfrou/matron/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/overworld.png rename to graphics/pokemon/furfrou/matron/overworld.png diff --git a/graphics/pokemon/furfrou/matron_trim/overworld_normal.pal b/graphics/pokemon/furfrou/matron/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/matron/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/matron_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/matron/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/matron/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/matron_trim/shiny.pal b/graphics/pokemon/furfrou/matron/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/matron_trim/shiny.pal rename to graphics/pokemon/furfrou/matron/shiny.pal diff --git a/graphics/pokemon/furfrou/pharaoh_trim/anim_front.png b/graphics/pokemon/furfrou/pharaoh/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/anim_front.png rename to graphics/pokemon/furfrou/pharaoh/anim_front.png diff --git a/graphics/pokemon/furfrou/pharaoh_trim/back.png b/graphics/pokemon/furfrou/pharaoh/back.png similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/back.png rename to graphics/pokemon/furfrou/pharaoh/back.png diff --git a/graphics/pokemon/furfrou/pharaoh_trim/icon.png b/graphics/pokemon/furfrou/pharaoh/icon.png similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/icon.png rename to graphics/pokemon/furfrou/pharaoh/icon.png diff --git a/graphics/pokemon/furfrou/pharaoh_trim/normal.pal b/graphics/pokemon/furfrou/pharaoh/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/normal.pal rename to graphics/pokemon/furfrou/pharaoh/normal.pal diff --git a/graphics/pokemon/furfrou/pharaoh_trim/overworld.png b/graphics/pokemon/furfrou/pharaoh/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/overworld.png rename to graphics/pokemon/furfrou/pharaoh/overworld.png diff --git a/graphics/pokemon/furfrou/pharaoh_trim/overworld_normal.pal b/graphics/pokemon/furfrou/pharaoh/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/pharaoh/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/pharaoh_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/pharaoh/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/pharaoh/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/pharaoh_trim/shiny.pal b/graphics/pokemon/furfrou/pharaoh/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/pharaoh_trim/shiny.pal rename to graphics/pokemon/furfrou/pharaoh/shiny.pal diff --git a/graphics/pokemon/furfrou/star_trim/anim_front.png b/graphics/pokemon/furfrou/star/anim_front.png similarity index 100% rename from graphics/pokemon/furfrou/star_trim/anim_front.png rename to graphics/pokemon/furfrou/star/anim_front.png diff --git a/graphics/pokemon/furfrou/star_trim/back.png b/graphics/pokemon/furfrou/star/back.png similarity index 100% rename from graphics/pokemon/furfrou/star_trim/back.png rename to graphics/pokemon/furfrou/star/back.png diff --git a/graphics/pokemon/furfrou/star_trim/icon.png b/graphics/pokemon/furfrou/star/icon.png similarity index 100% rename from graphics/pokemon/furfrou/star_trim/icon.png rename to graphics/pokemon/furfrou/star/icon.png diff --git a/graphics/pokemon/furfrou/star_trim/normal.pal b/graphics/pokemon/furfrou/star/normal.pal similarity index 100% rename from graphics/pokemon/furfrou/star_trim/normal.pal rename to graphics/pokemon/furfrou/star/normal.pal diff --git a/graphics/pokemon/furfrou/star_trim/overworld.png b/graphics/pokemon/furfrou/star/overworld.png similarity index 100% rename from graphics/pokemon/furfrou/star_trim/overworld.png rename to graphics/pokemon/furfrou/star/overworld.png diff --git a/graphics/pokemon/furfrou/star_trim/overworld_normal.pal b/graphics/pokemon/furfrou/star/overworld_normal.pal similarity index 100% rename from graphics/pokemon/furfrou/star_trim/overworld_normal.pal rename to graphics/pokemon/furfrou/star/overworld_normal.pal diff --git a/graphics/pokemon/furfrou/star_trim/overworld_shiny.pal b/graphics/pokemon/furfrou/star/overworld_shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/star_trim/overworld_shiny.pal rename to graphics/pokemon/furfrou/star/overworld_shiny.pal diff --git a/graphics/pokemon/furfrou/star_trim/shiny.pal b/graphics/pokemon/furfrou/star/shiny.pal similarity index 100% rename from graphics/pokemon/furfrou/star_trim/shiny.pal rename to graphics/pokemon/furfrou/star/shiny.pal diff --git a/graphics/text_window/dexnav_pal.pal b/graphics/text_window/dexnav_pal.pal new file mode 100644 index 000000000000..cb6acc371d35 --- /dev/null +++ b/graphics/text_window/dexnav_pal.pal @@ -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 diff --git a/include/battle.h b/include/battle.h index 0f798ea4819b..a61eff530610 100644 --- a/include/battle.h +++ b/include/battle.h @@ -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. @@ -67,37 +68,6 @@ #define BATTLE_BUFFER_LINK_SIZE 0x1000 -// 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]; -}; - -#define RESOURCE_FLAG_FLASH_FIRE 0x1 -#define RESOURCE_FLAG_ROOST 0x2 -#define RESOURCE_FLAG_UNBURDEN 0x4 -#define RESOURCE_FLAG_UNUSED 0x8 -#define RESOURCE_FLAG_UNUSED_2 0x10 -#define RESOURCE_FLAG_EMERGENCY_EXIT 0x20 -#define RESOURCE_FLAG_NEUTRALIZING_GAS 0x40 -#define RESOURCE_FLAG_ICE_FACE 0x80 - struct DisableStruct { u32 transformedMonPersonality; @@ -134,6 +104,7 @@ struct DisableStruct u8 laserFocusTimer; u8 throatChopTimer; u8 wrapTurns; + u8 syrupBombTimer; u8 tormentTimer:4; // used for G-Max Meltdown u8 usedMoves:4; u8 truantCounter:1; @@ -146,14 +117,23 @@ struct DisableStruct u8 toxicSpikesDone:1; u8 stickyWebDone:1; u8 stealthRockDone:1; - u8 syrupBombTimer; - u8 syrupBombIsShiny:1; - u8 steelSurgeDone:1; u8 weatherAbilityDone:1; u8 terrainAbilityDone:1; + u8 syrupBombIsShiny:1; + u8 steelSurgeDone:1; u8 usedProteanLibero:1; + u8 flashFireBoosted:1; + u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching) + u8 boosterEnergyActivates:1; + u8 roostActive:1; + u8 unbrudenActive:1; + u8 startEmergencyExit:1; + u8 neutralizingGas:1; + u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case + u8 padding:2; }; +// Fully Cleared each turn after end turn effects are done. A few things are cleared before end turn effects struct ProtectStruct { u32 protected:1; @@ -207,12 +187,11 @@ struct ProtectStruct u32 specialDmg; u8 physicalBattlerId; u8 specialBattlerId; - }; +// Cleared at the start of HandleAction_ActionFinished struct SpecialStatus { - s32 shellBellDmg; s32 physicalDmg; s32 specialDmg; u8 physicalBattlerId; @@ -224,7 +203,8 @@ struct SpecialStatus u8 faintedHasReplacement:1; u8 focusBanded:1; u8 focusSashed:1; - u8 unused:2; + u8 emergencyExited:1; + u8 afterYou:1; // End of byte u8 sturdied:1; u8 stormDrainRedirected:1; @@ -243,16 +223,15 @@ struct SpecialStatus u8 neutralizingGasRemoved:1; // See VARIOUS_TRY_END_NEUTRALIZING_GAS u8 affectionEndured:1; // End of byte - u8 damagedMons:4; // Mons that have been damaged directly by using a move, includes substitute. u8 dancerUsedMove:1; u8 dancerOriginalTarget:3; - // End of byte - u8 emergencyExited:1; - u8 afterYou:1; u8 preventLifeOrbDamage:1; // So that Life Orb doesn't activate various effects. u8 distortedTypeMatchups:1; u8 teraShellAbilityDone:1; u8 criticalHit:1; + // End of byte + u8 enduredDamage:1; + u8 padding:7; }; struct SideTimer @@ -378,9 +357,12 @@ struct AiLogicData u8 weatherHasEffect:1; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once. u8 ejectButtonSwitch:1; // Tracks whether current switch out was from Eject Button u8 ejectPackSwitch:1; // Tracks whether current switch out was from Eject Pack - u8 padding:5; + u8 predictingSwitch:1; // Determines whether AI will use predictions this turn or not + u8 aiSwitchPredictionInProgress:1; // Tracks whether the AI is in the middle of running prediction calculations + u8 padding:3; u8 shouldSwitch; // Stores result of ShouldSwitch, which decides whether a mon should be switched out u8 aiCalcInProgress:1; + u8 battlerDoingPrediction; // Stores which battler is currently running its prediction calcs }; struct AI_ThinkingStruct @@ -430,7 +412,6 @@ struct StatsArray struct BattleResources { struct SecretBase* secretBase; - struct ResourceFlags *flags; struct BattleScriptsStack* battleScriptsStack; struct BattleCallbacksStack* battleCallbackStack; struct StatsArray* beforeLvlUp; @@ -590,7 +571,6 @@ struct DynamaxData u8 dynamaxTurns[MAX_BATTLERS_COUNT]; u16 baseMoves[MAX_BATTLERS_COUNT]; // base move of Max Move u16 lastUsedBaseMove; - u16 levelUpHP; }; struct BattleGimmickData @@ -639,8 +619,32 @@ enum BattleIntroStates BATTLE_INTRO_STATE_SET_DEX_AND_BATTLE_VARS }; +struct BattlerState +{ + u8 targetsDone[MAX_BATTLERS_COUNT]; + + u32 commandingDondozo:1; + u32 absentBattlerFlags:1; + u32 focusPunchBattlers:1; + u32 multipleSwitchInBattlers:1; + u32 alreadyStatusedMoveAttempt:1; // For example when using Thunder Wave on an already paralyzed Pokémon. + u32 activeAbilityPopUps:1; + u32 lastMoveFailed:1; // For Stomping Tantrum + u32 forcedSwitch:1; + u32 storedHealingWish:1; + u32 storedLunarDance:1; + u32 usedEjectItem:1; + u32 sleepClauseEffectExempt:1; // Stores whether effect should be exempt from triggering Sleep Clause (Effect Spore) + u32 usedMicleBerry:1; + u32 pursuitTarget:1; + u32 padding:17; + // End of Word +}; + +// Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise. struct BattleStruct { + struct BattlerState battlerState[MAX_BATTLERS_COUNT]; u8 turnEffectsTracker; u8 turnEffectsBattlerId; u8 turnCountersTracker; @@ -658,7 +662,6 @@ struct BattleStruct u8 wildVictorySong; u8 dynamicMoveType; u8 wrappedBy[MAX_BATTLERS_COUNT]; - u8 focusPunchBattlers; // as bits u8 battlerPreventingSwitchout; u8 moneyMultiplier:6; u8 moneyMultiplierItem:1; @@ -699,9 +702,9 @@ struct BattleStruct u8 hpScale; u16 synchronizeMoveEffect; u8 anyMonHasTransformed:1; // Only used in battle_tv.c - u8 multipleSwitchInBattlers:4; // One bit per battler u8 multipleSwitchInState:2; u8 multipleSwitchInCursor:3; + u8 padding1:2; u8 multipleSwitchInSortedBattlers[MAX_BATTLERS_COUNT]; void (*savedCallback)(void); u16 usedHeldItems[PARTY_SIZE][NUM_BATTLE_SIDES]; // For each party member and side. For harvest, recycle @@ -738,7 +741,6 @@ struct BattleStruct u16 arenaStartHp[2]; u8 arenaLostPlayerMons; // Bits for party member, lost as in referee's decision, not by fainting. u8 arenaLostOpponentMons; - u8 alreadyStatusedMoveAttempt; // As bits for battlers; For example when using Thunder Wave on an already paralyzed Pokémon. u8 debugBattler; u8 magnitudeBasePower; u8 presentBasePower; @@ -748,7 +750,6 @@ struct BattleStruct u8 savedTargetCount:4; u8 savedAttackerCount:4; bool8 ateBoost[MAX_BATTLERS_COUNT]; - u8 activeAbilityPopUps; // as bits for each battler u8 abilityPopUpSpriteIds[MAX_BATTLERS_COUNT][2]; // two per battler struct ZMoveData zmove; struct DynamaxData dynamax; @@ -757,7 +758,6 @@ struct BattleStruct enum BattleIntroStates introState:8; u8 ateBerry[2]; // array id determined by side, each party pokemon as bit u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages - u8 lastMoveFailed; // as bits for each battler, for the sake of Stomping Tantrum u8 lastMoveTarget[MAX_BATTLERS_COUNT]; // The last target on which each mon used a move, for the sake of Instruct u16 tracedAbility[MAX_BATTLERS_COUNT]; u16 hpBefore[MAX_BATTLERS_COUNT]; // Hp of battlers before using a move. For Berserk and Anger Shell. @@ -772,8 +772,6 @@ struct BattleStruct u16 changedSpecies[NUM_BATTLE_SIDES][PARTY_SIZE]; // For forms when multiple mons can change into the same pokemon. u8 quickClawBattlerId; struct LostItem itemLost[NUM_BATTLE_SIDES][PARTY_SIZE]; // Pokemon that had items consumed or stolen (two bytes per party member per side) - u8 forcedSwitch:4; // For each battler - u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects u8 blunderPolicy:1; // should blunder policy activate u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky u8 bouncedMoveIsUsed:1; @@ -791,11 +789,7 @@ struct BattleStruct u8 hitSwitchTargetFailed:1; u8 effectsBeforeUsingMoveDone:1; // Mega Evo and Focus Punch/Shell Trap effects. u8 spriteIgnore0Hp:1; - u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit. - u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching) u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party. - u8 storedHealingWish:4; // Each battler as a bit. - u8 storedLunarDance:4; // Each battler as a bit. u8 bonusCritStages[MAX_BATTLERS_COUNT]; // G-Max Chi Strike boosts crit stages of allies. u8 itemPartyIndex[MAX_BATTLERS_COUNT]; u8 itemMoveIndex[MAX_BATTLERS_COUNT]; @@ -814,7 +808,6 @@ struct BattleStruct u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. u32 aiDelayFrames; // Number of frames it took to choose an action. u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE]; - u8 enduredDamage; u8 transformZeroToHero[NUM_BATTLE_SIDES]; u8 stickySyrupdBy[MAX_BATTLERS_COUNT]; u8 intrepidSwordBoost[NUM_BATTLE_SIDES]; @@ -825,18 +818,13 @@ struct BattleStruct u8 quickDrawRandom[MAX_BATTLERS_COUNT]; u8 shellSideArmCategory[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; u8 speedTieBreaks; // MAX_BATTLERS_COUNT! values. - u8 boosterEnergyActivates; u8 categoryOverride; // for Z-Moves and Max Moves - u8 commandingDondozo; u16 commanderActive[MAX_BATTLERS_COUNT]; u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side - u8 redCardActivates:1; - u8 padding1:7; - u8 usedEjectItem; u8 monCausingSleepClause[NUM_BATTLE_SIDES]; // Stores which pokemon on a given side is causing Sleep Clause to be active as the mon's index in the party - u8 sleepClauseEffectExempt:4; // Stores whether effect should be exempt from triggering Sleep Clause (Effect Spore) - u8 usedMicleBerry:4; - u8 pursuitTarget:4; // Each battler as a bit. + u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects + u8 redCardActivates:1; + u8 padding2:2; // padding in the middle so pursuit fields are together u8 pursuitSwitchByMove:1; u8 pursuitStoredSwitch; // Stored id for the Pursuit target's switch s32 battlerExpReward; @@ -852,7 +840,7 @@ struct BattleStruct u8 calculatedSpreadMoveAccuracy:1; u8 printedStrongWindsWeakenedAttack:1; u8 numSpreadTargets:2; - u8 padding2:2; + u8 padding3:2; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, @@ -864,11 +852,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 +1114,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 +1177,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); @@ -1197,7 +1197,7 @@ static inline bool32 IsBattlerTurnDamaged(u32 battler) { return gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0 - || gBattleStruct->enduredDamage & (1u << battler); + || gSpecialStatuses[battler].enduredDamage; } static inline bool32 IsBattlerAtMaxHp(u32 battler) diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 7cfc28e5d6a9..f561182fca67 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -123,7 +123,7 @@ bool32 HasMoveWithMoveEffectExcept(u32 battlerId, u32 moveEffect, u32 exception) bool32 HasMoveThatLowersOwnStats(u32 battlerId); bool32 HasMoveWithLowAccuracy(u32 battlerAtk, u32 battlerDef, u32 accCheck, bool32 ignoreStatus, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect); bool32 HasAnyKnownMove(u32 battlerId); -bool32 IsAromaVeilProtectedMove(u32 move); +bool32 IsAromaVeilProtectedEffect(u32 moveEffect); bool32 IsNonVolatileStatusMoveEffect(u32 moveEffect); bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility); bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move); @@ -182,6 +182,7 @@ bool32 PartnerHasSameMoveEffectWithoutTarget(u32 battlerAtkPartner, u32 move, u3 bool32 PartnerMoveEffectIsStatusSameTarget(u32 battlerAtkPartner, u32 battlerDef, u32 partnerMove); bool32 IsMoveEffectWeather(u32 move); bool32 PartnerMoveEffectIsTerrain(u32 battlerAtkPartner, u32 partnerMove); +bool32 PartnerMoveEffectIs(u32 battlerAtkPartner, u32 partnerMove, u32 effectCheck); bool32 PartnerMoveIs(u32 battlerAtkPartner, u32 partnerMove, u32 moveCheck); bool32 PartnerMoveIsSameAsAttacker(u32 battlerAtkPartner, u32 battlerDef, u32 move, u32 partnerMove); bool32 PartnerMoveIsSameNoTarget(u32 battlerAtkPartner, u32 move, u32 partnerMove); @@ -214,5 +215,6 @@ bool32 AI_ShouldSetUpHazards(u32 battlerAtk, u32 battlerDef, struct AiLogicData void IncreaseTidyUpScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); bool32 AI_ShouldSpicyExtract(u32 battlerAtk, u32 battlerAtkPartner, u32 move, struct AiLogicData *aiData); void IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score); +bool32 IsBattlerPredictedToSwitch(u32 battler); #endif //GUARD_BATTLE_AI_UTIL_H diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 5e92cac763ff..0e5f11e82e78 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -168,10 +168,6 @@ enum CONTROLLER_CHOSENMONRETURNVALUE, CONTROLLER_ONERETURNVALUE, CONTROLLER_ONERETURNVALUE_DUPLICATE, - CONTROLLER_CLEARUNKVAR, - CONTROLLER_SETUNKVAR, - CONTROLLER_CLEARUNKFLAG, - CONTROLLER_TOGGLEUNKFLAG, CONTROLLER_HITANIMATION, CONTROLLER_CANTSWITCH, CONTROLLER_PLAYSE, @@ -210,7 +206,7 @@ void PrepareBufferDataTransferLink(u32 battler, u32 bufferId, u16 size, u8 *data void BtlController_EmitGetMonData(u32 battler, u32 bufferId, u8 requestId, u8 monToCheck); void BtlController_EmitSetMonData(u32 battler, u32 bufferId, u8 requestId, u8 monToCheck, u8 bytes, void *data); void BtlController_EmitLoadMonSprite(u32 battler, u32 bufferId); -void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearSubstituteBit); +void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearTransform, bool8 dontClearSubstituteBit); void BtlController_EmitReturnMonToBall(u32 battler, u32 bufferId, bool8 skipAnim); void BtlController_EmitDrawTrainerPic(u32 battler, u32 bufferId); void BtlController_EmitTrainerSlide(u32 battler, u32 bufferId); @@ -255,7 +251,7 @@ void BattleControllerComplete(u32 battler); // Can be used for all the controlle void BtlController_Empty(u32 battler); // Empty command, does nothing, only completes the execution. void BtlController_TerminatorNop(u32 battler); // Dummy function at the end of the table. void BattleControllerDummy(u32 battler); -void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit, bool32 doSlideIn); +void StartSendOutAnim(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstituteBit, bool32 doSlideIn); void Controller_WaitForString(u32 battler); void Controller_WaitForHealthBar(u32 battler); diff --git a/include/battle_dynamax.h b/include/battle_dynamax.h index 20cd4d5e79ee..9957c37a106c 100644 --- a/include/battle_dynamax.h +++ b/include/battle_dynamax.h @@ -58,7 +58,7 @@ enum MaxMoveEffect bool32 CanDynamax(u32 battler); bool32 IsGigantamaxed(u32 battler); -void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon); +void ApplyDynamaxHPMultiplier(struct Pokemon* mon); void ActivateDynamax(u32 battler); u16 GetNonDynamaxHP(u32 battler); u16 GetNonDynamaxMaxHP(u32 battler); diff --git a/include/battle_gfx_sfx_util.h b/include/battle_gfx_sfx_util.h index 968f8d48dccd..d84af67f3551 100644 --- a/include/battle_gfx_sfx_util.h +++ b/include/battle_gfx_sfx_util.h @@ -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); @@ -37,7 +38,7 @@ void SpriteCB_SetInvisible(struct Sprite *sprite); void SetBattlerShadowSpriteCallback(u8 battler, u16 species); void HideBattlerShadowSprite(u8 battler); void FillAroundBattleWindows(void); -void ClearTemporarySpeciesSpriteData(u8 battler, bool8 dontClearSubstitute); +void ClearTemporarySpeciesSpriteData(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstitute); void AllocateMonSpritesGfx(void); void FreeMonSpritesGfx(void); bool32 ShouldPlayNormalMonCry(struct Pokemon *mon); diff --git a/include/battle_main.h b/include/battle_main.h index 7e3206c554bd..e8368f82d619 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -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); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 82c396996c84..f4cfab02ee69 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -50,17 +50,12 @@ extern const u8 BattleScript_DoSwitchOut[]; extern const u8 BattleScript_MoveSwitchOpenPartyScreen[]; extern const u8 BattleScript_Pausex20[]; extern const u8 BattleScript_LevelUp[]; -extern const u8 BattleScript_RainContinuesOrEnds[]; -extern const u8 BattleScript_SnowContinuesOrEnds[]; +extern const u8 BattleScript_WeatherContinues[]; +extern const u8 BattleScript_WeatherFaded[]; extern const u8 BattleScript_DamagingWeatherContinues[]; extern const u8 BattleScript_DamagingWeather[]; -extern const u8 BattleScript_IceBodyHeal[]; -extern const u8 BattleScript_SandStormHailSnowEnds[]; -extern const u8 BattleScript_SunlightContinues[]; -extern const u8 BattleScript_SunlightFaded[]; -extern const u8 BattleScript_FogContinues[]; extern const u8 BattleScript_FogEnded_Ret[]; -extern const u8 BattleScript_FogEnded[]; +extern const u8 BattleScript_IceBodyHeal[]; extern const u8 BattleScript_OverworldStatusStarts[]; extern const u8 BattleScript_OverworldWeatherStarts[]; extern const u8 BattleScript_OverworldTerrain[]; @@ -422,7 +417,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[]; diff --git a/include/battle_transition.h b/include/battle_transition.h index eba514b09f9f..8bc80dc642ba 100644 --- a/include/battle_transition.h +++ b/include/battle_transition.h @@ -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, diff --git a/include/battle_util.h b/include/battle_util.h index 9539321cd5a6..4fde2ea341f2 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -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) @@ -204,7 +206,7 @@ void TryClearRageAndFuryCutter(void); u32 AtkCanceller_MoveSuccessOrder(void); void SetAtkCancellerForCalledMove(void); bool32 HasNoMonsToSwitch(u32 battler, u8 r1, u8 r2); -bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility); +bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility); u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef); u32 CanPartnerAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef); u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 move, u32 moveType); @@ -226,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); @@ -245,9 +247,10 @@ 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); -s32 GetStealthHazardDamage(u8 hazardType, u32 battler); -s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp); +uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType); +void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags); +s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler); +s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, u8 type2, u32 maxHp); bool32 CanMegaEvolve(u32 battler); bool32 CanUltraBurst(u32 battler); void ActivateMegaEvolution(u32 battler); @@ -294,7 +297,7 @@ u32 GetBattlerMoveTargetType(u32 battler, u32 move); bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move); void CopyMonLevelAndBaseStatsToBattleMon(u32 battler, struct Pokemon *mon); void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon); -void RecalcBattlerStats(u32 battler, struct Pokemon *mon); +void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing); bool32 IsAlly(u32 battlerAtk, u32 battlerDef); bool32 IsGen6ExpShareEnabled(void); bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect); @@ -328,12 +331,17 @@ 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); +u32 NumAffectedSpreadMoveTargets(void); +bool32 IsPursuitTargetSet(void); +void ClearPursuitValuesIfSet(u32 battler); +void ClearPursuitValues(void); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/config/battle.h b/include/config/battle.h index 901b611a769d..016b8044cc7d 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -144,6 +144,7 @@ #define B_SYMBIOSIS_GEMS GEN_LATEST // In Gen7+, Symbiosis passes an item after a gem-boosted attack. Previously, items are passed before the gem-boosted attack hits, making the item effect apply. #define B_ABSORBING_ABILITY_STRING GEN_LATEST // In Gen5+, the abilities that absorb moves of a certain type use a generic string for stat increases and decreases. #define B_REDIRECT_ABILITY_IMMUNITY GEN_LATEST // In Gen5+, Pokémon with Lightning Rod/Storm Drain become immune to Electric/Water-type moves and increase their Sp. Attack by 1 stage on top of the redirecting effect. +#define B_REDIRECT_ABILITY_ALLIES GEN_LATEST // In Gen4+, Lightning Rod/Storm Drain redirect ally's moves as well. #define B_LEAF_GUARD_PREVENTS_REST GEN_LATEST // In Gen5+, Leaf Guard prevents the use of Rest in harsh sunlight. #define B_SNOW_WARNING GEN_LATEST // In Gen9+, Snow Warning will summon snow instead of hail. #define B_TRANSISTOR_BOOST GEN_LATEST // In Gen9+, Transistor will only boost Electric-type moves by 1.3x as opposed to 1.5x. @@ -157,6 +158,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. @@ -205,6 +207,7 @@ #define B_VAR_STARTING_STATUS 0 // If this var has a value, assigning a STATUS_FIELD_xx_TERRAIN to it before battle causes the battle to start with that terrain active. #define B_VAR_STARTING_STATUS_TIMER 0 // If this var has a value greater or equal than 1 field terrains will last that number of turns, otherwise they will last until they're overwritten. #define B_VAR_WILD_AI_FLAGS 0 // If not 0, you can use this var to add to default wild AI flags. NOT usable with flags above (1 << 15) +#define B_VAR_DIFFICULTY 0 // If not 0, you can use this var to control which difficulty version of a Trainer is loaded. This should be manually set by the developer using Script_SetDifficulty AFTER NewGameInitData has run. // Sky Battles #define B_FLAG_SKY_BATTLE 0 // If this flag has a value, the player will be able to engage in scripted Sky Battles. @@ -229,7 +232,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. diff --git a/include/config/dexnav.h b/include/config/dexnav.h new file mode 100644 index 000000000000..20d05f7a23f7 --- /dev/null +++ b/include/config/dexnav.h @@ -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 diff --git a/include/config/overworld.h b/include/config/overworld.h index 464024025ba9..5a6cb1e95536 100644 --- a/include/config/overworld.h +++ b/include/config/overworld.h @@ -3,7 +3,6 @@ // Movement config #define OW_RUNNING_INDOORS GEN_LATEST // In Gen4+, players are allowed to run indoors. -#define OW_AUTO_SIGNPOST FALSE // When enabled, if the tile that the player is facing has MB_SIGNPOST, MB_POKEMART_SIGN, or MB_POKEMON_CENTER_SIGN, the player will automatically read the signpost, as seen in FRLG. #define SLOW_MOVEMENT_ON_STAIRS FALSE // If enabled, the player will move slower up/down stairs like in FR // Other settings @@ -85,6 +84,7 @@ #define OW_FLAG_NO_ENCOUNTER 0 // If this flag is set, wild encounters will be disabled. #define OW_FLAG_NO_TRAINER_SEE 0 // If this flag is set, trainers will not battle the player unless they're talked to. #define OW_FLAG_NO_COLLISION 0 // If this flag is set, the player will be able to walk over tiles with collision. Mainly intended for debugging purposes. +#define OW_FLAG_POKE_RIDER 0 // If this flag is set, the player will be able to use fly from the Pokenav Region Map and the Town Map key item by pressing 'R' on a city/location they are able to fly to. #define BATTLE_PYRAMID_RANDOM_ENCOUNTERS FALSE // If set to TRUE, battle pyramid Pokemon will be generated randomly based on the round's challenge instead of hardcoded in src/data/battle_frontier/battle_pyramid_level_50_wild_mons.h (or open_level_wild_mons.h) diff --git a/include/config/test.h b/include/config/test.h index cce97484df32..90cf5a4b8807 100644 --- a/include/config/test.h +++ b/include/config/test.h @@ -1129,6 +1129,10 @@ #undef P_FAMILY_PECHARUNT #define P_FAMILY_PECHARUNT TRUE +// Vars +#undef B_VAR_DIFFICULTY +#define B_VAR_DIFFICULTY VAR_UNUSED_0x404E + // Flags #undef B_FLAG_SLEEP_CLAUSE #define B_FLAG_SLEEP_CLAUSE FLAG_SPECIAL_FLAG_UNUSED_0x4003 diff --git a/include/constants/battle.h b/include/constants/battle.h index a7300e65170e..561d4f81e58f 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -253,6 +253,13 @@ #define SIDE_STATUS_SCREEN_ANY (SIDE_STATUS_REFLECT | SIDE_STATUS_LIGHTSCREEN | SIDE_STATUS_AURORA_VEIL) #define SIDE_STATUS_PLEDGE_ANY (SIDE_STATUS_RAINBOW | SIDE_STATUS_SEA_OF_FIRE | SIDE_STATUS_SWAMP) +// Used for damaging entry hazards based on type +enum TypeSideHazard +{ + TYPE_SIDE_HAZARD_POINTED_STONES = TYPE_ROCK, + TYPE_SIDE_HAZARD_SHARP_STEEL = TYPE_STEEL, +}; + // Field affecting statuses. #define STATUS_FIELD_MAGIC_ROOM (1 << 0) #define STATUS_FIELD_TRICK_ROOM (1 << 1) @@ -266,7 +273,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) @@ -283,44 +289,38 @@ #define MOVE_RESULT_FOE_ENDURED_AFFECTION (1 << 9) #define MOVE_RESULT_NO_EFFECT (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED) +enum BattleWeather +{ + BATTLE_WEATHER_RAIN, + BATTLE_WEATHER_RAIN_PRIMAL, + BATTLE_WEATHER_RAIN_DOWNPOUR, + BATTLE_WEATHER_SUN, + BATTLE_WEATHER_SUN_PRIMAL, + BATTLE_WEATHER_SANDSTORM, + BATTLE_WEATHER_HAIL, + BATTLE_WEATHER_SNOW, + BATTLE_WEATHER_FOG, + BATTLE_WEATHER_STRONG_WINDS, + BATTLE_WEATHER_COUNT, +}; + // Battle Weather flags -#define B_WEATHER_NONE 0 -#define B_WEATHER_RAIN_TEMPORARY (1 << 0) -#define B_WEATHER_RAIN_DOWNPOUR (1 << 1) // unused -#define B_WEATHER_RAIN_PERMANENT (1 << 2) -#define B_WEATHER_RAIN_PRIMAL (1 << 3) -#define B_WEATHER_RAIN (B_WEATHER_RAIN_TEMPORARY | B_WEATHER_RAIN_DOWNPOUR | B_WEATHER_RAIN_PERMANENT | B_WEATHER_RAIN_PRIMAL) -#define B_WEATHER_SANDSTORM_TEMPORARY (1 << 4) -#define B_WEATHER_SANDSTORM_PERMANENT (1 << 5) -#define B_WEATHER_SANDSTORM (B_WEATHER_SANDSTORM_TEMPORARY | B_WEATHER_SANDSTORM_PERMANENT) -#define B_WEATHER_SUN_TEMPORARY (1 << 6) -#define B_WEATHER_SUN_PERMANENT (1 << 7) -#define B_WEATHER_SUN_PRIMAL (1 << 8) -#define B_WEATHER_SUN (B_WEATHER_SUN_TEMPORARY | B_WEATHER_SUN_PERMANENT | B_WEATHER_SUN_PRIMAL) -#define B_WEATHER_HAIL_TEMPORARY (1 << 9) -#define B_WEATHER_HAIL_PERMANENT (1 << 10) -#define B_WEATHER_HAIL (B_WEATHER_HAIL_TEMPORARY | B_WEATHER_HAIL_PERMANENT) -#define B_WEATHER_STRONG_WINDS (1 << 11) -#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW | B_WEATHER_FOG) -#define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS) -#define B_WEATHER_SNOW_TEMPORARY (1 << 12) -#define B_WEATHER_SNOW_PERMANENT (1 << 13) -#define B_WEATHER_SNOW (B_WEATHER_SNOW_TEMPORARY | B_WEATHER_SNOW_PERMANENT) -#define B_WEATHER_FOG_TEMPORARY (1 << 14) -#define B_WEATHER_FOG_PERMANENT (1 << 15) -#define B_WEATHER_FOG (B_WEATHER_FOG_TEMPORARY | B_WEATHER_FOG_PERMANENT) - -// Battle Weather as enum -#define ENUM_WEATHER_NONE 0 -#define ENUM_WEATHER_RAIN 1 -#define ENUM_WEATHER_SUN 2 -#define ENUM_WEATHER_SANDSTORM 3 -#define ENUM_WEATHER_HAIL 4 -#define ENUM_WEATHER_SUN_PRIMAL 5 -#define ENUM_WEATHER_RAIN_PRIMAL 6 -#define ENUM_WEATHER_STRONG_WINDS 7 -#define ENUM_WEATHER_SNOW 8 -#define ENUM_WEATHER_FOG 9 +#define B_WEATHER_NONE 0 +#define B_WEATHER_RAIN_NORMAL (1 << BATTLE_WEATHER_RAIN) +#define B_WEATHER_RAIN_PRIMAL (1 << BATTLE_WEATHER_RAIN_PRIMAL) +#define B_WEATHER_RAIN_DOWNPOUR (1 << BATTLE_WEATHER_RAIN_DOWNPOUR) // unused +#define B_WEATHER_RAIN (B_WEATHER_RAIN_NORMAL | B_WEATHER_RAIN_PRIMAL | B_WEATHER_RAIN_DOWNPOUR) +#define B_WEATHER_SUN_NORMAL (1 << BATTLE_WEATHER_SUN) +#define B_WEATHER_SUN_PRIMAL (1 << BATTLE_WEATHER_SUN_PRIMAL) +#define B_WEATHER_SUN (B_WEATHER_SUN_NORMAL | B_WEATHER_SUN_PRIMAL) +#define B_WEATHER_SANDSTORM (1 << BATTLE_WEATHER_SANDSTORM) +#define B_WEATHER_HAIL (1 << BATTLE_WEATHER_HAIL) +#define B_WEATHER_SNOW (1 << BATTLE_WEATHER_SNOW) +#define B_WEATHER_FOG (1 << BATTLE_WEATHER_FOG) +#define B_WEATHER_STRONG_WINDS (1 << BATTLE_WEATHER_STRONG_WINDS) + +#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW | B_WEATHER_FOG) +#define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS) // Move Effects #define MOVE_EFFECT_SLEEP 1 @@ -418,7 +418,7 @@ #define MOVE_EFFECT_SALT_CURE 87 #define MOVE_EFFECT_EERIE_SPELL 88 -#define NUM_MOVE_EFFECTS 88 +#define NUM_MOVE_EFFECTS 89 #define MOVE_EFFECT_AFFECTS_USER 0x2000 #define MOVE_EFFECT_CERTAIN 0x4000 @@ -521,7 +521,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 @@ -539,15 +539,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 diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index ecde1e86683c..0e52c10128b9 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -31,7 +31,7 @@ #define AI_FLAG_CHECK_VIABILITY (1 << 2) // AI damaging moves and move effects to determine the best available move in the current situation. #define AI_FLAG_FORCE_SETUP_FIRST_TURN (1 << 3) // AI will prioritize using setup moves on the first turn at the expensve of all else. AI_FLAG_CHECK_VIABILITY will instead do this when the AI determines it makes sense. #define AI_FLAG_RISKY (1 << 4) // AI will generally behave more recklessly, prioritizing damage over accuracy, explosions, etc. -#define AI_FLAG_PREFER_STRONGEST_MOVE (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player. +#define AI_FLAG_TRY_TO_2HKO (1 << 5) // AI adds score bonus to any move the AI has that either OHKOs or 2HKOs the player. #define AI_FLAG_PREFER_BATON_PASS (1 << 6) // AI prefers raising its own stats and setting for / using Baton Pass. #define AI_FLAG_DOUBLE_BATTLE (1 << 7) // Automatically set for double battles, handles AI behaviour with partner. #define AI_FLAG_HP_AWARE (1 << 8) // AI will favour certain move effects based on how much remaining HP it and the player's mon have. @@ -50,8 +50,10 @@ #define AI_FLAG_SEQUENCE_SWITCHING (1 << 19) // AI switches in mons in exactly party order, and never switches mid-battle. #define AI_FLAG_DOUBLE_ACE_POKEMON (1 << 20) // AI has *two* Ace Pokémon. The last two Pokémons in the party won't be used unless they're the last ones remaining. Goes well in battles where the trainer ID equals to twins, couples, etc. #define AI_FLAG_WEIGH_ABILITY_PREDICTION (1 << 21) // AI will predict player's ability based on aiRating +#define AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE (1 << 22) // AI adds score to highest damage move regardless of accuracy or secondary effect +#define AI_FLAG_PREDICT_SWITCH (1 << 23) // AI will predict the player's switches and switchins based on how it would handle the situation. Recommend using AI_FLAG_OMNISCIENT -#define AI_FLAG_COUNT 22 +#define AI_FLAG_COUNT 24 // The following options are enough to have a basic/smart trainer. Any other addtion could make the trainer worse/better depending on the flag #define AI_FLAG_BASIC_TRAINER (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY) diff --git a/include/constants/battle_partner.h b/include/constants/battle_partner.h index 5622349a888c..c609ee5aa2b5 100644 --- a/include/constants/battle_partner.h +++ b/include/constants/battle_partner.h @@ -2,7 +2,8 @@ #ifndef GUARD_CONSTANTS_BATTLE_PARTNERS_H #define GUARD_CONSTANTS_BATTLE_PARTNERS_H -#define PARTNER_NONE 0 -#define PARTNER_STEVEN 1 +#define PARTNER_NONE 0 +#define PARTNER_STEVEN 1 +#define PARTNER_COUNT 2 #endif // GUARD_CONSTANTS_BATTLE_PARTNERS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index bd1c61ec0952..808ee406d289 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -216,8 +216,6 @@ enum CmdVarious VARIOUS_SAVE_BATTLER_ITEM, VARIOUS_RESTORE_BATTLER_ITEM, VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM, - VARIOUS_SWAP_SIDE_STATUSES, - VARIOUS_SWAP_STATS, }; // Cmd_manipulatedamage diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 5149e85bcf1a..a70ccbe5e84f 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -784,14 +784,25 @@ // gWeatherEndsStringIds #define B_MSG_WEATHER_END_RAIN 0 -#define B_MSG_WEATHER_END_SANDSTORM 1 -#define B_MSG_WEATHER_END_SUN 2 +#define B_MSG_WEATHER_END_SUN 1 +#define B_MSG_WEATHER_END_SANDSTORM 2 #define B_MSG_WEATHER_END_HAIL 3 -#define B_MSG_WEATHER_END_STRONG_WINDS 4 -#define B_MSG_WEATHER_END_SNOW 5 -#define B_MSG_WEATHER_END_FOG 6 +#define B_MSG_WEATHER_END_SNOW 4 +#define B_MSG_WEATHER_END_FOG 5 +#define B_MSG_WEATHER_END_STRONG_WINDS 6 #define B_MSG_WEATHER_END_COUNT 7 +// gWeatherTurnStringIds +#define B_MSG_WEATHER_TURN_RAIN 0 +#define B_MSG_WEATHER_TURN_DOWNPOUR 1 +#define B_MSG_WEATHER_TURN_SUN 2 +#define B_MSG_WEATHER_TURN_SANDSTORM 3 +#define B_MSG_WEATHER_TURN_HAIL 4 +#define B_MSG_WEATHER_TURN_SNOW 5 +#define B_MSG_WEATHER_TURN_FOG 6 +#define B_MSG_WEATHER_TURN_STRONG_WINDS 7 +#define B_MSG_WEATHER_TURN_COUNT 8 + // gRainContinuesStringIds #define B_MSG_RAIN_CONTINUES 0 #define B_MSG_DOWNPOUR_CONTINUES 1 @@ -1010,9 +1021,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 diff --git a/include/constants/difficulty.h b/include/constants/difficulty.h new file mode 100644 index 000000000000..44ef8d9d7192 --- /dev/null +++ b/include/constants/difficulty.h @@ -0,0 +1,15 @@ +#ifndef GUARD_DIFFICULTY_CONSTANTS_H +#define GUARD_DIFFICULTY_CONSTANTS_H + +enum DifficultyLevel +{ + DIFFICULTY_EASY, + DIFFICULTY_NORMAL, //If you rename this, the word "Normal" in fprint_trainers must be replaced with the new difficulty name. + DIFFICULTY_HARD, + DIFFICULTY_COUNT, +}; + +#define DIFFICULTY_MIN 0 +#define DIFFICULTY_MAX (DIFFICULTY_COUNT - 1) + +#endif // GUARD_DIFFICULTY_CONSTANTS_H diff --git a/include/constants/expansion.h b/include/constants/expansion.h index 1f2af1a22633..6b3a5ace78db 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -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 diff --git a/include/constants/field_effects.h b/include/constants/field_effects.h index f6e6106d90a3..48406195f0ba 100644 --- a/include/constants/field_effects.h +++ b/include/constants/field_effects.h @@ -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,5 +131,6 @@ #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 #endif // GUARD_FIELD_EFFECT_CONSTANTS_H diff --git a/include/constants/game_stat.h b/include/constants/game_stat.h index 5796afbaec6d..17e328d5beaf 100644 --- a/include/constants/game_stat.h +++ b/include/constants/game_stat.h @@ -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 diff --git a/include/constants/generational_changes.h b/include/constants/generational_changes.h new file mode 100644 index 000000000000..557b34b6537e --- /dev/null +++ b/include/constants/generational_changes.h @@ -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 diff --git a/include/constants/global.h b/include/constants/global.h index 89508e374d82..3476bd3680d2 100644 --- a/include/constants/global.h +++ b/include/constants/global.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. diff --git a/include/constants/party_menu.h b/include/constants/party_menu.h index 1f37f3416c96..e997dd566dc1 100644 --- a/include/constants/party_menu.h +++ b/include/constants/party_menu.h @@ -81,6 +81,7 @@ #define PARTY_MSG_ALREADY_HOLDING_ONE 26 #define PARTY_MSG_WHICH_APPLIANCE 27 #define PARTY_MSG_CHOOSE_SECOND_FUSION 28 +#define PARTY_MSG_NO_POKEMON 29 #define PARTY_MSG_NONE 127 // IDs for DisplayPartyPokemonDescriptionText, to display a message in the party pokemon's box diff --git a/include/constants/species.h b/include/constants/species.h index b94a15a39640..3656d7664ec8 100644 --- a/include/constants/species.h +++ b/include/constants/species.h @@ -1214,15 +1214,15 @@ #define SPECIES_FLORGES_ORANGE 1143 #define SPECIES_FLORGES_BLUE 1144 #define SPECIES_FLORGES_WHITE 1145 -#define SPECIES_FURFROU_HEART_TRIM 1146 -#define SPECIES_FURFROU_STAR_TRIM 1147 -#define SPECIES_FURFROU_DIAMOND_TRIM 1148 -#define SPECIES_FURFROU_DEBUTANTE_TRIM 1149 -#define SPECIES_FURFROU_MATRON_TRIM 1150 -#define SPECIES_FURFROU_DANDY_TRIM 1151 -#define SPECIES_FURFROU_LA_REINE_TRIM 1152 -#define SPECIES_FURFROU_KABUKI_TRIM 1153 -#define SPECIES_FURFROU_PHARAOH_TRIM 1154 +#define SPECIES_FURFROU_HEART 1146 +#define SPECIES_FURFROU_STAR 1147 +#define SPECIES_FURFROU_DIAMOND 1148 +#define SPECIES_FURFROU_DEBUTANTE 1149 +#define SPECIES_FURFROU_MATRON 1150 +#define SPECIES_FURFROU_DANDY 1151 +#define SPECIES_FURFROU_LA_REINE 1152 +#define SPECIES_FURFROU_KABUKI 1153 +#define SPECIES_FURFROU_PHARAOH 1154 #define SPECIES_MEOWSTIC_F 1155 #define SPECIES_AEGISLASH_BLADE 1156 #define SPECIES_PUMPKABOO_SMALL 1157 diff --git a/include/constants/weather.h b/include/constants/weather.h index c4a23a18bc77..32dc97a1a27e 100644 --- a/include/constants/weather.h +++ b/include/constants/weather.h @@ -19,6 +19,7 @@ #define WEATHER_ABNORMAL 15 // The alternating weather during Groudon/Kyogre conflict #define WEATHER_ROUTE119_CYCLE 20 #define WEATHER_ROUTE123_CYCLE 21 +#define WEATHER_COUNT 22 // These are used in maps' coord_weather_event entries. // They are not a one-to-one mapping with the engine's diff --git a/include/constants/wild_encounter.h b/include/constants/wild_encounter.h index ae669a2c35a2..364d18350fc4 100644 --- a/include/constants/wild_encounter.h +++ b/include/constants/wild_encounter.h @@ -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 diff --git a/include/contest.h b/include/contest.h index 8a3b6a3c6558..acd12a4ebc6e 100644 --- a/include/contest.h +++ b/include/contest.h @@ -109,7 +109,6 @@ struct ContestPokemon bool8 gameCleared; u8 isShiny:1; u8 unused1:7; - u8 unused2[9]; u32 personality; u32 otId; }; diff --git a/include/data.h b/include/data.h index ef59aae56930..1d2a1291f954 100644 --- a/include/data.h +++ b/include/data.h @@ -3,6 +3,8 @@ #include "constants/moves.h" #include "constants/trainers.h" +#include "constants/battle.h" +#include "difficulty.h" #define MAX_TRAINER_ITEMS 4 @@ -88,7 +90,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; @@ -112,7 +114,8 @@ struct TypeInfo u16 damageCategory:2; // Used for B_PHYSICAL_SPECIAL_SPLIT <= GEN_3 u16 useSecondTypeIconPalette:1; u16 isSpecialCaseType:1; - u16 padding:12; + u16 isHiddenPowerType:1; // Changing this for any type will change the distribution of all Hidden Power types from vanilla. + u16 padding:11; const u32 *const paletteTMHM; //u16 enhanceItem; //u16 berry; @@ -164,8 +167,8 @@ extern const union AnimCmd *const sAnims_Trainer[]; extern const struct TrainerSprite gTrainerSprites[]; extern const struct TrainerBacksprite gTrainerBacksprites[]; -extern const struct Trainer gTrainers[]; -extern const struct Trainer gBattlePartners[]; +extern const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT]; +extern const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT]; extern const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT]; @@ -191,71 +194,103 @@ static inline u16 SanitizeTrainerId(u16 trainerId) static inline const struct Trainer *GetTrainerStructFromId(u16 trainerId) { - return &gTrainers[SanitizeTrainerId(trainerId)]; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return &gTrainers[difficulty][sanitizedTrainerId]; } static inline const u8 GetTrainerClassFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].trainerClass; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].trainerClass; } static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) { + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId); + if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) - return gTrainerClasses[gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass].name; + return gTrainerClasses[gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass].name; return gTrainerClasses[GetTrainerClassFromId(trainerId)].name; } static inline const u8 *GetTrainerNameFromId(u16 trainerId) { + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId); + if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) - return gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; - return gTrainers[SanitizeTrainerId(trainerId)].trainerName; + return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; + return gTrainers[difficulty][sanitizedTrainerId].trainerName; } static inline const u8 GetTrainerPicFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].trainerPic; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].trainerPic; } static inline const u8 GetTrainerStartingStatusFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].startingStatus; + return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].startingStatus; } static inline const bool32 IsTrainerDoubleBattle(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].doubleBattle; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].doubleBattle; } static inline const u8 GetTrainerPartySizeFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].partySize; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].partySize; } static inline const bool32 DoesTrainerHaveMugshot(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].mugshotEnabled; + return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].mugshotColor; } static inline const u8 GetTrainerMugshotColorFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].mugshotColor; + return gTrainers[GetCurrentDifficultyLevel()][SanitizeTrainerId(trainerId)].mugshotColor; } static inline const u16 *GetTrainerItemsFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].items; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].items; } static inline const struct TrainerMon *GetTrainerPartyFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].party; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].party; } static inline const bool32 GetTrainerAIFlagsFromId(u16 trainerId) { - return gTrainers[SanitizeTrainerId(trainerId)].aiFlags; + u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + + return gTrainers[difficulty][sanitizedTrainerId].aiFlags; } #endif // GUARD_DATA_H diff --git a/include/daycare.h b/include/daycare.h index 4d5b470f8b3e..a7ef5581f91f 100644 --- a/include/daycare.h +++ b/include/daycare.h @@ -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 diff --git a/include/dexnav.h b/include/dexnav.h new file mode 100644 index 000000000000..baa8f8c5a74f --- /dev/null +++ b/include/dexnav.h @@ -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 diff --git a/include/difficulty.h b/include/difficulty.h new file mode 100644 index 000000000000..c8443367c91d --- /dev/null +++ b/include/difficulty.h @@ -0,0 +1,17 @@ +#ifndef GUARD_DIFFICULTY_H +#define GUARD_DIFFICULTY_H + +#include "constants/difficulty.h" +#include "script.h" + +enum DifficultyLevel GetCurrentDifficultyLevel(void); +void SetCurrentDifficultyLevel(enum DifficultyLevel); + +enum DifficultyLevel GetBattlePartnerDifficultyLevel(u16); +enum DifficultyLevel GetTrainerDifficultyLevel(u16); +void Script_IncreaseDifficulty(void); +void Script_DecreaseDifficulty(void); +void Script_GetDifficulty(void); +void Script_SetDifficulty(struct ScriptContext *); + +#endif // GUARD_DIFFICULTY_H diff --git a/include/event_object_movement.h b/include/event_object_movement.h index 4b1b3e1f9ff3..f6aa18280f78 100644 --- a/include/event_object_movement.h +++ b/include/event_object_movement.h @@ -316,6 +316,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 *); diff --git a/include/event_scripts.h b/include/event_scripts.h index 60a8d6123e55..772a7a955dcf 100644 --- a/include/event_scripts.h +++ b/include/event_scripts.h @@ -36,6 +36,7 @@ extern const u8 EventScript_TryDoDoubleTrainerBattle[]; extern const u8 EventScript_TryDoNormalTrainerBattle[]; extern const u8 EventScript_TryDoDoubleRematchBattle[]; extern const u8 EventScript_TryDoRematchBattle[]; +extern const u8 EventScript_ObjectApproachPlayer[]; extern const u8 BerryTreeScript[]; @@ -405,6 +406,7 @@ extern const u8 EventScript_UseFlash[]; extern const u8 EventScript_UseCut[]; extern const u8 EventScript_UseRockSmash[]; extern const u8 EventScript_UseDig[]; +extern const u8 EventScript_UseCutGrass[]; //player pc extern const u8 LittlerootTown_BrendansHouse_2F_EventScript_TurnOffPlayerPC[]; @@ -653,5 +655,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 diff --git a/include/field_control_avatar.h b/include/field_control_avatar.h index da23fe433683..9a55f9e7bf06 100644 --- a/include/field_control_avatar.h +++ b/include/field_control_avatar.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; diff --git a/include/field_effect.h b/include/field_effect.h index 93a74f1ba274..3db86bc21975 100644 --- a/include/field_effect.h +++ b/include/field_effect.h @@ -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 diff --git a/include/field_weather.h b/include/field_weather.h index ba45d161b770..cff2eb5bc3f3 100644 --- a/include/field_weather.h +++ b/include/field_weather.h @@ -33,7 +33,6 @@ struct Weather } s1; struct { - u8 filler0[0xA0]; struct Sprite *fogHSprites[NUM_FOG_HORIZONTAL_SPRITES]; struct Sprite *ashSprites[NUM_ASH_SPRITES]; struct Sprite *fogDSprites[NUM_FOG_DIAGONAL_SPRITES]; @@ -129,7 +128,6 @@ struct Weather s16 droughtLastBrightnessStage; s16 droughtTimer; s16 droughtState; - u8 droughtUnused[9]; u8 loadDroughtPalsIndex; u8 loadDroughtPalsOffset; }; diff --git a/include/generational_changes.h b/include/generational_changes.h new file mode 100644 index 000000000000..5a726007c36e --- /dev/null +++ b/include/generational_changes.h @@ -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 diff --git a/include/global.fieldmap.h b/include/global.fieldmap.h index d686a624a235..8540d7b18583 100644 --- a/include/global.fieldmap.h +++ b/include/global.fieldmap.h @@ -323,7 +323,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; diff --git a/include/global.h b/include/global.h index 687281eaa7d8..3e5e984547c5 100644 --- a/include/global.h +++ b/include/global.h @@ -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; diff --git a/include/main.h b/include/main.h index eba04cbaa9a1..b64c9349a8c0 100644 --- a/include/main.h +++ b/include/main.h @@ -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); diff --git a/include/move.h b/include/move.h new file mode 100644 index 000000000000..67206d9ba232 --- /dev/null +++ b/include/move.h @@ -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 diff --git a/include/overworld.h b/include/overworld.h index 28a4aa9277b7..ea23c15b3040 100644 --- a/include/overworld.h +++ b/include/overworld.h @@ -52,6 +52,7 @@ extern bool8 (*gFieldCallback2)(void); extern u8 gLocalLinkPlayerId; extern u8 gFieldLinkPlayerCount; extern bool8 gExitStairsMovementDisabled; +extern bool8 gSkipShowMonAnim; extern const struct UCoords32 gDirectionToVectors[]; diff --git a/include/party_menu.h b/include/party_menu.h index a34f06cec6bb..5236dd27a702 100644 --- a/include/party_menu.h +++ b/include/party_menu.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; diff --git a/include/player_pc.h b/include/player_pc.h index 2521eac13103..305c661766af 100644 --- a/include/player_pc.h +++ b/include/player_pc.h @@ -9,7 +9,6 @@ struct PlayerPCItemPageStruct u16 itemsAbove; u8 pageItems; u8 count; - u8 filler[3]; u8 scrollIndicatorTaskId; }; diff --git a/include/pokemon.h b/include/pokemon.h index 0618c6c78573..bc92b73c7564 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -479,125 +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; - - 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; - - 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 - - // 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__ )) - -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 Ability { u8 name[ABILITY_NAME_LENGTH + 1]; @@ -727,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[]; @@ -840,6 +720,7 @@ u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit u8 *UseStatIncreaseItem(u16 itemId); u8 GetNature(struct Pokemon *mon); u8 GetNatureFromPersonality(u32 personality); +u32 GetGMaxTargetSpecies(u32 species); u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 evolutionItem, struct Pokemon *tradePartner); bool8 IsMonPastEvolutionLevel(struct Pokemon *mon); u16 NationalPokedexNumToSpecies(u16 nationalNum); @@ -903,8 +784,8 @@ void DestroyMonSpritesGfxManager(u8 managerId); u8 *MonSpritesGfxManager_GetSpritePtr(u8 managerId, u8 spriteNum); u16 GetFormSpeciesId(u16 speciesId, u8 formId); u8 GetFormIdFromFormSpeciesId(u16 formSpeciesId); -u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg); -u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg); +u32 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg); +u32 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); @@ -921,10 +802,9 @@ 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); +uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier); #endif // GUARD_POKEMON_H diff --git a/include/pokemon_icon.h b/include/pokemon_icon.h index 9e51e1bc4d60..3986f8948b0c 100644 --- a/include/pokemon_icon.h +++ b/include/pokemon_icon.h @@ -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 diff --git a/include/pokemon_summary_screen.h b/include/pokemon_summary_screen.h index fe299c48b4bf..1f286698a56d 100755 --- a/include/pokemon_summary_screen.h +++ b/include/pokemon_summary_screen.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; diff --git a/include/pokenav.h b/include/pokenav.h index 174c338e270f..5c238a6c5407 100644 --- a/include/pokenav.h +++ b/include/pokenav.h @@ -171,6 +171,8 @@ enum HELPBAR_NONE, HELPBAR_MAP_ZOOMED_OUT, HELPBAR_MAP_ZOOMED_IN, + HELPBAR_MAP_ZOOMED_OUT_CANFLY, + HELPBAR_MAP_ZOOMED_IN_CANFLY, HELPBAR_CONDITION_MON_LIST, HELPBAR_CONDITION_MON_STATUS, HELPBAR_CONDITION_MARKINGS, @@ -295,6 +297,7 @@ enum POKENAV_MAP_FUNC_ZOOM_OUT, POKENAV_MAP_FUNC_ZOOM_IN, POKENAV_MAP_FUNC_EXIT, + POKENAV_MAP_FUNC_FLY }; // Modes for PokenavFadeScreen @@ -438,6 +441,7 @@ void CreateRegionMapLoopedTask(s32); bool32 IsRegionMapLoopedTaskActive(void); void FreeRegionMapSubstruct1(void); void FreeRegionMapSubstruct2(void); +void UpdateRegionMapHelpBarText(void); // pokenav_conditions.c u32 PokenavCallback_Init_ConditionGraph_Party(void); diff --git a/include/random.h b/include/random.h index 000bc1302ced..1a735097d32d 100644 --- a/include/random.h +++ b/include/random.h @@ -175,7 +175,9 @@ enum RandomTag RNG_SHELL_SIDE_ARM, RNG_RANDOM_TARGET, RNG_AI_PREDICT_ABILITY, + RNG_AI_PREDICT_SWITCH, RNG_HEALER, + RNG_DEXNAV_ENCOUNTER_LEVEL, }; #define RandomWeighted(tag, ...) \ diff --git a/include/region_map.h b/include/region_map.h index 9f0b110a658f..08277651dec5 100644 --- a/include/region_map.h +++ b/include/region_map.h @@ -14,6 +14,7 @@ enum MAP_INPUT_MOVE_END, MAP_INPUT_A_BUTTON, MAP_INPUT_B_BUTTON, + MAP_INPUT_R_BUTTON }; enum { @@ -115,6 +116,10 @@ void TrySetPlayerIconBlink(void); void BlendRegionMap(u16 color, u32 coeff); void SetRegionMapDataForZoom(void); +//Pokenav Fly funcs +u32 FilterFlyDestination(struct RegionMap* regionMap); +void SetFlyDestination(struct RegionMap* regionMap); + extern const struct RegionMapLocation gRegionMapEntries[]; #endif //GUARD_REGION_MAP_H diff --git a/include/scanline_effect.h b/include/scanline_effect.h index 80d9df764d6a..0b395d4f609b 100644 --- a/include/scanline_effect.h +++ b/include/scanline_effect.h @@ -30,8 +30,6 @@ struct ScanlineEffect void (*setFirstScanlineReg)(void); u8 srcBuffer; u8 state; - u8 unused16; - u8 unused17; u8 waveTaskId; }; diff --git a/include/script.h b/include/script.h index 1f3c4f7afb95..1546d15dd487 100644 --- a/include/script.h +++ b/include/script.h @@ -11,6 +11,7 @@ struct ScriptContext u8 stackDepth; u8 mode; u8 comparisonResult; + bool8 breakOnTrainerBattle; u8 (*nativePtr)(void); const u8 *scriptPtr; const u8 *stack[20]; @@ -39,12 +40,13 @@ void ScriptContext_Init(void); bool8 ScriptContext_IsEnabled(void); bool8 ScriptContext_RunScript(void); void ScriptContext_SetupScript(const u8 *ptr); +void ScriptContext_ContinueScript(struct ScriptContext *ctx); void ScriptContext_Stop(void); void ScriptContext_Enable(void); void RunScriptImmediately(const u8 *ptr); -u8 *MapHeaderGetScriptTable(u8 tag); +const u8 *MapHeaderGetScriptTable(u8 tag); void MapHeaderRunScriptType(u8 tag); -u8 *MapHeaderCheckScriptTable(u8 tag); +const u8 *MapHeaderCheckScriptTable(u8 tag); void RunOnLoadMapScript(void); void RunOnTransitionMapScript(void); void RunOnResumeMapScript(void); @@ -66,4 +68,110 @@ void SetMovingNpcId(u16 npcId); extern u8 gMsgIsSignPost; extern u8 gMsgBoxIsCancelable; +/* Script effects analysis. + * + * 'RunScriptImmediatelyUntilEffect' executes a script until it reaches + * the first command which calls 'Script_RequestEffects' with an + * effect in 'effects' in which case it returns 'TRUE' and stores the + * current state in 'ctx'; or until it reaches an 'end'/'return' in + * which case it returns 'FALSE'. + * + * 'Script_HasNoEffect' wraps 'RunScriptImmediatelyUntilEffect' and + * returns 'TRUE' if the script exits without an effect on the save or + * the hardware, or 'FALSE' if it would have an effect (the effect is + * not performed). + * + * Commands, natives, and specials which call 'Script_RequestEffects' + * must be explicitly tagged with 'requests_effects=1', and must call + * the function before any of those effects occur. An untagged function + * could cause any effect, so execution is stopped to be safe. If the + * code has no effects it must call 'Script_RequestEffects(SCREFF_V1)' + * to note that explicitly. + * + * Regular variables are in the save (so should use 'SCREFF_SAVE'), but + * special variables are not in the save, so 'Script_RequestWriteVar' is + * provided to only request the 'SCREFF_SAVE' effect for a non-special + * variable. + * + * The 'effects' parameter to 'RunScriptImmediatelyUntilEffect' and + * 'Script_RequestEffects' must be the bitwise or of an effects version + * (currently 'SCREFF_V1') and any number of effects. For example + * 'Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE)'. */ + +enum // effects +{ + SCREFF_SAVE = 1 << 0, // writes to the save. + SCREFF_HARDWARE = 1 << 1, // writes to a hardware register. + SCREFF_TRAINERBATTLE = 1 << 2, // 'trainerbattle' command. +}; + +#define SCREFF_ANY (SCREFF_SAVE | SCREFF_HARDWARE | SCREFF_TRAINERBATTLE) + +enum // effects versions +{ + SCREFF_V1 = 0xFFFFFFF8, +}; + +extern struct ScriptEffectContext *gScriptEffectContext; + +bool32 RunScriptImmediatelyUntilEffect_Internal(u32 effects, const u8 *ptr, struct ScriptContext *ctx); +bool32 Script_HasNoEffect(const u8 *ptr); +void Script_GotoBreak_Internal(void); +void Script_RequestEffects_Internal(u32 effects); +void Script_RequestWriteVar_Internal(u32 varId); + +static inline bool32 Script_IsAnalyzingEffects(void) +{ + return gScriptEffectContext != NULL; +} + +#define RunScriptImmediatelyUntilEffect(effects, ptr, ctx) \ + ({ \ + _Static_assert((effects) & 0x80000000, "RunScriptImmediatelyUntilEffect requires an effects version"); \ + RunScriptImmediatelyUntilEffect_Internal(effects, ptr, ctx); \ + }) + +/* Optimize 'Script_RequestEffects' to a no-op if it would have no + * effect. 'Script_RequestEffects' must be called in all commands and + * natives/specials with 'request_effects=TRUE' even if it would have + * no effect to future-proof against new effects. */ +#define Script_RequestEffects(effects) \ + ({ \ + _Static_assert((effects) & 0x80000000, "Script_RequestEffects requires an effects version"); \ + if ((effects) != SCREFF_V1) \ + if (Script_IsAnalyzingEffects()) \ + Script_RequestEffects_Internal((effects) & SCREFF_ANY); \ + }) + +/* Optimize 'Script_RequestWriteVar' to a no-op if it would have no + * effect. */ +#define Script_RequestWriteVar(varId) \ + ({ \ + if (Script_IsAnalyzingEffects()) \ + Script_RequestWriteVar_Internal(varId); \ + }) + +static inline void Script_CheckEffectInstrumentedSpecial(u32 specialId) +{ + typedef u16 (*SpecialFunc)(void); + extern const SpecialFunc gSpecials[]; + // In ROM mirror 1. + if (Script_IsAnalyzingEffects() && (((uintptr_t)gSpecials[specialId]) & 0xE000000) != 0xA000000) + Script_GotoBreak_Internal(); +} + +static inline void Script_CheckEffectInstrumentedGotoNative(bool8 (*func)(void)) +{ + // In ROM mirror 1. + if (Script_IsAnalyzingEffects() && (((uintptr_t)func) & 0xE000000) != 0xA000000) + Script_GotoBreak_Internal(); +} + +static inline void Script_CheckEffectInstrumentedCallNative(void (*func)(struct ScriptContext *)) +{ + // In ROM mirror 1. + if (Script_IsAnalyzingEffects() && (((uintptr_t)func) & 0xE000000) != 0xA000000) + Script_GotoBreak_Internal(); +} + #endif // GUARD_SCRIPT_H diff --git a/include/strings.h b/include/strings.h index 8e1f797079e1..06a3a658a25b 100644 --- a/include/strings.h +++ b/include/strings.h @@ -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[]; diff --git a/include/test/battle.h b/include/test/battle.h index 7cf70539881a..1c044fd6e2f6 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -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); diff --git a/include/test/overworld_script.h b/include/test/overworld_script.h index e2f65930f5d1..9b85f82ac353 100644 --- a/include/test/overworld_script.h +++ b/include/test/overworld_script.h @@ -42,6 +42,17 @@ #define RUN_OVERWORLD_SCRIPT(...) RunScriptImmediately(OVERWORLD_SCRIPT(__VA_ARGS__)) +// Make important constants available. +// TODO: Find a better approach to this. +asm(".set FALSE, 0\n" + ".set TRUE, 1\n" + ".set PARTY_SIZE, " STR(PARTY_SIZE) "\n" + ".set VARS_START, " STR(VARS_START) "\n" + ".set VARS_END, " STR(VARS_END) "\n" + ".set SPECIAL_VARS_START, " STR(SPECIAL_VARS_START) "\n" + ".set SPECIAL_VARS_END, " STR(SPECIAL_VARS_END) "\n"); +asm(".include \"constants/gba_constants.inc\"\n"); + // Make overworld script macros available. asm(".include \"asm/macros/event.inc\"\n"); diff --git a/include/text_window.h b/include/text_window.h index a292d1309e71..98776193f649 100644 --- a/include/text_window.h +++ b/include/text_window.h @@ -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 diff --git a/include/trainer_card.h b/include/trainer_card.h index 7c37a84a6c2e..9e5e53df664d 100644 --- a/include/trainer_card.h +++ b/include/trainer_card.h @@ -50,7 +50,6 @@ struct TrainerCard u32 frontier; } linkPoints; // This field is used differently by FRLG vs Emerald /*0x40*/ u32 unionRoomNum; - /*0x44*/ u8 filler[8]; /*0x4C*/ bool8 shouldDrawStickers; // FRLG only /*0x4D*/ u8 unused; /*0x4E*/ u8 monIconTint; // FRLG only diff --git a/include/wild_encounter.h b/include/wild_encounter.h index 63289f081ccc..c7abb72aa1fa 100644 --- a/include/wild_encounter.h +++ b/include/wild_encounter.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 diff --git a/ld_script_test.ld b/ld_script_test.ld index 8972a97b008d..d279d6b4f6a1 100644 --- a/ld_script_test.ld +++ b/ld_script_test.ld @@ -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. */ - /* .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); + . = 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); diff --git a/spritesheet_rules.mk b/spritesheet_rules.mk index 88725dda66d7..b1cc2ac02540 100644 --- a/spritesheet_rules.mk +++ b/spritesheet_rules.mk @@ -4212,31 +4212,31 @@ $(POKEMONGFXDIR)/florges/orange/overworld.4bpp: %.4bpp: %.png $(POKEMONGFXDIR)/florges/white/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/heart_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/heart/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/star_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/star/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/diamond_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/diamond/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/debutante_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/debutante/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/matron_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/matron/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/dandy_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/dandy/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/la_reine_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/la_reine/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/kabuki_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/kabuki/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 -$(POKEMONGFXDIR)/furfrou/pharaoh_trim/overworld.4bpp: %.4bpp: %.png +$(POKEMONGFXDIR)/furfrou/pharaoh/overworld.4bpp: %.4bpp: %.png $(GFX) $< $@ -mwidth 4 -mheight 4 $(POKEMONGFXDIR)/hoopa/unbound/overworld.4bpp: %.4bpp: %.png diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 83182fe07c01..8482716f5b55 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -48,7 +48,7 @@ static s32 AI_TryToFaint(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_CheckViability(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_ForceSetupFirstTurn(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); -static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); +static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_PreferBatonPass(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_HPAware(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_Roaming(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); @@ -57,7 +57,7 @@ static s32 AI_FirstBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 AI_DynamicFunc(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); - +static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score); static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = { @@ -66,7 +66,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = [2] = AI_CheckViability, // AI_FLAG_CHECK_VIABILITY [3] = AI_ForceSetupFirstTurn, // AI_FLAG_FORCE_SETUP_FIRST_TURN [4] = AI_Risky, // AI_FLAG_RISKY - [5] = AI_PreferStrongestMove, // AI_FLAG_PREFER_STRONGEST_MOVE + [5] = AI_TryTo2HKO, // AI_FLAG_TRY_TO_2HKO [6] = AI_PreferBatonPass, // AI_FLAG_PREFER_BATON_PASS [7] = AI_DoubleBattle, // AI_FLAG_DOUBLE_BATTLE [8] = AI_HPAware, // AI_FLAG_HP_AWARE @@ -84,7 +84,7 @@ static s32 (*const sBattleAiFuncTable[])(u32, u32, u32, s32) = [20] = NULL, // Unused [21] = NULL, // Unused [22] = NULL, // Unused - [23] = NULL, // Unused + [23] = AI_PredictSwitch, // AI_FLAG_PREDICT_SWITCH [24] = NULL, // Unused [25] = NULL, // Unused [26] = NULL, // Unused @@ -136,7 +136,7 @@ static u32 GetWildAiFlags(void) if (avgLevel >= 20) flags |= AI_FLAG_CHECK_VIABILITY; if (avgLevel >= 60) - flags |= AI_FLAG_PREFER_STRONGEST_MOVE; + flags |= AI_FLAG_TRY_TO_2HKO; if (avgLevel >= 80) flags |= AI_FLAG_HP_AWARE; @@ -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)) @@ -733,7 +734,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) RETURN_SCORE_MINUS(10); - if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + if (gBattleStruct->battlerState[battlerDef].commandingDondozo) RETURN_SCORE_MINUS(20); // check if negates type @@ -799,16 +800,16 @@ 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; case ABILITY_AROMA_VEIL: - if (IsAromaVeilProtectedMove(move)) + if (IsAromaVeilProtectedEffect(moveEffect)) RETURN_SCORE_MINUS(10); break; case ABILITY_SWEET_VEIL: @@ -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: @@ -901,7 +902,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) RETURN_SCORE_MINUS(10); break; case ABILITY_AROMA_VEIL: - if (IsAromaVeilProtectedMove(move)) + if (IsAromaVeilProtectedEffect(moveEffect)) RETURN_SCORE_MINUS(10); break; } @@ -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)) @@ -946,16 +947,17 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) weather = AI_GetWeather(aiData); if (weather & B_WEATHER_PRIMAL_ANY) { - switch (move) + switch (moveEffect) { - case MOVE_SUNNY_DAY: - case MOVE_RAIN_DANCE: - case MOVE_HAIL: - case MOVE_SANDSTORM: + case EFFECT_SUNNY_DAY: + case EFFECT_RAIN_DANCE: + case EFFECT_HAIL: + case EFFECT_SNOWSCAPE: + case EFFECT_SANDSTORM: RETURN_SCORE_MINUS(30); } - if (!IS_MOVE_STATUS(move)) + if (!IsBattleMoveStatus(move)) { if (weather & B_WEATHER_SUN_PRIMAL) { @@ -974,7 +976,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: @@ -1326,6 +1328,14 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) // AI_CBM_HighRiskForDamage if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) ADJUST_SCORE(-10); + if (HasDamagingMove(battlerDef) && !((gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE) + || IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) + || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))) + ADJUST_SCORE(-10); + if (HasMoveEffect(battlerAtk, EFFECT_SUBSTITUTE) && !(gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE)) + ADJUST_SCORE(-10); + if (HasMoveEffect(battlerAtk, EFFECT_SLEEP) && ! (gBattleMons[battlerDef].status1 & STATUS1_SLEEP)) + ADJUST_SCORE(-10); break; case EFFECT_COUNTER: case EFFECT_MIRROR_COAT: @@ -1696,7 +1706,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 +1802,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 +1893,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 +1995,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,11 +2025,11 @@ 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]) - && (move == MOVE_FLY || move == MOVE_BOUNCE)) + && GetMoveTwoTurnAttackStatus(move) == STATUS3_ON_AIR) ADJUST_SCORE(-10); // Attacker will faint while in the air break; case EFFECT_HEALING_WISH: //healing wish, lunar dance @@ -2247,7 +2257,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)) @@ -2257,7 +2267,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } break; case EFFECT_TRICK_ROOM: - if (PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_TRICK_ROOM)) + if (PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_TRICK_ROOM)) { ADJUST_SCORE(-10); } @@ -2366,17 +2376,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; } case EFFECT_THIRD_TYPE: - switch (move) - { - case MOVE_TRICK_OR_TREAT: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) || GetActiveGimmick(battlerDef) == GIMMICK_TERA) - ADJUST_SCORE(-10); - break; - case MOVE_FORESTS_CURSE: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) || GetActiveGimmick(battlerDef) == GIMMICK_TERA) - ADJUST_SCORE(-10); - break; - } + if (IS_BATTLER_OF_TYPE(battlerDef, GetMoveArgType(move)) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) || GetActiveGimmick(battlerDef) == GIMMICK_TERA) + ADJUST_SCORE(-10); break; case EFFECT_HEAL_PULSE: // and floral healing if (!IS_TARGETING_PARTNER(battlerAtk, battlerDef)) // Don't heal enemies @@ -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,13 +2483,13 @@ 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; case EFFECT_TAILWIND: if (gSideTimers[GetBattlerSide(battlerAtk)].tailwindTimer != 0 - || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_TAILWIND) + || PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_TAILWIND) || (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && gFieldTimers.trickRoomTimer > 1)) // Trick Room active and not ending this turn ADJUST_SCORE(-10); break; @@ -2565,9 +2566,8 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_TAKE_HEART: if ((!(gBattleMons[battlerAtk].status1 & STATUS1_ANY) - || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_JUNGLE_HEALING) - || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_HEAL_BELL) - || PartnerMoveIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, MOVE_AROMATHERAPY)) + || PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_JUNGLE_HEALING) + || PartnerMoveEffectIs(BATTLE_PARTNER(battlerAtk), aiData->partnerMove, EFFECT_HEAL_BELL)) && !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPATK) && !BattlerStatCanRise(battlerAtk, aiData->abilities[battlerAtk], STAT_SPDEF)) ADJUST_SCORE(-10); @@ -2581,7 +2581,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: @@ -2617,10 +2617,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); @@ -2629,7 +2629,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); } @@ -2641,29 +2641,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: @@ -2687,7 +2688,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 { @@ -2695,7 +2696,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); } } @@ -2724,7 +2725,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; @@ -2777,7 +2778,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)) @@ -2833,7 +2834,7 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case ABILITY_FLASH_FIRE: if (moveType == TYPE_FIRE && HasMoveWithType(battlerAtkPartner, TYPE_FIRE) - && !(gBattleResources->flags->flags[battlerAtkPartner] & RESOURCE_FLAG_FLASH_FIRE)) + && !gDisableStructs[battlerAtkPartner].flashFireBoosted) { RETURN_SCORE_PLUS(WEAK_EFFECT); } @@ -2848,7 +2849,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)) @@ -2857,7 +2858,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)) @@ -2914,7 +2915,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)) @@ -2984,7 +2985,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); @@ -2995,7 +2996,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); } @@ -3069,7 +3070,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); } @@ -3088,7 +3089,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])) @@ -3180,27 +3181,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 @@ -3389,7 +3391,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) @@ -3405,7 +3407,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: @@ -3582,7 +3584,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: @@ -3630,7 +3632,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: @@ -3645,13 +3647,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: @@ -3799,10 +3801,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; @@ -3857,13 +3860,6 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) //if (CountUsablePartyMons(battlerDef) != 0) //ADJUST_SCORE(8); break; - case EFFECT_PURSUIT: - // TODO - // if (IsPredictedToSwitch(battlerDef, battlerAtk)) - // ADJUST_SCORE(GOOD_EFFECT); - // else if (IsPredictedToUsePursuitableMove(battlerDef, battlerAtk) && !MoveWouldHitFirst(move, battlerAtk, battlerDef)) //Pursuit against fast U-Turn - // ADJUST_SCORE(GOOD_EFFECT); - // break; case EFFECT_DEFOG: if ((gSideStatuses[GetBattlerSide(battlerAtk)] & SIDE_STATUS_HAZARDS_ANY && CountUsablePartyMons(battlerAtk) != 0) || (gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SCREEN_ANY | SIDE_STATUS_SAFEGUARD | SIDE_STATUS_MIST))) @@ -3874,7 +3870,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 } @@ -3889,13 +3885,13 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) break; case EFFECT_FOLLOW_ME: if (isDoubleBattle - && move != MOVE_SPOTLIGHT + && GetMoveTarget(move) == MOVE_TARGET_USER && !IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) - && (move != MOVE_RAGE_POWDER || IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) // Rage Powder doesn't affect powder immunities + && (!IsPowderMove(move) || IsAffectedByPowder(battlerDef, aiData->abilities[battlerDef], aiData->holdEffects[battlerDef])) // Rage Powder doesn't affect powder immunities && 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; @@ -3906,7 +3902,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); @@ -3970,7 +3966,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]) { @@ -4031,7 +4027,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: @@ -4111,7 +4107,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: @@ -4278,7 +4274,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: @@ -4309,7 +4305,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: @@ -4325,7 +4321,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 == 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: @@ -4367,7 +4363,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; } @@ -4381,7 +4377,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,28 +4433,30 @@ static u32 AI_CalcMoveEffectScore(u32 battlerAtk, u32 battlerDef, u32 move) 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: @@ -4466,7 +4464,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: @@ -4486,14 +4484,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: @@ -4501,7 +4499,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: @@ -4530,7 +4528,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); @@ -4663,11 +4661,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); @@ -4698,13 +4696,14 @@ 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 else { - if ((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_RISKY) && GetBestDmgMoveFromBattler(battlerAtk, battlerDef) == move) + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & (AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE) + && GetBestDmgMoveFromBattler(battlerAtk, battlerDef) == move) ADJUST_SCORE(BEST_DAMAGE_MOVE); else ADJUST_SCORE(AI_CompareDamagingMoves(battlerAtk, battlerDef, AI_THINKING_STRUCT->movesetIndex)); @@ -4727,13 +4726,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: @@ -4825,9 +4824,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: @@ -4854,11 +4855,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) @@ -4897,9 +4898,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) @@ -4918,7 +4921,7 @@ static s32 AI_Risky(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) } // Adds score bonus to best powered move -static s32 AI_PreferStrongestMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +static s32 AI_TryTo2HKO(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) { if (IS_TARGETING_PARTNER(battlerAtk, battlerDef)) return score; @@ -4936,12 +4939,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); @@ -4952,7 +4957,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)) @@ -4984,11 +4989,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)) { @@ -5166,7 +5171,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 } } @@ -5176,9 +5181,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) @@ -5264,6 +5269,150 @@ static s32 AI_PowerfulStatus(u32 battlerAtk, u32 battlerDef, u32 move, s32 score return score; } +static s32 AI_PredictSwitch(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) +{ + u32 i; + u32 unmodifiedScore = score; + u32 ability = gBattleMons[battlerAtk].ability; + u32 opposingHazardFlags = gSideStatuses[GetBattlerSide(battlerDef)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_TOXIC_SPIKES); + u32 aiHazardFlags = gSideStatuses[GetBattlerSide(battlerAtk)] & (SIDE_STATUS_HAZARDS_ANY); + u32 moveEffect = gMovesInfo[move].effect; + struct AiLogicData *aiData = AI_DATA; + u32 effectiveness = aiData->effectiveness[battlerAtk][battlerDef][AI_THINKING_STRUCT->movesetIndex]; + + // Switch benefit + switch (moveEffect) + { + case EFFECT_PURSUIT: + ADJUST_SCORE(GOOD_EFFECT); + // else if (IsPredictedToUsePursuitableMove(battlerDef, battlerAtk) && !MoveWouldHitFirst(move, battlerAtk, battlerDef)) //Pursuit against fast U-Turn + // ADJUST_SCORE(GOOD_EFFECT); + break; + + case EFFECT_FOCUS_PUNCH: + ADJUST_SCORE(DECENT_EFFECT); + if (AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_CHECK_BAD_MOVE) + { + if (aiData->abilities[battlerDef] == ABILITY_WONDER_GUARD && effectiveness < AI_EFFECTIVENESS_x2) + ADJUST_SCORE(10); + if (HasDamagingMove(battlerDef) && !((gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE) + || IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) + || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))) + ADJUST_SCORE(10); + } + break; + + // Free setup (U-Turn etc. handled in Check Viability by ShouldPivot) + case EFFECT_BOLT_BEAK: + case EFFECT_LIGHT_SCREEN: + case EFFECT_REFLECT: + case EFFECT_MAGNET_RISE: + case EFFECT_TRICK_ROOM: + case EFFECT_STEALTH_ROCK: + case EFFECT_SPIKES: + case EFFECT_TOXIC_SPIKES: + ADJUST_SCORE(BEST_EFFECT); + break; + case EFFECT_FUTURE_SIGHT: + case EFFECT_TELEKINESIS: + case EFFECT_GRAVITY: + case EFFECT_RAIN_DANCE: + case EFFECT_SANDSTORM: + case EFFECT_SNOWSCAPE: + case EFFECT_HAIL: + case EFFECT_SUNNY_DAY: + case EFFECT_AQUA_RING: + case EFFECT_ELECTRIC_TERRAIN: + case EFFECT_PSYCHIC_TERRAIN: + case EFFECT_GRASSY_TERRAIN: + case EFFECT_MISTY_TERRAIN: + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_HIT_SWITCH_TARGET: + if (opposingHazardFlags != 0) + ADJUST_SCORE(BEST_EFFECT); + else + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_ROAR: + if (opposingHazardFlags != 0) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_DEFOG: + if (aiHazardFlags != 0) + ADJUST_SCORE(GOOD_EFFECT); + break; + case EFFECT_WISH: + case EFFECT_HEAL_BELL: + if (ShouldUseWishAromatherapy(battlerAtk, battlerDef, move)) + ADJUST_SCORE(DECENT_EFFECT); + break; + case EFFECT_RESTORE_HP: + if (AI_DATA->hpPercents[battlerAtk] < 60) + ADJUST_SCORE(GOOD_EFFECT); + break; + + // Fails if opponent switches + case EFFECT_PROTECT: + case EFFECT_COUNTER: + case EFFECT_MIRROR_COAT: + case EFFECT_SHELL_TRAP: + case EFFECT_METAL_BURST: + case EFFECT_SUCKER_PUNCH: + case EFFECT_UPPER_HAND: + case EFFECT_ENCORE: + case EFFECT_FOLLOW_ME: + case EFFECT_ME_FIRST: + case EFFECT_DISABLE: + case EFFECT_ELECTRIFY: + case EFFECT_ENDURE: + case EFFECT_HAZE: + case EFFECT_TOPSY_TURVY: + case EFFECT_ION_DELUGE: + case EFFECT_MAGIC_COAT: + case EFFECT_SNATCH: + ADJUST_SCORE(-BEST_EFFECT); + break; + + // Get stuck in bad matchup + case EFFECT_IMPRISON: + case EFFECT_EMBARGO: + case EFFECT_TAUNT: + case EFFECT_INGRAIN: + case EFFECT_NO_RETREAT: + case EFFECT_MEAN_LOOK: + ADJUST_SCORE(-GOOD_EFFECT); + break; + } + + // Additional effects + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + switch (gMovesInfo[move].additionalEffects[i].moveEffect) + { + case MOVE_EFFECT_WRAP: + ADJUST_SCORE(-GOOD_EFFECT); + break; + case MOVE_EFFECT_RAPID_SPIN: + if (aiHazardFlags != 0) + ADJUST_SCORE(BEST_EFFECT); + break; + case MOVE_EFFECT_FEINT: + ADJUST_SCORE(-BEST_EFFECT); + break; + } + } + + // Take advantage of ability damage bonus + if ((ability == ABILITY_STAKEOUT || ability == ABILITY_ANALYTIC) && IsBattleMoveStatus(move)) + ADJUST_SCORE(-WEAK_EFFECT); + + // This must be last or the player can gauge whether the AI is predicting based on how long it thinks + if (!IsBattlerPredictedToSwitch(battlerDef)) + return unmodifiedScore; + return score; +} + static void AI_Flee(void) { AI_THINKING_STRUCT->aiAction |= (AI_ACTION_DONE | AI_ACTION_FLEE | AI_ACTION_DO_NOT_ATTACK); @@ -5341,6 +5490,8 @@ static s32 AI_DynamicFunc(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) void ScriptSetDynamicAiFunc(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + AiScoreFunc func = (AiScoreFunc)ScriptReadWord(ctx); sDynamicAiFunc = func; } diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 5547351ec192..93148d8b837d 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -37,14 +37,21 @@ static void InitializeSwitchinCandidate(struct Pokemon *mon) AI_DATA->switchinCandidate.hypotheticalStatus = FALSE; } +u32 GetThinkingBattler(u32 battler) +{ + if (AI_DATA->aiSwitchPredictionInProgress) + return AI_DATA->battlerDoingPrediction; + return battler; +} + static bool32 IsAceMon(u32 battler, u32 monPartyId) { - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_ACE_POKEMON - && !(gBattleStruct->forcedSwitch & (1u << battler)) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_ACE_POKEMON + && !gBattleStruct->battlerState[battler].forcedSwitch && monPartyId == CalculateEnemyPartyCountInSide(battler)-1) return TRUE; - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_DOUBLE_ACE_POKEMON - && !(gBattleStruct->forcedSwitch & (1u << battler)) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_DOUBLE_ACE_POKEMON + && !gBattleStruct->battlerState[battler].forcedSwitch && (monPartyId == CalculateEnemyPartyCount()-1 || monPartyId == CalculateEnemyPartyCount()-2)) return TRUE; return FALSE; @@ -88,7 +95,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) u16 typeEffectiveness = UQ_4_12(1.0), aiMoveEffect; //baseline typing damage // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic @@ -108,7 +115,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 +130,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 +163,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) && gMovesInfo[playerMove].effect != EFFECT_FOCUS_PUNCH) { damageTaken = AI_CalcDamage(playerMove, opposingBattler, battler, &effectiveness, FALSE, weather, DMG_ROLL_HIGHEST).expected; if (damageTaken > maxDamageTaken) @@ -190,7 +197,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) && gBattleMons[battler].hp >= gBattleMons[battler].maxHP / 4))) { // 50% chance to stay in regardless - if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50)) + if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50) || AI_DATA->aiSwitchPredictionInProgress) return FALSE; // Switch mon out @@ -210,7 +217,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) return FALSE; // 50% chance to stay in regardless - if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50)) + if (RandomPercentage(RNG_AI_SWITCH_HASBADODDS, 50) || AI_DATA->aiSwitchPredictionInProgress) return FALSE; // Switch mon out @@ -332,13 +339,15 @@ 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; - if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; - if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && RandomPercentage(RNG_AI_SWITCH_ABSORBING, 66)) + if (HasSuperEffectiveMoveAgainstOpponents(battler, TRUE) && (RandomPercentage(RNG_AI_SWITCH_ABSORBING, 66) || AI_DATA->aiSwitchPredictionInProgress)) return FALSE; if (IsDoubleBattle()) @@ -356,34 +365,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; } @@ -436,7 +445,7 @@ static bool32 ShouldSwitchIfOpponentChargingOrInvulnerable(u32 battler) u32 incomingMove = AI_DATA->lastUsedMove[opposingBattler]; bool32 isOpposingBattlerChargingOrInvulnerable = (IsSemiInvulnerable(opposingBattler, incomingMove) || IsTwoTurnNotSemiInvulnerableMove(opposingBattler, incomingMove)); - if (IsDoubleBattle() || !(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + if (IsDoubleBattle() || !(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; if (isOpposingBattlerChargingOrInvulnerable && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) @@ -455,7 +464,7 @@ static bool32 ShouldSwitchIfTrapperInParty(u32 battler) s32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler))); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Check if current mon has an ability that traps opponent @@ -498,7 +507,7 @@ static bool32 ShouldSwitchIfBadlyStatused(u32 battler) && monAbility != ABILITY_SOUNDPROOF) switchMon = TRUE; - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) { //Yawn if (gStatuses3[battler] & STATUS3_YAWN @@ -693,7 +702,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc u16 move; // Similar functionality handled more thoroughly by ShouldSwitchIfHasBadOdds - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) return FALSE; if (gLastLandedMoves[battler] == MOVE_NONE) @@ -702,7 +711,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()) @@ -725,6 +734,8 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc for (i = firstId; i < lastId; i++) { u16 species, monAbility; + uq4_12_t typeMultiplier; + u16 moveFlags = 0; if (!IsValidForBattle(&party[i])) continue; @@ -741,8 +752,9 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc species = GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG); monAbility = GetMonAbility(&party[i]); - CalcPartyMonTypeEffectivenessMultiplier(gLastLandedMoves[battler], species, monAbility); - if (gBattleStruct->moveResultFlags[BATTLE_OPPOSITE(battler)] & flags) + typeMultiplier = CalcPartyMonTypeEffectivenessMultiplier(gLastLandedMoves[battler], species, monAbility); + UpdateMoveResultFlags(typeMultiplier, &moveFlags); + if (moveFlags & flags) { battlerIn1 = gLastHitBy[battler]; @@ -752,7 +764,7 @@ static bool32 FindMonWithFlagsAndSuperEffective(u32 battler, u16 flags, u32 perc if (move == 0) continue; - if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= AI_EFFECTIVENESS_x2 && RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance)) + if (AI_GetMoveEffectiveness(move, battler, battlerIn1) >= AI_EFFECTIVENESS_x2 && (RandomPercentage(RNG_AI_SWITCH_SE_DEFENSIVE, percentChance) || AI_DATA->aiSwitchPredictionInProgress)) return SetSwitchinAndSwitch(battler, i); } } @@ -812,9 +824,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; @@ -833,7 +846,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) u32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler))); // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // If not Encore'd don't switch @@ -841,7 +854,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 @@ -849,7 +862,7 @@ static bool32 ShouldSwitchIfEncored(u32 battler) return FALSE; // Switch out 50% of the time otherwise - else if (RandomPercentage(RNG_AI_SWITCH_ENCORE, 50) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) + else if ((RandomPercentage(RNG_AI_SWITCH_ENCORE, 50) || AI_DATA->aiSwitchPredictionInProgress) && AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE) return SetSwitchinAndSwitch(battler, PARTY_SIZE); return FALSE; @@ -861,7 +874,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); } @@ -875,7 +888,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) s8 spAttackingStage = gBattleMons[battler].statStages[STAT_SPATK]; // Only use this if AI_FLAG_SMART_SWITCHING is set for the trainer - if (!(AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING)) + if (!(AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING)) return FALSE; // Physical attacker @@ -887,7 +900,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) // 50% chance if attack at -2 and have a good candidate mon else if (attackingStage == DEFAULT_STAT_STAGE - 2) { - if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, 50)) + if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, 50) || AI_DATA->aiSwitchPredictionInProgress)) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } // If at -3 or worse, switch out regardless @@ -904,7 +917,7 @@ static bool32 ShouldSwitchIfAttackingStatsLowered(u32 battler) // 50% chance if attack at -2 and have a good candidate mon else if (spAttackingStage == DEFAULT_STAT_STAGE - 2) { - if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, 50)) + if (AI_DATA->mostSuitableMonId[battler] != PARTY_SIZE && (RandomPercentage(RNG_AI_SWITCH_STATS_LOWERED, 50) || AI_DATA->aiSwitchPredictionInProgress)) return SetSwitchinAndSwitch(battler, PARTY_SIZE); } // If at -3 or worse, switch out regardless @@ -922,7 +935,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; @@ -934,7 +946,7 @@ bool32 ShouldSwitch(u32 battler) return FALSE; // Sequence Switching AI never switches mid-battle - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SEQUENCE_SWITCHING) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) return FALSE; availableToSwitch = 0; @@ -970,21 +982,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. @@ -996,7 +1000,7 @@ bool32 ShouldSwitch(u32 battler) return TRUE; // These Functions can prompt switch to party member returned by GetMostSuitableMonToSwitchInto - if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) + if ((AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) && (CanMonSurviveHazardSwitchin(battler) == FALSE)) return FALSE; if (ShouldSwitchIfTrapperInParty(battler)) return TRUE; @@ -1022,7 +1026,7 @@ bool32 ShouldSwitch(u32 battler) // Removing switch capabilites under specific conditions // These Functions prevent the "FindMonWithFlagsAndSuperEffective" from getting out of hand. // We don't use FindMonWithFlagsAndSuperEffective with AI_FLAG_SMART_SWITCHING, so we can bail early. - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_SWITCHING) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_SWITCHING) return FALSE; if (HasSuperEffectiveMoveAgainstOpponents(battler, FALSE)) return FALSE; @@ -1242,7 +1246,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 +1293,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(TYPE_SIDE_HAZARD_POINTED_STONES, 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(TYPE_SIDE_HAZARD_SHARP_STEEL, defType1, defType2, battleMon->maxHP); // Spikes if ((hazardFlags & SIDE_STATUS_SPIKES) && IsMonGrounded(heldItemEffect, ability, defType1, defType2)) { @@ -1698,7 +1702,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) && gMovesInfo[playerMove].effect != EFFECT_FOCUS_PUNCH) { damageTaken = AI_CalcPartyMonDamage(playerMove, opposingBattler, battler, battleMon, FALSE, DMG_ROLL_HIGHEST); if (damageTaken > maxDamageTaken) @@ -1734,7 +1738,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 +1779,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 +1802,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, else if (IsAceMon(battler, i)) { aceMonId = i; + aceMonCount++; continue; } else @@ -1826,9 +1831,9 @@ 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) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_CONSERVATIVE) damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_LOWEST); else damageDealt = AI_CalcPartyMonDamage(aiMove, battler, opposingBattler, AI_DATA->switchinCandidate.battleMon, TRUE, DMG_ROLL_DEFAULT); @@ -1856,7 +1861,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 +1876,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 +1949,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; @@ -2006,14 +2011,14 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd) GetAIPartyIndexes(battler, &firstId, &lastId); party = GetBattlerParty(battler); - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SEQUENCE_SWITCHING) + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SEQUENCE_SWITCHING) { bestMonId = GetNextMonInParty(party, firstId, lastId, battlerIn1, battlerIn2); return bestMonId; } // Only use better mon selection if AI_FLAG_SMART_MON_CHOICES is set for the trainer. - if (AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic + if (AI_THINKING_STRUCT->aiFlags[GetThinkingBattler(battler)] & AI_FLAG_SMART_MON_CHOICES && !IsDoubleBattle()) // Double Battles aren't included in AI_FLAG_SMART_MON_CHOICE. Defaults to regular switch in logic { bestMonId = GetBestMonIntegrated(party, firstId, lastId, battler, opposingBattler, battlerIn1, battlerIn2, switchAfterMonKOd); return bestMonId; @@ -2022,7 +2027,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 +2044,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 +2064,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; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index dd1cd296daec..6f6b5c718818 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -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 @@ -111,6 +102,18 @@ bool32 IsAiBattlerPredictingAbility(u32 battlerId) return BattlerHasAi(battlerId); } +bool32 IsBattlerPredictedToSwitch(u32 battler) +{ + // Check for prediction flag on AI, whether they're using those predictions this turn, and whether the AI thinks the player should switch + if (AI_THINKING_STRUCT->aiFlags[AI_DATA->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH + || AI_THINKING_STRUCT->aiFlags[AI_DATA->battlerDoingPrediction] & AI_FLAG_PREDICT_SWITCH) + { + if (AI_DATA->predictingSwitch && AI_DATA->shouldSwitch & (1u << battler)) + return TRUE; + } + return FALSE; +} + void ClearBattlerMoveHistory(u32 battlerId) { memset(BATTLE_HISTORY->usedMoves[battlerId], 0, sizeof(BATTLE_HISTORY->usedMoves[battlerId])); @@ -338,9 +341,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 +377,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; } @@ -438,7 +442,7 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy if (battlerDef == BATTLE_PARTNER(battlerAtk)) battlerDefAbility = aiData->abilities[battlerDef]; - if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + if (gBattleStruct->battlerState[battlerDef].commandingDondozo) return TRUE; if (CanAbilityBlockMove(battlerAtk, battlerDef, move, aiData->abilities[battlerDef])) @@ -450,7 +454,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 +474,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.type)) + 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.moveProperty == 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: @@ -485,16 +489,6 @@ bool32 IsDamageMoveUnusable(u32 battlerAtk, u32 battlerDef, u32 move, u32 moveTy if (!gDisableStructs[battlerAtk].isFirstTurn) return TRUE; break; - case EFFECT_FOCUS_PUNCH: - if (HasDamagingMove(battlerDef) && !((gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE) - || IsBattlerIncapacitated(battlerDef, aiData->abilities[battlerDef]) - || gBattleMons[battlerDef].status2 & (STATUS2_INFATUATION | STATUS2_CONFUSION))) - // TODO: || IsPredictedToSwitch(battlerDef, battlerAtk) - return TRUE; - // If AI could Sub and doesn't have a Sub, don't Punch yet - if (HasMoveEffect(battlerAtk, EFFECT_SUBSTITUTE) && !(gBattleMons[battlerAtk].status2 & STATUS2_SUBSTITUTE)) - return TRUE; - break; } return FALSE; @@ -512,7 +506,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 +529,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 +548,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 +561,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.fixedDamage * (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 +615,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 +635,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 +659,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 +720,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 +782,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 +795,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 +845,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 +879,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 +889,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 +906,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 +922,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 +945,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 +966,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 +990,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 +1053,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 +1105,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 +1145,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; @@ -1345,8 +1349,8 @@ s32 AI_DecideKnownAbilityForTurn(u32 battlerId) u32 abilityAiRatings[NUM_ABILITY_SLOTS] = {0}; // We've had ability overwritten by e.g. Worry Seed. It is not part of AI_PARTY in case of switching - if (gBattleStruct->overwrittenAbilities[battlerId]) - return gBattleStruct->overwrittenAbilities[battlerId]; + if (gDisableStructs[battlerId].overwrittenAbility) + return gDisableStructs[battlerId].overwrittenAbility; // The AI knows its own ability. if (IsAiBattlerAware(battlerId)) @@ -1409,7 +1413,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; @@ -1432,16 +1436,16 @@ u32 AI_GetWeather(struct AiLogicData *aiData) return gBattleWeather; } -bool32 IsAromaVeilProtectedMove(u32 move) +bool32 IsAromaVeilProtectedEffect(u32 moveEffect) { - switch (move) + switch (moveEffect) { - case MOVE_DISABLE: - case MOVE_ATTRACT: - case MOVE_ENCORE: - case MOVE_TORMENT: - case MOVE_TAUNT: - case MOVE_HEAL_BLOCK: + case EFFECT_DISABLE: + case EFFECT_ATTRACT: + case EFFECT_ENCORE: + case EFFECT_TORMENT: + case EFFECT_TAUNT: + case EFFECT_HEAL_BLOCK: return TRUE; default: return FALSE; @@ -1496,8 +1500,9 @@ bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility) if (AI_THINKING_STRUCT->aiFlags[sBattler_AI] & AI_FLAG_NEGATE_UNAWARE) return FALSE; - if (move == MOVE_SKY_DROP - || move == MOVE_SNIPE_SHOT + u32 effect = GetMoveEffect(move); + if (effect == EFFECT_SKY_DROP + || effect == EFFECT_SNIPE_SHOT || atkAbility == ABILITY_PROPELLER_TAIL || atkAbility == ABILITY_STALWART) return TRUE; @@ -1508,13 +1513,13 @@ bool32 IsSemiInvulnerable(u32 battlerDef, u32 move) { if (gStatuses3[battlerDef] & STATUS3_PHANTOM_FORCE) return TRUE; - else if (gBattleStruct->commandingDondozo & (1u << battlerDef)) + else if (gBattleStruct->battlerState[battlerDef].commandingDondozo) 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 +1540,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 +1718,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 +1982,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 +2011,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,7 +2026,7 @@ 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; } @@ -2035,8 +2041,8 @@ bool32 IsPowerBasedOnStatus(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.status & argument)) + && GetMoveEffect(moves[i]) == effect + && (GetMoveEffectArg_Status(moves[i]) & argument)) return TRUE; } @@ -2066,7 +2072,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 +2087,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 +2133,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 +2158,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 +2184,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 +2192,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 +2208,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 +2236,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 +2398,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 +2410,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 +2431,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 +2446,7 @@ bool32 HasDamagingMoveOfType(u32 battlerId, u32 type) for (i = 0; i < MAX_MON_MOVES; i++) { if (moves[i] != MOVE_NONE && moves[i] != MOVE_UNAVAILABLE - && gMovesInfo[moves[i]].type == type && !IS_MOVE_STATUS(moves[i])) + && GetMoveType(moves[i]) == type && !IsBattleMoveStatus(moves[i])) return TRUE; } @@ -2443,7 +2455,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 +2472,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 +2481,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.twoTurnAttack.status)); + || (AI_GetWeather(AI_DATA) & GetMoveTwoTurnAttackWeather(move))); default: return FALSE; } @@ -2695,7 +2728,7 @@ static bool32 PartyBattlerShouldAvoidHazards(u32 currBattler, u32 switchBattler) u32 ability = GetMonAbility(mon); // we know our own party data u32 holdEffect; u32 species = GetMonData(mon, MON_DATA_SPECIES); - u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); + u32 flags = gSideStatuses[GetBattlerSide(currBattler)] & (SIDE_STATUS_SPIKES | SIDE_STATUS_STEALTH_ROCK | SIDE_STATUS_STEELSURGE | SIDE_STATUS_STICKY_WEB | SIDE_STATUS_TOXIC_SPIKES); s32 hazardDamage = 0; u32 type1 = gSpeciesInfo[species].types[0]; u32 type2 = gSpeciesInfo[species].types[1]; @@ -2714,7 +2747,9 @@ 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(TYPE_SIDE_HAZARD_POINTED_STONES, type1, type2, maxHp); + if ((flags & SIDE_STATUS_STEELSURGE)) + hazardDamage += GetStealthHazardDamageByTypesAndHP(TYPE_SIDE_HAZARD_SHARP_STEEL, type1, type2, maxHp); if (flags & SIDE_STATUS_SPIKES && ((type1 != TYPE_FLYING && type2 != TYPE_FLYING && ability != ABILITY_LEVITATE && holdEffect != HOLD_EFFECT_AIR_BALLOON) @@ -2746,9 +2781,8 @@ enum AIPivot ShouldPivot(u32 battlerAtk, u32 battlerDef, u32 defAbility, u32 mov if (CountUsablePartyMons(battlerAtk) == 0) return CAN_TRY_PIVOT; // can't switch, but attack might still be useful - //TODO - predict opponent switching - /*if (IsPredictedToSwitch(battlerDef, battlerAtk) && !hasStatBoost) - return SHOULD_PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent*/ + if (IsBattlerPredictedToSwitch(battlerDef)) + return SHOULD_PIVOT; // Try pivoting so you can switch to a better matchup to counter your new opponent if (AI_IsFaster(battlerAtk, battlerDef, move)) // Attacker goes first { @@ -2760,7 +2794,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 +2803,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 +2850,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 +2880,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 +3036,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; @@ -3141,7 +3175,7 @@ static u32 FindMoveUsedXTurnsAgo(u32 battlerId, u32 x) bool32 IsWakeupTurn(u32 battler) { // Check if rest was used 2 turns ago - if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && FindMoveUsedXTurnsAgo(battler, 2) == MOVE_REST) + if ((gBattleMons[battler].status1 & STATUS1_SLEEP) == 1 && GetMoveEffect(FindMoveUsedXTurnsAgo(battler, 2)) == EFFECT_REST) return TRUE; else // no way to know return FALSE; @@ -3229,8 +3263,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.absorbPercentage == 0) ? 50 : gMovesInfo[move].argument.absorbPercentage; - s32 healDmg = (healPercent * damage) / 100; + s32 healDmg = (GetMoveAbsorbPercentage(move) * damage) / 100; if (gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) healDmg = 0; @@ -3331,7 +3364,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 +3379,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 +3391,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 +3424,24 @@ 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; +} + +//PARTNER_MOVE_EFFECT_IS +bool32 PartnerMoveEffectIs(u32 battlerAtkPartner, u32 partnerMove, u32 effectCheck) +{ + if (!IsDoubleBattle()) + return FALSE; + + if (partnerMove != MOVE_NONE && GetMoveEffect(partnerMove) == effectCheck) return TRUE; return FALSE; @@ -3443,7 +3491,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 +3518,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 +3531,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 +3674,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; } } @@ -3746,6 +3794,10 @@ static u32 IncreaseStatUpScoreInternal(u32 battlerAtk, u32 battlerDef, u32 statI if (AI_DATA->abilities[battlerDef] == ABILITY_OPPORTUNIST) return NO_INCREASE; + // If predicting switch, stat increases are great momentum + if (IsBattlerPredictedToSwitch(battlerDef)) + tempScore += WEAK_EFFECT; + switch (statId) { case STAT_CHANGE_ATK: @@ -3868,7 +3920,7 @@ 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); @@ -3904,7 +3956,7 @@ void IncreaseParalyzeScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) void IncreaseSleepScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score) { - if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0)) + if (((AI_THINKING_STRUCT->aiFlags[battlerAtk] & AI_FLAG_TRY_TO_FAINT) && CanAIFaintTarget(battlerAtk, battlerDef, 0) && gMovesInfo[GetBestDmgMoveFromBattler(battlerAtk, battlerDef)].effect != EFFECT_FOCUS_PUNCH) || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_SLP || AI_DATA->holdEffects[battlerDef] == HOLD_EFFECT_CURE_STATUS) return; @@ -3952,7 +4004,7 @@ 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); @@ -3966,7 +4018,7 @@ void IncreaseFrostbiteScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 *score 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 +4041,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 +4159,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 +4177,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))) @@ -4145,9 +4198,8 @@ void IncreaseSubstituteMoveScore(u32 battlerAtk, u32 battlerDef, u32 move, s32 * else if (gBattleMons[battlerDef].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_FROSTBITE)) ADJUST_SCORE_PTR(DECENT_EFFECT); - // TODO: - // if (IsPredictedToSwitch(battlerDef, battlerAtk) - // ADJUST_SCORE_PTR(DECENT_EFFECT); + if (IsBattlerPredictedToSwitch(battlerDef)) + ADJUST_SCORE(DECENT_EFFECT); if (HasMoveEffect(battlerDef, EFFECT_SLEEP) || HasMoveEffect(battlerDef, EFFECT_TOXIC) diff --git a/src/battle_anim.c b/src/battle_anim.c index b036f83cbf6d..640e0044ea6c 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -112,7 +112,7 @@ EWRAM_DATA static u16 sSoundAnimFramesToWait = 0; EWRAM_DATA static u8 sMonAnimTaskIdArray[2] = {0}; EWRAM_DATA u8 gAnimMoveTurn = 0; EWRAM_DATA static u8 sAnimBackgroundFadeState = 0; -EWRAM_DATA u16 gAnimMoveIndex = 0; // Set but unused. +EWRAM_DATA u16 gAnimMoveIndex = 0; EWRAM_DATA u8 gBattleAnimAttacker = 0; EWRAM_DATA u8 gBattleAnimTarget = 0; EWRAM_DATA u16 gAnimBattlerSpecies[MAX_BATTLERS_COUNT] = {0}; @@ -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); diff --git a/src/battle_anim_dark.c b/src/battle_anim_dark.c index 2400c22aafde..fd9ffdf92392 100644 --- a/src/battle_anim_dark.c +++ b/src/battle_anim_dark.c @@ -257,6 +257,10 @@ const struct SpriteTemplate gPunishmentImpactSpriteTemplate = .callback = AnimPunishment, }; +// arg 0: x pixel offset +// arg 1: y pixel offset +// arg 2: Something +// arg 3: Something static void AnimPunishment(struct Sprite *sprite) { StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]); diff --git a/src/battle_anim_dragon.c b/src/battle_anim_dragon.c index f3ee2a381878..55ecd5d0c1c8 100644 --- a/src/battle_anim_dragon.c +++ b/src/battle_anim_dragon.c @@ -14,8 +14,6 @@ static void AnimSpinningDracoMeteor(struct Sprite *sprite); static void AnimSpinningDracoMeteorFinish(struct Sprite *sprite); static void AnimDracoMeteorRock_Step(struct Sprite *sprite); -EWRAM_DATA static u16 sUnusedOverheatData[7] = {0}; - static const union AnimCmd sAnim_OutrageOverheatFire_0[] = { ANIMCMD_FRAME(0, 4), @@ -601,7 +599,6 @@ static void UpdateDragonDanceScanlineEffect(struct Task *task) void AnimOverheatFlame(struct Sprite *sprite) { - int i; int yAmplitude = (gBattleAnimArgs[2] * 3) / 5; sprite->x = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_X_2); sprite->y = GetBattlerSpriteCoord(gBattleAnimAttacker, BATTLER_COORD_Y_PIC_OFFSET) + gBattleAnimArgs[4]; @@ -611,8 +608,6 @@ void AnimOverheatFlame(struct Sprite *sprite) sprite->y += sprite->data[2] * gBattleAnimArgs[0]; sprite->data[3] = gBattleAnimArgs[3]; sprite->callback = AnimOverheatFlame_Step; - for (i = 0; i < 7; i++) - sUnusedOverheatData[i] = sprite->data[i]; } static void AnimOverheatFlame_Step(struct Sprite *sprite) diff --git a/src/battle_anim_electric.c b/src/battle_anim_electric.c index 6e7c1c1e0ca6..59cd017b9a39 100644 --- a/src/battle_anim_electric.c +++ b/src/battle_anim_electric.c @@ -657,6 +657,13 @@ static void AnimUnusedCirclingShock(struct Sprite *sprite) sprite->callback = TranslateSpriteInCircle; } +// arg 0: +// arg 1: +// arg 2: +// arg 3: duration +// arg 4: target +// arg 5: +// arg 6: void AnimSparkElectricity(struct Sprite *sprite) { u8 battler; diff --git a/src/battle_anim_mon_movement.c b/src/battle_anim_mon_movement.c index 240e43b713fe..0bacd962199c 100644 --- a/src/battle_anim_mon_movement.c +++ b/src/battle_anim_mon_movement.c @@ -908,7 +908,7 @@ static void AnimTask_SlideOffScreen_Step(u8 taskId) // arg 1: wave amplitude // arg 2: wave period // arg 3: num sways -// arg 4: which mon (0 = attacker, 1`= target) +// arg 4: which mon (0 = attacker, 1 = target) void AnimTask_SwayMon(u8 taskId) { u8 spriteId; diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 928f050822b3..f00626efe818 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -2117,24 +2117,26 @@ s16 GetBattlerSpriteCoordAttr(u8 battlerId, u8 attr) } else { - if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + struct Pokemon *mon = GetPartyBattlerData(battlerId); + + spriteInfo = gBattleSpritesDataPtr->battlerData; + if (!spriteInfo[battlerId].transformSpecies) { - spriteInfo = gBattleSpritesDataPtr->battlerData; - if (!spriteInfo[battlerId].transformSpecies) - { - species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES); - personality = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY); - } - else - { - species = spriteInfo[battlerId].transformSpecies; - personality = gTransformedPersonalities[battlerId]; - } + species = GetMonData(mon, MON_DATA_SPECIES); + personality = GetMonData(mon, MON_DATA_PERSONALITY); + } + else + { + species = spriteInfo[battlerId].transformSpecies; + personality = gTransformedPersonalities[battlerId]; + } - species = SanitizeSpeciesId(species); - if (species == SPECIES_UNOWN) - species = GetUnownSpeciesId(personality); + species = SanitizeSpeciesId(species); + if (species == SPECIES_UNOWN) + species = GetUnownSpeciesId(personality); + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + { #if P_GENDER_DIFFERENCES if (gSpeciesInfo[species].backPicFemale != NULL && IsPersonalityFemale(species, personality)) size = gSpeciesInfo[species].backPicSizeFemale; @@ -2146,22 +2148,6 @@ s16 GetBattlerSpriteCoordAttr(u8 battlerId, u8 attr) } else { - spriteInfo = gBattleSpritesDataPtr->battlerData; - if (!spriteInfo[battlerId].transformSpecies) - { - species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES); - personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY); - } - else - { - species = spriteInfo[battlerId].transformSpecies; - personality = gTransformedPersonalities[battlerId]; - } - - species = SanitizeSpeciesId(species); - if (species == SPECIES_UNOWN) - species = GetUnownSpeciesId(personality); - #if P_GENDER_DIFFERENCES if (gSpeciesInfo[species].frontPicFemale != NULL && IsPersonalityFemale(species, personality)) size = gSpeciesInfo[species].frontPicSizeFemale; diff --git a/src/battle_anim_new.c b/src/battle_anim_new.c index 38597b19b376..7308a9d6fd83 100644 --- a/src/battle_anim_new.c +++ b/src/battle_anim_new.c @@ -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.maxEffect) + 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); diff --git a/src/battle_arena.c b/src/battle_arena.c index 4a6df309b56a..dd0f0c1bbd3f 100644 --- a/src/battle_arena.c +++ b/src/battle_arena.c @@ -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]++; } @@ -385,10 +386,9 @@ void BattleArena_AddSkillPoints(u8 battler) if (gHitMarker & HITMARKER_OBEYS) { - u8 *failedMoveBits = &gBattleStruct->alreadyStatusedMoveAttempt; - if (*failedMoveBits & (1u << battler)) + if (gBattleStruct->battlerState[battler].alreadyStatusedMoveAttempt) { - *failedMoveBits &= ~((1u << battler)); + gBattleStruct->battlerState[battler].alreadyStatusedMoveAttempt = FALSE; skillPoints[battler] -= 2; } else if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) diff --git a/src/battle_controller_link_opponent.c b/src/battle_controller_link_opponent.c index 7aeefa54b6a6..c437a687bd61 100644 --- a/src/battle_controller_link_opponent.c +++ b/src/battle_controller_link_opponent.c @@ -87,10 +87,6 @@ static void (*const sLinkOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 batt [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, diff --git a/src/battle_controller_link_partner.c b/src/battle_controller_link_partner.c index 283b492a9150..795b885f95c0 100644 --- a/src/battle_controller_link_partner.c +++ b/src/battle_controller_link_partner.c @@ -86,10 +86,6 @@ static void (*const sLinkPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battl [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 2fbf8cf69f97..822b04e04f80 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -101,10 +101,6 @@ static void (*const sOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, @@ -609,7 +605,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] = diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 00e73735e8c3..eacf2d3fb7aa 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -138,10 +138,6 @@ static void (*const sPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = [CONTROLLER_CHOSENMONRETURNVALUE] = PlayerHandleChosenMonReturnValue, [CONTROLLER_ONERETURNVALUE] = PlayerHandleOneReturnValue, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = PlayerHandleOneReturnValue_Duplicate, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, @@ -680,13 +676,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; @@ -776,6 +772,7 @@ void HandleInputChooseMove(u32 battler) if (gBattleStruct->zmove.viewing) { ReloadMoveNames(battler); + ChangeGimmickTriggerSprite(gBattleStruct->gimmick.triggerSpriteId, gBattleStruct->gimmick.playerSelect); } else { @@ -1410,6 +1407,14 @@ void Task_PlayerController_RestoreBgmAfterCry(u8 taskId) #define tExpTask_gainedExp_2 data[4] // Stored as two half-words containing a word. #define tExpTask_frames data[10] +static void DynamaxModifyHPLevelUp(struct Pokemon *mon, u32 battler, u32 oldMaxHP) +{ + ApplyDynamaxHPMultiplier(mon); + gBattleScripting.levelUpHP = GetMonData(mon, MON_DATA_MAX_HP) - oldMaxHP; // overwrite levelUpHP since it overflows + gBattleMons[battler].hp += gBattleScripting.levelUpHP; + SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp); +} + static s32 GetTaskExpValue(u8 taskId) { return (u16)(gTasks[taskId].tExpTask_gainedExp_1) | (gTasks[taskId].tExpTask_gainedExp_2 << 16); @@ -1428,21 +1433,16 @@ static void Task_GiveExpToMon(u8 taskId) u8 level = GetMonData(mon, MON_DATA_LEVEL); u32 currExp = GetMonData(mon, MON_DATA_EXP); u32 nextLvlExp = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1]; + u32 oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP); if (currExp + gainedExp >= nextLvlExp) { SetMonData(mon, MON_DATA_EXP, &nextLvlExp); - gBattleStruct->dynamax.levelUpHP = GetMonData(mon, MON_DATA_HP) \ - + UQ_4_12_TO_INT((gBattleScripting.levelUpHP * UQ_4_12(1.5)) + UQ_4_12_ROUND); CalculateMonStats(mon); // Reapply Dynamax HP multiplier after stats are recalculated. if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler]) - { - ApplyDynamaxHPMultiplier(battler, mon); - gBattleMons[battler].hp = gBattleStruct->dynamax.levelUpHP; - SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp); - } + DynamaxModifyHPLevelUp(mon, battler, oldMaxHP); gainedExp -= nextLvlExp - currExp; BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp); @@ -1491,6 +1491,7 @@ static void Task_GiveExpWithExpBar(u8 taskId) { u8 level; u16 species; + u32 oldMaxHP; s32 currExp, expOnNextLvl, newExpPoints; if (gTasks[taskId].tExpTask_frames < 13) @@ -1502,31 +1503,27 @@ static void Task_GiveExpWithExpBar(u8 taskId) u8 monId = gTasks[taskId].tExpTask_monId; s32 gainedExp = GetTaskExpValue(taskId); u8 battler = gTasks[taskId].tExpTask_battler; + struct Pokemon *mon = &gPlayerParty[monId]; newExpPoints = MoveBattleBar(battler, gHealthboxSpriteIds[battler], EXP_BAR, 0); SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); if (newExpPoints == -1) // The bar has been filled with given exp points. { m4aSongNumStop(SE_EXP); - level = GetMonData(&gPlayerParty[monId], MON_DATA_LEVEL); - currExp = GetMonData(&gPlayerParty[monId], MON_DATA_EXP); - species = GetMonData(&gPlayerParty[monId], MON_DATA_SPECIES); + level = GetMonData(mon, MON_DATA_LEVEL); + currExp = GetMonData(mon, MON_DATA_EXP); + species = GetMonData(mon, MON_DATA_SPECIES); + oldMaxHP = GetMonData(mon, MON_DATA_MAX_HP); expOnNextLvl = gExperienceTables[gSpeciesInfo[species].growthRate][level + 1]; if (currExp + gainedExp >= expOnNextLvl) { - SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &expOnNextLvl); - gBattleStruct->dynamax.levelUpHP = GetMonData(&gPlayerParty[monId], MON_DATA_HP) \ - + UQ_4_12_TO_INT((gBattleScripting.levelUpHP * UQ_4_12(1.5)) + UQ_4_12_ROUND); - CalculateMonStats(&gPlayerParty[monId]); + SetMonData(mon, MON_DATA_EXP, &expOnNextLvl); + CalculateMonStats(mon); // Reapply Dynamax HP multiplier after stats are recalculated. if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && monId == gBattlerPartyIndexes[battler]) - { - ApplyDynamaxHPMultiplier(battler, &gPlayerParty[monId]); - gBattleMons[battler].hp = gBattleStruct->dynamax.levelUpHP; - SetMonData(&gPlayerParty[monId], MON_DATA_HP, &gBattleMons[battler].hp); - } + DynamaxModifyHPLevelUp(mon, battler, oldMaxHP); gainedExp -= expOnNextLvl - currExp; BtlController_EmitTwoReturnValues(battler, BUFFER_B, RET_VALUE_LEVELED_UP, gainedExp); @@ -1535,7 +1532,7 @@ static void Task_GiveExpWithExpBar(u8 taskId) else { currExp += gainedExp; - SetMonData(&gPlayerParty[monId], MON_DATA_EXP, &currExp); + SetMonData(mon, MON_DATA_EXP, &currExp); gBattlerControllerFuncs[battler] = Controller_WaitForString; DestroyTask(taskId); } @@ -1711,18 +1708,19 @@ static void MoveSelectionDisplayPpNumber(u32 battler) static void MoveSelectionDisplayMoveType(u32 battler) { u8 *txtPtr, *end; - u8 type; u32 speciesId; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); - type = gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].type; + u32 move = moveInfo->moves[gMoveSelectionCursor[battler]]; + u32 type = GetMoveType(move); + u32 effect = GetMoveEffect(move); - if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_BLAST) + if (effect == EFFECT_TERA_BLAST) { if (IsGimmickSelected(battler, GIMMICK_TERA) || GetActiveGimmick(battler) == GIMMICK_TERA) type = GetBattlerTeraType(battler); } - else if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_IVY_CUDGEL) + else if (effect == EFFECT_IVY_CUDGEL) { speciesId = gBattleMons[battler].species; @@ -1731,12 +1729,12 @@ 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(move) == DAMAGE_CATEGORY_STATUS && (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX))) { type = TYPE_NORMAL; // Max Guard is always a Normal-type move } - else if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_STARSTORM) + else if (effect == EFFECT_TERA_STARSTORM) { if (gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR || (IsGimmickSelected(battler, GIMMICK_TERA) && gBattleMons[battler].species == SPECIES_TERAPAGOS_TERASTAL)) @@ -1745,7 +1743,7 @@ static void MoveSelectionDisplayMoveType(u32 battler) else if (P_SHOW_DYNAMIC_TYPES) // Non-vanilla changes to battle UI showing dynamic types { struct Pokemon *mon = &gPlayerParty[gBattlerPartyIndexes[battler]]; - type = CheckDynamicMoveType(mon, moveInfo->moves[gMoveSelectionCursor[battler]], battler); + type = CheckDynamicMoveType(mon, move, battler); } end = StringCopy(txtPtr, gTypesInfo[type].name); @@ -1757,8 +1755,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 +1784,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) @@ -2044,14 +2039,14 @@ static void PlayerHandleChooseAction(u32 battler) ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0); PREPARE_MON_NICK_BUFFER(gBattleTextBuff1, battler, gBattlerPartyIndexes[battler]); BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo); - BreakStringAutomatic(gDisplayedStringBattle, WindowWidthPx(B_WIN_ACTION_PROMPT), 2, FONT_NORMAL); if (B_SHOW_PARTNER_TARGET && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && IsBattlerAlive(B_POSITION_PLAYER_RIGHT)) { 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 +2057,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}")); } @@ -2237,7 +2232,7 @@ void PlayerHandleExpUpdate(u32 battler) static void PlayerHandleStatusXor(u32 battler) { - u8 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS) ^ gBattleResources->bufferA[battler][1]; + u32 val = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS) ^ gBattleResources->bufferA[battler][1]; SetMonData(&gPlayerParty[gBattlerPartyIndexes[battler]], MON_DATA_STATUS, &val); PlayerBufferExecCompleted(battler); diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index f987c333ce4b..1fcc4fbef744 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -90,10 +90,6 @@ static void (*const sPlayerPartnerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 bat [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, @@ -297,9 +293,11 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler) s16 xPos, yPos; u32 trainerPicId; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); + if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) { - trainerPicId = gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic; + trainerPicId = gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic; xPos = 90; yPos = (8 - gTrainerBacksprites[trainerPicId].coordinates.size) * 4 + 80; } @@ -353,10 +351,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)) @@ -426,9 +425,10 @@ static void PlayerPartnerHandleHealthBarUpdate(u32 battler) static void PlayerPartnerHandleIntroTrainerBallThrow(u32 battler) { const u32 *trainerPal; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(gPartnerTrainerId); if (gPartnerTrainerId > TRAINER_PARTNER(PARTNER_NONE)) - trainerPal = gTrainerBacksprites[gBattlePartners[gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data; + trainerPal = gTrainerBacksprites[gBattlePartners[difficulty][gPartnerTrainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic].palette.data; else if (IsAiVsAiBattle()) trainerPal = gTrainerSprites[GetTrainerPicFromId(gPartnerTrainerId)].palette.data; else diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index afd56a9faf42..7cffc5fd5b4f 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -93,10 +93,6 @@ static void (*const sRecordedOpponentBufferCommands[CONTROLLER_CMDS_COUNT])(u32 [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index 2bb64f30668f..568051bd8c60 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -90,10 +90,6 @@ static void (*const sRecordedPlayerBufferCommands[CONTROLLER_CMDS_COUNT])(u32 ba [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_HandleClearUnkVar, - [CONTROLLER_SETUNKVAR] = BtlController_HandleSetUnkVar, - [CONTROLLER_CLEARUNKFLAG] = BtlController_HandleClearUnkFlag, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_HandleToggleUnkFlag, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, diff --git a/src/battle_controller_safari.c b/src/battle_controller_safari.c index 932ce47fd938..2d85ddaaece3 100644 --- a/src/battle_controller_safari.c +++ b/src/battle_controller_safari.c @@ -82,10 +82,6 @@ static void (*const sSafariBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_Empty, - [CONTROLLER_SETUNKVAR] = BtlController_Empty, - [CONTROLLER_CLEARUNKFLAG] = BtlController_Empty, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_Empty, [CONTROLLER_HITANIMATION] = BtlController_Empty, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = BtlController_HandlePlaySE, @@ -299,7 +295,6 @@ static void SafariHandleChooseAction(u32 battler) ActionSelectionCreateCursorAt(gActionSelectionCursor[battler], 0); BattleStringExpandPlaceholdersToDisplayedString(gText_WhatWillPkmnDo2); - BreakStringAutomatic(gDisplayedStringBattle, WindowWidthPx(B_WIN_ACTION_PROMPT), 2, FONT_NORMAL); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_ACTION_PROMPT); } diff --git a/src/battle_controller_wally.c b/src/battle_controller_wally.c index 66d39326947a..bba1ffd1da7c 100644 --- a/src/battle_controller_wally.c +++ b/src/battle_controller_wally.c @@ -94,10 +94,6 @@ static void (*const sWallyBufferCommands[CONTROLLER_CMDS_COUNT])(u32 battler) = [CONTROLLER_CHOSENMONRETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE] = BtlController_Empty, [CONTROLLER_ONERETURNVALUE_DUPLICATE] = BtlController_Empty, - [CONTROLLER_CLEARUNKVAR] = BtlController_Empty, - [CONTROLLER_SETUNKVAR] = BtlController_Empty, - [CONTROLLER_CLEARUNKFLAG] = BtlController_Empty, - [CONTROLLER_TOGGLEUNKFLAG] = BtlController_Empty, [CONTROLLER_HITANIMATION] = BtlController_HandleHitAnimation, [CONTROLLER_CANTSWITCH] = BtlController_Empty, [CONTROLLER_PLAYSE] = WallyHandlePlaySE, diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 553eb7a85c61..d60cd34312e1 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -28,7 +28,6 @@ static EWRAM_DATA u8 sLinkSendTaskId = 0; static EWRAM_DATA u8 sLinkReceiveTaskId = 0; -EWRAM_DATA struct UnusedControllerStruct gUnusedControllerStruct = {}; // Debug? Unused code that writes to it, never read COMMON_DATA void (*gBattlerControllerFuncs[MAX_BATTLERS_COUNT])(u32 battler) = {0}; COMMON_DATA u8 gBattleControllerData[MAX_BATTLERS_COUNT] = {0}; // Used by the battle controllers to store misc sprite/task IDs for each battler @@ -976,12 +975,12 @@ void BtlController_EmitLoadMonSprite(u32 battler, u32 bufferId) PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4); } -void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearSubstituteBit) +void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearTransform, bool8 dontClearSubstituteBit) { gBattleResources->transferBuffer[0] = CONTROLLER_SWITCHINANIM; gBattleResources->transferBuffer[1] = partyId; - gBattleResources->transferBuffer[2] = dontClearSubstituteBit; - gBattleResources->transferBuffer[3] = 5; + gBattleResources->transferBuffer[2] = dontClearTransform; + gBattleResources->transferBuffer[3] = dontClearSubstituteBit; PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4); } @@ -1113,7 +1112,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; @@ -1371,40 +1370,6 @@ void BtlController_EmitOneReturnValue_Duplicate(u32 battler, u32 bufferId, u16 r PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4); } -static void UNUSED BtlController_EmitClearUnkVar(u32 battler, u32 bufferId) -{ - gBattleResources->transferBuffer[0] = CONTROLLER_CLEARUNKVAR; - gBattleResources->transferBuffer[1] = CONTROLLER_CLEARUNKVAR; - gBattleResources->transferBuffer[2] = CONTROLLER_CLEARUNKVAR; - gBattleResources->transferBuffer[3] = CONTROLLER_CLEARUNKVAR; - PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4); -} - -static void UNUSED BtlController_EmitSetUnkVar(u32 battler, u32 bufferId, u8 b) -{ - gBattleResources->transferBuffer[0] = CONTROLLER_SETUNKVAR; - gBattleResources->transferBuffer[1] = b; - PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 2); -} - -static void UNUSED BtlController_EmitClearUnkFlag(u32 battler, u32 bufferId) -{ - gBattleResources->transferBuffer[0] = CONTROLLER_CLEARUNKFLAG; - gBattleResources->transferBuffer[1] = CONTROLLER_CLEARUNKFLAG; - gBattleResources->transferBuffer[2] = CONTROLLER_CLEARUNKFLAG; - gBattleResources->transferBuffer[3] = CONTROLLER_CLEARUNKFLAG; - PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4); -} - -static void UNUSED BtlController_EmitToggleUnkFlag(u32 battler, u32 bufferId) -{ - gBattleResources->transferBuffer[0] = CONTROLLER_TOGGLEUNKFLAG; - gBattleResources->transferBuffer[1] = CONTROLLER_TOGGLEUNKFLAG; - gBattleResources->transferBuffer[2] = CONTROLLER_TOGGLEUNKFLAG; - gBattleResources->transferBuffer[3] = CONTROLLER_TOGGLEUNKFLAG; - PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4); -} - void BtlController_EmitHitAnimation(u32 battler, u32 bufferId) { gBattleResources->transferBuffer[0] = CONTROLLER_HITANIMATION; @@ -1616,7 +1581,7 @@ static u32 GetBattlerMonData(u32 battler, struct Pokemon *party, u32 monId, u8 * u32 side = GetBattlerSide(battler); u32 partyIndex = gBattlerPartyIndexes[battler]; if (TestRunner_Battle_GetForcedAbility(side, partyIndex)) - gBattleMons[battler].ability = gBattleStruct->overwrittenAbilities[battler] = TestRunner_Battle_GetForcedAbility(side, partyIndex); + gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex); } #endif break; @@ -2111,13 +2076,13 @@ static bool8 ShouldDoSlideInAnim(void) return TRUE; } -void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit, bool32 doSlideIn) +void StartSendOutAnim(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstituteBit, bool32 doSlideIn) { u16 species; u32 side = GetBattlerSide(battler); struct Pokemon *party = GetBattlerParty(battler); - ClearTemporarySpeciesSpriteData(battler, dontClearSubstituteBit); + ClearTemporarySpeciesSpriteData(battler, dontClearTransform, dontClearSubstituteBit); gBattlerPartyIndexes[battler] = gBattleResources->bufferA[battler][1]; species = GetIllusionMonSpecies(battler); if (species == SPECIES_NONE) @@ -2462,11 +2427,11 @@ void BtlController_HandleLoadMonSprite(u32 battler, void (*controllerCallback)(u void BtlController_HandleSwitchInAnim(u32 battler, bool32 isPlayerSide, void (*controllerCallback)(u32 battler)) { if (isPlayerSide) - ClearTemporarySpeciesSpriteData(battler, gBattleResources->bufferA[battler][2]); + ClearTemporarySpeciesSpriteData(battler, gBattleResources->bufferA[battler][2], gBattleResources->bufferA[battler][3]); gBattlerPartyIndexes[battler] = gBattleResources->bufferA[battler][1]; if (isPlayerSide) BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battler]], battler); - StartSendOutAnim(battler, gBattleResources->bufferA[battler][2], FALSE); + StartSendOutAnim(battler, gBattleResources->bufferA[battler][2], gBattleResources->bufferA[battler][3], FALSE); gBattlerControllerFuncs[battler] = controllerCallback; } @@ -2542,7 +2507,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; } @@ -2758,30 +2726,6 @@ void BtlController_HandleStatusAnimation(u32 battler) } } -void BtlController_HandleClearUnkVar(u32 battler) -{ - gUnusedControllerStruct.unk = 0; - BattleControllerComplete(battler); -} - -void BtlController_HandleSetUnkVar(u32 battler) -{ - gUnusedControllerStruct.unk = gBattleResources->bufferA[battler][1]; - BattleControllerComplete(battler); -} - -void BtlController_HandleClearUnkFlag(u32 battler) -{ - gUnusedControllerStruct.flag = 0; - BattleControllerComplete(battler); -} - -void BtlController_HandleToggleUnkFlag(u32 battler) -{ - gUnusedControllerStruct.flag ^= 1; - BattleControllerComplete(battler); -} - void BtlController_HandleHitAnimation(u32 battler) { if (gSprites[gBattlerSpriteIds[battler]].invisible == TRUE) @@ -2962,17 +2906,17 @@ static void Task_StartSendOutAnim(u8 taskId) if (TwoMonsAtSendOut(battler)) { gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler]; - StartSendOutAnim(battler, FALSE, ShouldDoSlideInAnim()); + StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim()); battlerPartner = battler ^ BIT_FLANK; gBattleResources->bufferA[battlerPartner][1] = gBattlerPartyIndexes[battlerPartner]; BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battlerPartner]], battlerPartner); - StartSendOutAnim(battlerPartner, FALSE, ShouldDoSlideInAnim()); + StartSendOutAnim(battlerPartner, FALSE, FALSE, ShouldDoSlideInAnim()); } else { gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler]; - StartSendOutAnim(battler, FALSE, ShouldDoSlideInAnim()); + StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim()); } gBattlerControllerFuncs[battler] = (void*)(GetWordTaskArg(taskId, tControllerFunc_1)); DestroyTask(taskId); diff --git a/src/battle_debug.c b/src/battle_debug.c index b03ef194f042..b140d3791ed7 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -220,7 +220,7 @@ enum LIST_AI_CHECK_VIABILITY, LIST_AI_SETUP_FIRST_TURN, LIST_AI_RISKY, - LIST_AI_PREFER_STRONGEST_MOVE, + LIST_AI_TRY_TO_2HKO, LIST_AI_PREFER_BATON_PASS, LIST_AI_DOUBLE_BATTLE, LIST_AI_HP_AWARE, @@ -385,7 +385,7 @@ static const u8 sText_TryToFaint[] = _("Try to Faint"); static const u8 sText_CheckViability[] = _("Check Viability"); static const u8 sText_SetUpFirstTurn[] = _("Setup First Turn"); static const u8 sText_Risky[] = _("Risky"); -static const u8 sText_PreferStrongestMove[] = _("Prefer Strongest Move"); +static const u8 sText_TryTo2HKO[] = _("Try to 2HKO"); static const u8 sText_PreferBatonPass[] = _("Prefer Baton Pass"); static const u8 sText_DoubleBattle[] = _("Double Battle"); static const u8 sText_HpAware[] = _("HP Aware"); @@ -628,7 +628,7 @@ static const struct ListMenuItem sAIListItems[] = {sText_CheckViability, LIST_AI_CHECK_VIABILITY}, {sText_SetUpFirstTurn, LIST_AI_SETUP_FIRST_TURN}, {sText_Risky, LIST_AI_RISKY}, - {sText_PreferStrongestMove, LIST_AI_PREFER_STRONGEST_MOVE}, + {sText_TryTo2HKO, LIST_AI_TRY_TO_2HKO}, {sText_PreferBatonPass, LIST_AI_PREFER_BATON_PASS}, {sText_DoubleBattle, LIST_AI_DOUBLE_BATTLE}, {sText_HpAware, LIST_AI_HP_AWARE}, @@ -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: diff --git a/src/battle_dome.c b/src/battle_dome.c index 8b376c7e752b..19c508652342 100644 --- a/src/battle_dome.c +++ b/src/battle_dome.c @@ -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++) diff --git a/src/battle_dynamax.c b/src/battle_dynamax.c index 876f1e532b5e..38664c5d09bd 100644 --- a/src/battle_dynamax.c +++ b/src/battle_dynamax.c @@ -123,22 +123,22 @@ bool32 CanDynamax(u32 battler) // Returns whether a battler is transformed into a Gigantamax form. bool32 IsGigantamaxed(u32 battler) { - struct Pokemon *mon = &GetSideParty(GetBattlerSide(battler))[gBattlerPartyIndexes[battler]]; + struct Pokemon *mon = GetPartyBattlerData(battler); if ((gSpeciesInfo[gBattleMons[battler].species].isGigantamax) && GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR)) return TRUE; return FALSE; } // Applies the HP Multiplier for Dynamaxed Pokemon and Raid Bosses. -void ApplyDynamaxHPMultiplier(u32 battler, struct Pokemon* mon) +void ApplyDynamaxHPMultiplier(struct Pokemon* mon) { if (GetMonData(mon, MON_DATA_SPECIES) == SPECIES_SHEDINJA) return; else { - u32 scale = 150 + 5 * GetMonData(mon, MON_DATA_DYNAMAX_LEVEL); - u32 hp = (GetMonData(mon, MON_DATA_HP) * scale + 99) / 100; - u32 maxHP = (GetMonData(mon, MON_DATA_MAX_HP) * scale + 99) / 100; + uq4_12_t multiplier = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), FALSE); + u32 hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * multiplier) + UQ_4_12_ROUND); + u32 maxHP = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_MAX_HP) * multiplier) + UQ_4_12_ROUND); SetMonData(mon, MON_DATA_HP, &hp); SetMonData(mon, MON_DATA_MAX_HP, &maxHP); } @@ -151,8 +151,9 @@ u16 GetNonDynamaxHP(u32 battler) return gBattleMons[battler].hp; else { - u16 mult = UQ_4_12_FLOORED(1.0/1.5); // placeholder - u16 hp = UQ_4_12_TO_INT((gBattleMons[battler].hp * mult) + UQ_4_12_ROUND); + struct Pokemon *mon = GetPartyBattlerData(battler); + uq4_12_t mult = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), TRUE); + u32 hp = UQ_4_12_TO_INT((gBattleMons[battler].hp * mult) + UQ_4_12_ROUND); return hp; } } @@ -164,8 +165,9 @@ u16 GetNonDynamaxMaxHP(u32 battler) return gBattleMons[battler].maxHP; else { - u16 mult = UQ_4_12_FLOORED(1.0/1.5); // placeholder - u16 maxHP = UQ_4_12_TO_INT((gBattleMons[battler].maxHP * mult) + UQ_4_12_ROUND); + struct Pokemon *mon = GetPartyBattlerData(battler); + uq4_12_t mult = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), TRUE); + u32 maxHP = UQ_4_12_TO_INT((gBattleMons[battler].maxHP * mult) + UQ_4_12_ROUND); return maxHP; } } @@ -202,7 +204,7 @@ void UndoDynamax(u32 battler) if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX) { struct Pokemon *mon = (side == B_SIDE_PLAYER) ? &gPlayerParty[monId] : &gEnemyParty[monId]; - u16 mult = UQ_4_12_FLOORED(1.0/1.5); // placeholder + uq4_12_t mult = GetDynamaxLevelHPMultiplier(GetMonData(mon, MON_DATA_DYNAMAX_LEVEL), TRUE); gBattleMons[battler].hp = UQ_4_12_TO_INT((GetMonData(mon, MON_DATA_HP) * mult + 1) + UQ_4_12_ROUND); // round up SetMonData(mon, MON_DATA_HP, &gBattleMons[battler].hp); CalculateMonStats(mon); @@ -240,7 +242,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: @@ -254,12 +256,12 @@ static u16 GetTypeBasedMaxMove(u32 battler, u32 type) // Gigantamax check u32 i; u32 species = gBattleMons[battler].species; - u32 targetSpecies = SPECIES_NONE; + u32 targetSpecies = species; if (!gSpeciesInfo[species].isGigantamax) targetSpecies = GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_GIGANTAMAX); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != species) species = targetSpecies; if (gSpeciesInfo[species].isGigantamax) @@ -282,7 +284,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 +294,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 +322,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.maxEffect == MAX_EFFECT_FIXED_POWER) + if (GetMoveMaxEffect(GetMaxMove(gBattlerAttacker, move)) == MAX_EFFECT_FIXED_POWER) return 160; // Exceptions to all other rules below: @@ -333,8 +335,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 +372,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 +386,7 @@ static u8 GetMaxPowerTier(u32 move) } } - switch (gMovesInfo[move].effect) + switch (GetMoveEffect(move)) { case EFFECT_BIDE: case EFFECT_SUPER_FANG: @@ -418,7 +422,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 +432,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 +474,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.maxEffect; + u8 maxEffect = GetMoveMaxEffect(move); switch (maxEffect) { // Status 1 @@ -508,10 +512,10 @@ void BS_UpdateDynamax(void) { NATIVE_ARGS(); u32 battler = gBattleScripting.battler; - struct Pokemon *mon = &GetSideParty(GetBattlerSide(battler))[gBattlerPartyIndexes[battler]]; + struct Pokemon *mon = GetPartyBattlerData(battler); if (!IsGigantamaxed(battler)) // RecalcBattlerStats will get called on form change. - RecalcBattlerStats(battler, mon); + RecalcBattlerStats(battler, mon, GetActiveGimmick(battler) == GIMMICK_DYNAMAX); UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL); gBattlescriptCurrInstr = cmd->nextInstr; @@ -522,7 +526,7 @@ void BS_SetMaxMoveEffect(void) { NATIVE_ARGS(); u16 effect = 0; - u8 maxEffect = gMovesInfo[gCurrentMove].argument.maxEffect; + u8 maxEffect = GetMoveMaxEffect(gCurrentMove); // Don't continue if the move didn't land. if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT) @@ -541,7 +545,7 @@ void BS_SetMaxMoveEffect(void) if (!NoAliveMonsForEitherParty()) { // Max Effects are ordered by stat ID. - SET_STATCHANGER(gMovesInfo[gCurrentMove].argument.maxEffect, 1, FALSE); + SET_STATCHANGER(maxEffect, 1, FALSE); BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_EffectRaiseStatAllies; effect++; @@ -569,7 +573,7 @@ void BS_SetMaxMoveEffect(void) break; default: // Max Effects are ordered by stat ID. - statId = gMovesInfo[gCurrentMove].argument.maxEffect - MAX_EFFECT_LOWER_ATTACK + 1; + statId = maxEffect - MAX_EFFECT_LOWER_ATTACK + 1; break; } SET_STATCHANGER(statId, stage, TRUE); @@ -587,19 +591,19 @@ void BS_SetMaxMoveEffect(void) switch (maxEffect) { case MAX_EFFECT_SUN: - weather = ENUM_WEATHER_SUN; + weather = BATTLE_WEATHER_SUN; msg = B_MSG_STARTED_SUNLIGHT; break; case MAX_EFFECT_RAIN: - weather = ENUM_WEATHER_RAIN; + weather = BATTLE_WEATHER_RAIN; msg = B_MSG_STARTED_RAIN; break; case MAX_EFFECT_SANDSTORM: - weather = ENUM_WEATHER_SANDSTORM; + weather = BATTLE_WEATHER_SANDSTORM; msg = B_MSG_STARTED_SANDSTORM; break; case MAX_EFFECT_HAIL: - weather = ENUM_WEATHER_HAIL; + weather = BATTLE_WEATHER_HAIL; msg = B_MSG_STARTED_HAIL; break; } @@ -618,7 +622,7 @@ void BS_SetMaxMoveEffect(void) case MAX_EFFECT_PSYCHIC_TERRAIN: { u32 statusFlag = 0; - switch (gMovesInfo[gCurrentMove].argument.moveProperty) + switch (GetMoveEffectArg_MoveProperty(gCurrentMove)) { case MAX_EFFECT_MISTY_TERRAIN: statusFlag = STATUS_FIELD_MISTY_TERRAIN; @@ -659,11 +663,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++; } diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 611c1bec59a3..7677c9f38c38 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -329,7 +329,7 @@ static u8 GetBattlePalaceMoveGroup(u8 battler, u16 move) case MOVE_TARGET_RANDOM: case MOVE_TARGET_BOTH: case MOVE_TARGET_FOES_AND_ALLY: - if (IS_MOVE_STATUS(move)) + if (IsBattleMoveStatus(move)) return PALACE_MOVE_GROUP_SUPPORT; else return PALACE_MOVE_GROUP_ATTACK; @@ -435,6 +435,18 @@ void SpriteCB_TrainerSlideIn(struct Sprite *sprite) } } +void SpriteCB_TrainerSpawn(struct Sprite *sprite) +{ + if (!(gIntroSlideFlags & 1)) + { + sprite->x2 = 0; + if (sprite->y2 != 0) + sprite->callback = SpriteCB_TrainerSlideVertical; + else + sprite->callback = SpriteCallbackDummy; + } +} + // Slide up to 0 if necessary (used by multi battle intro) static void SpriteCB_TrainerSlideVertical(struct Sprite *sprite) { @@ -597,7 +609,7 @@ bool8 IsBattleSEPlaying(u8 battler) void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler) { - u32 monsPersonality, currentPersonality, isShiny, species, paletteOffset, position; + u32 personalityValue, isShiny, species, paletteOffset, position; const void *lzPaletteData; struct Pokemon *illusionMon = GetIllusionMonPtr(battler); if (illusionMon != NULL) @@ -606,48 +618,42 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler) if (GetMonData(mon, MON_DATA_IS_EGG) || GetMonData(mon, MON_DATA_SPECIES) == SPECIES_NONE) // Don't load GFX of egg pokemon. return; - monsPersonality = GetMonData(mon, MON_DATA_PERSONALITY); isShiny = GetMonData(mon, MON_DATA_IS_SHINY); if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies == SPECIES_NONE) { species = GetMonData(mon, MON_DATA_SPECIES); - currentPersonality = monsPersonality; + personalityValue = GetMonData(mon, MON_DATA_PERSONALITY); } else { species = gBattleSpritesDataPtr->battlerData[battler].transformSpecies; + // If battler has Gigantamax factor, try convert gfx to G-Max version + if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR)) + gBattleSpritesDataPtr->battlerData[battler].transformSpecies = species = GetGMaxTargetSpecies(species); + if (B_TRANSFORM_SHINY >= GEN_4) { - currentPersonality = gTransformedPersonalities[battler]; + personalityValue = gTransformedPersonalities[battler]; isShiny = gTransformedShininess[battler]; } else { - currentPersonality = monsPersonality; + personalityValue = GetMonData(mon, MON_DATA_PERSONALITY); } } position = GetBattlerPosition(battler); - if (GetBattlerSide(battler) == B_SIDE_OPPONENT) - { - HandleLoadSpecialPokePic(TRUE, - gMonSpritesGfxPtr->spritesGfx[position], - species, currentPersonality); - } - else - { - HandleLoadSpecialPokePic(FALSE, - gMonSpritesGfxPtr->spritesGfx[position], - species, currentPersonality); - } + HandleLoadSpecialPokePic((GetBattlerSide(battler) == B_SIDE_OPPONENT), + gMonSpritesGfxPtr->spritesGfx[position], + species, personalityValue); paletteOffset = OBJ_PLTT_ID(battler); if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies == SPECIES_NONE) lzPaletteData = GetMonFrontSpritePal(mon); else - lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, currentPersonality); + lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personalityValue); LZDecompressWram(lzPaletteData, gDecompressionBuffer); LoadPalette(gDecompressionBuffer, paletteOffset, PLTT_SIZE_4BPP); @@ -913,8 +919,10 @@ void CopyBattleSpriteInvisibility(u8 battler) void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bool8 trackEnemyPersonality) { u32 personalityValue, position, paletteOffset, targetSpecies; - bool8 isShiny; + bool32 isShiny; const void *lzPaletteData, *src; + struct Pokemon *monAtk = GetPartyBattlerData(battlerAtk); + struct Pokemon *monDef = GetPartyBattlerData(battlerDef); void *dst; if (IsContest()) @@ -932,48 +940,35 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo else { position = GetBattlerPosition(battlerAtk); - - if (GetBattlerSide(battlerDef) == B_SIDE_OPPONENT) - targetSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_SPECIES); - else - targetSpecies = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_SPECIES); - - if (GetBattlerSide(battlerAtk) == B_SIDE_PLAYER) + if (gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies == SPECIES_NONE) { - if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality && !megaEvo) - { - personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_PERSONALITY); - isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_IS_SHINY); - } + // Get base form if its currently Gigantamax + if (IsGigantamaxed(battlerDef)) + targetSpecies = gBattleStruct->changedSpecies[GetBattlerSide(battlerDef)][gBattlerPartyIndexes[battlerDef]]; else - { - personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY); - isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY); - } - - HandleLoadSpecialPokePic(FALSE, - gMonSpritesGfxPtr->spritesGfx[position], - targetSpecies, - personalityValue); + targetSpecies = GetMonData(monDef, MON_DATA_SPECIES); + personalityValue = GetMonData(monAtk, MON_DATA_PERSONALITY); + isShiny = GetMonData(monAtk, MON_DATA_IS_SHINY); } else { + targetSpecies = gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies; if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality && !megaEvo) { - personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_PERSONALITY); - isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_IS_SHINY); + personalityValue = GetMonData(monDef, MON_DATA_PERSONALITY); + isShiny = GetMonData(monDef, MON_DATA_IS_SHINY); } else { - personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY); - isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY); + personalityValue = GetMonData(monAtk, MON_DATA_PERSONALITY); + isShiny = GetMonData(monAtk, MON_DATA_IS_SHINY); } - - HandleLoadSpecialPokePic(TRUE, - gMonSpritesGfxPtr->spritesGfx[position], - targetSpecies, - personalityValue); } + + HandleLoadSpecialPokePic((GetBattlerSide(battlerAtk) != B_SIDE_PLAYER), + gMonSpritesGfxPtr->spritesGfx[position], + targetSpecies, + personalityValue); } src = gMonSpritesGfxPtr->spritesGfx[position]; dst = (void *)(OBJ_VRAM0 + gSprites[gBattlerSpriteIds[battlerAtk]].oam.tileNum * 32); @@ -993,6 +988,24 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo } } + // dynamax tint + if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX) + { + // Calyrex and its forms have a blue dynamax aura instead of red. + if (GET_BASE_SPECIES_ID(targetSpecies) == SPECIES_CALYREX) + BlendPalette(paletteOffset, 16, 4, RGB(12, 0, 31)); + else + BlendPalette(paletteOffset, 16, 4, RGB(31, 0, 12)); + CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16)); + } + + // Terastallization's tint + if (GetActiveGimmick(battlerAtk) == GIMMICK_TERA) + { + BlendPalette(paletteOffset, 16, 8, GetTeraTypeRGB(GetBattlerTeraType(battlerAtk))); + CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16)); + } + gSprites[gBattlerSpriteIds[battlerAtk]].y = GetBattlerSpriteDefault_Y(battlerAtk); StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], 0); } @@ -1043,7 +1056,8 @@ void LoadBattleMonGfxAndAnimate(u8 battler, bool8 loadMonSprite, u8 spriteId) void TrySetBehindSubstituteSpriteBit(u8 battler, u16 move) { - if (gMovesInfo[move].effect == EFFECT_SUBSTITUTE || gMovesInfo[move].effect == EFFECT_SHED_TAIL) + u32 effect = GetMoveEffect(move); + if (effect == EFFECT_SUBSTITUTE || effect == EFFECT_SHED_TAIL) gBattleSpritesDataPtr->battlerData[battler].behindSubstitute = 1; } @@ -1185,7 +1199,7 @@ void CreateEnemyShadowSprite(u32 battler) { gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteIdPrimary = CreateSprite(&gSpriteTemplate_EnemyShadow, GetBattlerSpriteCoord(battler, BATTLER_COORD_X), - GetBattlerSpriteCoord(battler, BATTLER_COORD_Y), + GetBattlerSpriteCoord(battler, BATTLER_COORD_Y) + 29, 0xC8); if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteIdPrimary < MAX_SPRITES) { @@ -1247,9 +1261,11 @@ void SpriteCB_EnemyShadow(struct Sprite *shadowSprite) return; } - s8 xOffset = 0, yOffset = 0, size = SHADOW_SIZE_S; + s8 xOffset = 0, UNUSED yOffset = 0, size = SHADOW_SIZE_S; if (gAnimScriptActive || battlerSprite->invisible) + { invisible = TRUE; + } else if (transformSpecies != SPECIES_NONE) { xOffset = gSpeciesInfo[transformSpecies].enemyShadowXOffset; @@ -1267,21 +1283,19 @@ void SpriteCB_EnemyShadow(struct Sprite *shadowSprite) yOffset = gSpeciesInfo[species].enemyShadowYOffset + 16; size = gSpeciesInfo[species].enemyShadowSize; } - else - { - yOffset = 29; - } if (gBattleSpritesDataPtr->battlerData[battler].behindSubstitute) invisible = TRUE; shadowSprite->x = battlerSprite->x + xOffset; shadowSprite->x2 = battlerSprite->x2; - shadowSprite->y = battlerSprite->y + yOffset; shadowSprite->invisible = invisible; if (B_ENEMY_MON_SHADOW_STYLE >= GEN_4 && P_GBA_STYLE_SPECIES_GFX == FALSE) + { shadowSprite->oam.tileNum = shadowSprite->tBaseTileNum + (8 * size); + shadowSprite->y = battlerSprite->y + yOffset; + } } #undef tBattlerId @@ -1372,9 +1386,10 @@ void FillAroundBattleWindows(void) } } -void ClearTemporarySpeciesSpriteData(u8 battler, bool8 dontClearSubstitute) +void ClearTemporarySpeciesSpriteData(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstitute) { - gBattleSpritesDataPtr->battlerData[battler].transformSpecies = SPECIES_NONE; + if (!dontClearTransform) + gBattleSpritesDataPtr->battlerData[battler].transformSpecies = SPECIES_NONE; if (!dontClearSubstitute) ClearBehindSubstituteBit(battler); } diff --git a/src/battle_interface.c b/src/battle_interface.c index 5c514a0d80d8..196f33849586 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -2695,6 +2695,17 @@ static void RestoreOverwrittenPixels(u8 *tiles) Free(buffer); } +static inline bool32 IsAnyAbilityPopUpActive(void) +{ + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleStruct->battlerState[battler].activeAbilityPopUps) + return TRUE; + } + + return FALSE; +} + void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) { const s16 (*coords)[2]; @@ -2713,12 +2724,13 @@ void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) return; } - if (!gBattleStruct->activeAbilityPopUps) + if (!IsAnyAbilityPopUpActive()) { LoadSpriteSheet(&sSpriteSheet_AbilityPopUp); LoadSpritePalette(&sSpritePalette_AbilityPopUp); } - gBattleStruct->activeAbilityPopUps |= 1u << battlerId; + + gBattleStruct->battlerState[battlerId].activeAbilityPopUps = TRUE; battlerPosition = GetBattlerPosition(battlerId); if (isDoubleBattle) @@ -2809,7 +2821,7 @@ static void SpriteCb_AbilityPopUp(struct Sprite *sprite) ||(sprite->tRightToLeft && (sprite->x -= 4) <= sprite->tOriginalX - ABILITY_POP_UP_POS_X_SLIDE) ) { - gBattleStruct->activeAbilityPopUps &= ~(1u << sprite->tBattlerId); + gBattleStruct->battlerState[sprite->tBattlerId].activeAbilityPopUps = FALSE; DestroySprite(sprite); } } @@ -2823,7 +2835,7 @@ static void SpriteCb_AbilityPopUp(struct Sprite *sprite) void DestroyAbilityPopUp(u8 battlerId) { - if (gBattleStruct->activeAbilityPopUps & (1u << battlerId)) + if (gBattleStruct->battlerState[battlerId].activeAbilityPopUps) { gSprites[gBattleStruct->abilityPopUpSpriteIds[battlerId][0]].tFrames = 0; gSprites[gBattleStruct->abilityPopUpSpriteIds[battlerId][1]].tFrames = 0; @@ -2835,7 +2847,7 @@ static void Task_FreeAbilityPopUpGfx(u8 taskId) { if (!gSprites[gTasks[taskId].tSpriteId1].inUse && !gSprites[gTasks[taskId].tSpriteId2].inUse - && !gBattleStruct->activeAbilityPopUps) + && !IsAnyAbilityPopUpActive()) { FreeSpriteTilesByTag(ABILITY_POP_UP_TAG); FreeSpritePaletteByTag(ABILITY_POP_UP_TAG); diff --git a/src/battle_intro.c b/src/battle_intro.c index a6b1607285b9..b951c163c839 100644 --- a/src/battle_intro.c +++ b/src/battle_intro.c @@ -8,6 +8,7 @@ #include "main.h" #include "scanline_effect.h" #include "task.h" +#include "test_runner.h" #include "trig.h" #include "constants/battle_partner.h" #include "constants/trainers.h" @@ -17,6 +18,7 @@ static void BattleIntroSlide2(u8); static void BattleIntroSlide3(u8); static void BattleIntroSlideLink(u8); static void BattleIntroSlidePartner(u8); +static void BattleIntroNoSlide(u8); static const u8 sBattleAnimBgCnts[] = {REG_OFFSET_BG0CNT, REG_OFFSET_BG1CNT, REG_OFFSET_BG2CNT, REG_OFFSET_BG3CNT}; @@ -149,9 +151,59 @@ static void BattleIntroSlideEnd(u8 taskId) SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WIN01_CLR | WINOUT_WINOBJ_BG_ALL | WINOUT_WINOBJ_OBJ | WINOUT_WINOBJ_CLR); } +static void BattleIntroNoSlide(u8 taskId) +{ + switch (gTasks[taskId].tState) + { + case 0: + if (gBattleTypeFlags & BATTLE_TYPE_LINK) + { + gTasks[taskId].data[2] = 16; + gTasks[taskId].tState++; + gIntroSlideFlags &= ~1; + } + else + { + gTasks[taskId].data[2] = 1; + gTasks[taskId].tState++; + gIntroSlideFlags &= ~1; + } + break; + case 1: + gTasks[taskId].data[2]--; + if (gTasks[taskId].data[2] == 0) + { + gTasks[taskId].tState++; + SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR); + gScanlineEffect.state = 3; + } + break; + case 2: + gBattle_WIN0V -= 0xFF * 2; + if ((gBattle_WIN0V & 0xFF00) == 0) + { + gTasks[taskId].tState++; + } + break; + case 3: + gTasks[taskId].tState++; + CpuFill32(0, (void *)BG_SCREEN_ADDR(28), BG_SCREEN_SIZE); + SetBgAttribute(1, BG_ATTR_CHARBASEINDEX, 0); + SetBgAttribute(2, BG_ATTR_CHARBASEINDEX, 0); + SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(28) | BGCNT_TXT256x512); + SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_16COLOR | BGCNT_SCREENBASE(30) | BGCNT_TXT512x256); + break; + case 4: + BattleIntroSlideEnd(taskId); + break; + } +} + static void BattleIntroSlide1(u8 taskId) { int i; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + return BattleIntroNoSlide(taskId); gBattle_BG1_X += 6; switch (gTasks[taskId].tState) @@ -237,6 +289,8 @@ static void BattleIntroSlide1(u8 taskId) static void BattleIntroSlide2(u8 taskId) { int i; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + return BattleIntroNoSlide(taskId); switch (gTasks[taskId].tTerrain) { @@ -349,6 +403,8 @@ static void BattleIntroSlide2(u8 taskId) static void BattleIntroSlide3(u8 taskId) { int i; + if (B_FAST_INTRO_NO_SLIDE || gTestRunnerHeadless) + return BattleIntroNoSlide(taskId); gBattle_BG1_X += 8; switch (gTasks[taskId].tState) diff --git a/src/battle_main.c b/src/battle_main.c index c23fc300402a..5c1b999ab95b 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -20,10 +20,12 @@ #include "data.h" #include "debug.h" #include "decompress.h" +#include "dexnav.h" #include "dma3.h" #include "event_data.h" #include "evolution_scene.h" #include "field_weather.h" +#include "generational_changes.h" #include "graphics.h" #include "gpu_regs.h" #include "international_string_util.h" @@ -162,7 +164,6 @@ EWRAM_DATA u8 gChosenMovePos = 0; EWRAM_DATA u16 gCurrentMove = 0; EWRAM_DATA u16 gChosenMove = 0; EWRAM_DATA u16 gCalledMove = 0; -EWRAM_DATA s32 gHpDealt = 0; EWRAM_DATA s32 gBideDmg[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA u16 gLastUsedItem = 0; EWRAM_DATA u16 gLastUsedAbility = 0; @@ -483,21 +484,24 @@ static void CB2_InitBattleInternal(void) else { gBattle_WIN0V = WIN_RANGE(DISPLAY_HEIGHT / 2, DISPLAY_HEIGHT / 2 + 1); - ScanlineEffect_Clear(); - - for (i = 0; i < DISPLAY_HEIGHT / 2; i++) + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) { - gScanlineEffectRegBuffers[0][i] = 0xF0; - gScanlineEffectRegBuffers[1][i] = 0xF0; - } + ScanlineEffect_Clear(); - for (; i < DISPLAY_HEIGHT; i++) - { - gScanlineEffectRegBuffers[0][i] = 0xFF10; - gScanlineEffectRegBuffers[1][i] = 0xFF10; - } + for (i = 0; i < DISPLAY_HEIGHT / 2; i++) + { + gScanlineEffectRegBuffers[0][i] = 0xF0; + gScanlineEffectRegBuffers[1][i] = 0xF0; + } - ScanlineEffect_SetParams(sIntroScanlineParams16Bit); + for (; i < DISPLAY_HEIGHT; i++) + { + gScanlineEffectRegBuffers[0][i] = 0xFF10; + gScanlineEffectRegBuffers[1][i] = 0xFF10; + } + + ScanlineEffect_SetParams(sIntroScanlineParams16Bit); + } } ResetPaletteFade(); @@ -528,7 +532,8 @@ static void CB2_InitBattleInternal(void) LoadBattleTextboxAndBackground(); ResetSpriteData(); ResetTasks(); - DrawBattleEntryBackground(); + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + DrawBattleEntryBackground(); FreeAllSpritePalettes(); gReservedSpritePaletteCount = MAX_BATTLERS_COUNT; SetVBlankCallback(VBlankCB_Battle); @@ -1906,8 +1911,9 @@ void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMon for (j = 0; j < MAX_MON_MOVES; ++j) { + u32 pp = GetMovePP(partyEntry->moves[j]); SetMonData(mon, MON_DATA_MOVE1 + j, &partyEntry->moves[j]); - SetMonData(mon, MON_DATA_PP1 + j, &gMovesInfo[partyEntry->moves[j]].pp); + SetMonData(mon, MON_DATA_PP1 + j, &pp); } } @@ -2054,6 +2060,8 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir void CreateTrainerPartyForPlayer(void) { + Script_RequestEffects(SCREFF_V1); + ZeroPlayerPartyMons(); gPartnerTrainerId = gSpecialVar_0x8004; CreateNPCTrainerPartyFromTrainer(gPlayerParty, GetTrainerStructFromId(gSpecialVar_0x8004), TRUE, BATTLE_TYPE_TRAINER); @@ -2646,17 +2654,24 @@ void SpriteCB_WildMon(struct Sprite *sprite) { sprite->callback = SpriteCB_MoveWildMonToRight; StartSpriteAnimIfDifferent(sprite, 0); - if (WILD_DOUBLE_BATTLE) - BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 10, RGB(8, 8, 8)); - else - BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 10, RGB(8, 8, 8)); + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + { + if (WILD_DOUBLE_BATTLE) + BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 10, RGB(8, 8, 8)); + else + BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 10, RGB(8, 8, 8)); + } } static void SpriteCB_MoveWildMonToRight(struct Sprite *sprite) { if ((gIntroSlideFlags & 1) == 0) { - sprite->x2 += 2; + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + sprite->x2 += 2; + else + sprite->x2 = 0; + if (sprite->x2 == 0) { sprite->callback = SpriteCB_WildMonShowHealthbox; @@ -2672,10 +2687,13 @@ static void SpriteCB_WildMonShowHealthbox(struct Sprite *sprite) SetHealthboxSpriteVisible(gHealthboxSpriteIds[sprite->sBattler]); sprite->callback = SpriteCB_WildMonAnimate; StartSpriteAnimIfDifferent(sprite, 0); - if (WILD_DOUBLE_BATTLE) - BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 0, RGB(8, 8, 8)); - else - BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 0, RGB(8, 8, 8)); + if (B_FAST_INTRO_NO_SLIDE == FALSE && !gTestRunnerHeadless) + { + if (WILD_DOUBLE_BATTLE) + BeginNormalPaletteFade((0x10000 << sprite->sBattler) | (0x10000 << BATTLE_PARTNER(sprite->sBattler)), 0, 10, 0, RGB(8, 8, 8)); + else + BeginNormalPaletteFade((0x10000 << sprite->sBattler), 0, 10, 0, RGB(8, 8, 8)); + } } } @@ -3031,7 +3049,6 @@ static void BattleStartClearSetData(void) gLastHitBy[i] = 0xFF; gLockedMoves[i] = MOVE_NONE; gLastPrintedMoves[i] = MOVE_NONE; - gBattleResources->flags->flags[i] = 0; gPalaceSelectionBattleScripts[i] = 0; gBattleStruct->lastTakenMove[i] = MOVE_NONE; gBattleStruct->choicedMove[i] = MOVE_NONE; @@ -3042,7 +3059,6 @@ static void BattleStartClearSetData(void) gBattleStruct->lastTakenMoveFrom[i][3] = MOVE_NONE; gBattleStruct->AI_monToSwitchIntoId[i] = PARTY_SIZE; gBattleStruct->skyDropTargets[i] = 0xFF; - gBattleStruct->overwrittenAbilities[i] = ABILITY_NONE; } gLastUsedMove = 0; @@ -3116,10 +3132,8 @@ static void BattleStartClearSetData(void) gBattleStruct->swapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky gBattleStruct->categoryOverride = FALSE; // used for Z-Moves and Max Moves - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; + ClearPursuitValues(); gSelectedMonPartyId = PARTY_SIZE; // Revival Blessing gCategoryIconSpriteId = 0xFF; @@ -3134,10 +3148,11 @@ static void BattleStartClearSetData(void) void SwitchInClearSetData(u32 battler) { s32 i; + u32 effect = GetMoveEffect(gCurrentMove); struct DisableStruct disableStructCopy = gDisableStructs[battler]; ClearIllusionMon(battler); - if (gMovesInfo[gCurrentMove].effect != EFFECT_BATON_PASS) + if (effect != EFFECT_BATON_PASS) { for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE; @@ -3152,7 +3167,7 @@ void SwitchInClearSetData(u32 battler) } } } - if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS) + if (effect == EFFECT_BATON_PASS) { gBattleMons[battler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY_ANY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED); gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED @@ -3194,7 +3209,7 @@ void SwitchInClearSetData(u32 battler) memset(&gDisableStructs[battler], 0, sizeof(struct DisableStruct)); - if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS) + if (effect == EFFECT_BATON_PASS) { gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP; gDisableStructs[battler].battlerWithSureHit = disableStructCopy.battlerWithSureHit; @@ -3202,7 +3217,7 @@ void SwitchInClearSetData(u32 battler) gDisableStructs[battler].battlerPreventingEscape = disableStructCopy.battlerPreventingEscape; gDisableStructs[battler].embargoTimer = disableStructCopy.embargoTimer; } - else if (gMovesInfo[gCurrentMove].effect == EFFECT_SHED_TAIL) + else if (effect == EFFECT_SHED_TAIL) { gBattleMons[battler].status2 |= STATUS2_SUBSTITUTE; gDisableStructs[battler].substituteHP = disableStructCopy.substituteHP; @@ -3225,17 +3240,11 @@ void SwitchInClearSetData(u32 battler) gBattleStruct->lastTakenMoveFrom[battler][1] = 0; gBattleStruct->lastTakenMoveFrom[battler][2] = 0; gBattleStruct->lastTakenMoveFrom[battler][3] = 0; - gBattleStruct->lastMoveFailed &= ~(1u << battler); + gBattleStruct->battlerState[battler].lastMoveFailed = FALSE; gBattleStruct->palaceFlags &= ~(1u << battler); - gBattleStruct->boosterEnergyActivates &= ~(1u << battler); gBattleStruct->canPickupItem &= ~(1u << battler); - if (gBattleStruct->pursuitTarget & (1u << battler)) - { - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; - } + ClearPursuitValuesIfSet(battler); for (i = 0; i < ARRAY_COUNT(gSideTimers); i++) { @@ -3253,14 +3262,13 @@ void SwitchInClearSetData(u32 battler) } gBattleStruct->choicedMove[battler] = MOVE_NONE; - gBattleResources->flags->flags[battler] = 0; gCurrentMove = MOVE_NONE; gBattleStruct->arenaTurnCounter = 0xFF; // Reset damage to prevent things like red card activating if the switched-in mon is holding it gSpecialStatuses[battler].physicalDmg = 0; gSpecialStatuses[battler].specialDmg = 0; - gBattleStruct->enduredDamage &= ~(1u << battler); + gSpecialStatuses[battler].enduredDamage = FALSE; // Reset Eject Button / Eject Pack switch detection AI_DATA->ejectButtonSwitch = FALSE; @@ -3269,8 +3277,6 @@ void SwitchInClearSetData(u32 battler) // Reset G-Max Chi Strike boosts. gBattleStruct->bonusCritStages[battler] = 0; - gBattleStruct->overwrittenAbilities[battler] = ABILITY_NONE; - // Clear selected party ID so Revival Blessing doesn't get confused. gSelectedMonPartyId = PARTY_SIZE; @@ -3281,7 +3287,7 @@ void SwitchInClearSetData(u32 battler) u32 side = GetBattlerSide(battler); u32 partyIndex = gBattlerPartyIndexes[battler]; if (TestRunner_Battle_GetForcedAbility(side, partyIndex)) - gBattleMons[i].ability = gBattleStruct->overwrittenAbilities[i] = TestRunner_Battle_GetForcedAbility(side, partyIndex); + gBattleMons[i].ability = gDisableStructs[i].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex); } #endif // TESTING @@ -3367,16 +3373,9 @@ const u8* FaintClearSetData(u32 battler) gBattleStruct->lastTakenMoveFrom[battler][1] = 0; gBattleStruct->lastTakenMoveFrom[battler][2] = 0; gBattleStruct->lastTakenMoveFrom[battler][3] = 0; - - if (gBattleStruct->pursuitTarget & (1u << battler)) - { - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; - } - gBattleStruct->palaceFlags &= ~(1u << battler); - gBattleStruct->boosterEnergyActivates &= ~(1u << battler); + + ClearPursuitValuesIfSet(battler); if (gBattleStruct->commanderActive[battler] != SPECIES_NONE) { @@ -3403,8 +3402,6 @@ const u8* FaintClearSetData(u32 battler) gBattleStruct->lastTakenMoveFrom[i][battler] = 0; } - gBattleResources->flags->flags[battler] = 0; - gBattleMons[battler].types[0] = gSpeciesInfo[gBattleMons[battler].species].types[0]; gBattleMons[battler].types[1] = gSpeciesInfo[gBattleMons[battler].species].types[1]; gBattleMons[battler].types[2] = TYPE_MYSTERY; @@ -3412,8 +3409,6 @@ const u8* FaintClearSetData(u32 battler) Ai_UpdateFaintData(battler); TryBattleFormChange(battler, FORM_CHANGE_FAINT); - gBattleStruct->overwrittenAbilities[battler] = ABILITY_NONE; - // If the fainted mon was involved in a Sky Drop if (gBattleStruct->skyDropTargets[battler] != 0xFF) { @@ -3520,7 +3515,7 @@ static void DoBattleIntro(void) u32 side = GetBattlerSide(battler); u32 partyIndex = gBattlerPartyIndexes[battler]; if (TestRunner_Battle_GetForcedAbility(side, partyIndex)) - gBattleMons[battler].ability = gBattleStruct->overwrittenAbilities[battler] = TestRunner_Battle_GetForcedAbility(side, partyIndex); + gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex); } #endif } @@ -3580,7 +3575,7 @@ static void DoBattleIntro(void) } else // Skip party summary since it is a wild battle. { - if (B_FAST_INTRO == TRUE) + if (B_FAST_INTRO_PKMN_TEXT == TRUE) gBattleStruct->introState = BATTLE_INTRO_STATE_INTRO_TEXT; // Don't wait for sprite, print message at the same time. else gBattleStruct->introState++; // Wait for sprite to load. @@ -3652,7 +3647,7 @@ static void DoBattleIntro(void) } else { - if (B_FAST_INTRO == TRUE) + if (B_FAST_INTRO_PKMN_TEXT == TRUE) gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; else gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_TRAINER_2_SEND_OUT_ANIM; @@ -3691,7 +3686,7 @@ static void DoBattleIntro(void) BtlController_EmitIntroTrainerBallThrow(battler, BUFFER_A); MarkBattlerForControllerExec(battler); } - if (B_FAST_INTRO == TRUE + if (B_FAST_INTRO_PKMN_TEXT == TRUE && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_LINK))) gBattleStruct->introState = BATTLE_INTRO_STATE_WAIT_FOR_WILD_BATTLE_TEXT; // Print at the same time as trainer sends out second mon. else @@ -3714,7 +3709,7 @@ static void DoBattleIntro(void) battler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); // A hack that makes fast intro work in trainer battles too. - if (B_FAST_INTRO == TRUE + if (B_FAST_INTRO_PKMN_TEXT == TRUE && gBattleTypeFlags & BATTLE_TYPE_TRAINER && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_RECORDED_IS_MASTER | BATTLE_TYPE_LINK)) && gSprites[gHealthboxSpriteIds[battler ^ BIT_SIDE]].callback == SpriteCallbackDummy) @@ -3836,7 +3831,7 @@ static void TryDoEventsBeforeFirstTurn(void) u32 side = GetBattlerSide(i); u32 partyIndex = gBattlerPartyIndexes[i]; if (TestRunner_Battle_GetForcedAbility(side, partyIndex)) - gBattleMons[i].ability = gBattleStruct->overwrittenAbilities[i] = TestRunner_Battle_GetForcedAbility(side, partyIndex); + gBattleMons[i].ability = gDisableStructs[i].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex); } } #endif // TESTING @@ -3939,10 +3934,10 @@ static void TryDoEventsBeforeFirstTurn(void) *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; gChosenActionByBattler[i] = B_ACTION_NONE; gChosenMoveByBattler[i] = MOVE_NONE; + gBattleStruct->battlerState[i].absentBattlerFlags = gAbsentBattlerFlags & (1u << i); } TurnValuesCleanUp(FALSE); SpecialStatusesClear(); - *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); gBattleMainFunc = HandleTurnActionSelectionState; @@ -4056,12 +4051,12 @@ void BattleTurnPassed(void) { gChosenActionByBattler[i] = B_ACTION_NONE; gChosenMoveByBattler[i] = MOVE_NONE; + gBattleStruct->battlerState[i].absentBattlerFlags = gAbsentBattlerFlags & (1u << i); } for (i = 0; i < MAX_BATTLERS_COUNT; i++) *(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE; - *(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags; BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG); AssignUsableGimmicks(); SetShellSideArmCategory(); @@ -4206,6 +4201,30 @@ enum STATE_SELECTION_SCRIPT_MAY_RUN }; +void SetupAISwitchingData(u32 battler, bool32 isAiRisky) +{ + s32 opposingBattler = GetBattlerAtPosition(BATTLE_OPPOSITE(GetBattlerPosition(battler))); + + // AI's data + AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, isAiRisky); + if (ShouldSwitch(battler)) + AI_DATA->shouldSwitch |= (1u << battler); + + // AI's predicting data + if ((AI_THINKING_STRUCT->aiFlags[battler] & AI_FLAG_PREDICT_SWITCH)) + { + AI_DATA->aiSwitchPredictionInProgress = TRUE; + AI_DATA->battlerDoingPrediction = battler; + AI_DATA->mostSuitableMonId[opposingBattler] = GetMostSuitableMonToSwitchInto(opposingBattler, isAiRisky); + if (ShouldSwitch(opposingBattler)) + AI_DATA->shouldSwitch |= (1u << opposingBattler); + AI_DATA->aiSwitchPredictionInProgress = FALSE; + + // Determine whether AI will use predictions this turn + AI_DATA->predictingSwitch = RandomPercentage(RNG_AI_PREDICT_SWITCH, 50); + } +} + static void HandleTurnActionSelectionState(void) { s32 i, battler; @@ -4230,11 +4249,7 @@ static void HandleTurnActionSelectionState(void) // Setup battler data sBattler_AI = battler; BattleAI_SetupAIData(0xF, sBattler_AI); - - // Setup switching data - AI_DATA->mostSuitableMonId[battler] = GetMostSuitableMonToSwitchInto(battler, isAiRisky); - if (ShouldSwitch(battler)) - AI_DATA->shouldSwitch |= (1u << battler); + SetupAISwitchingData(battler, isAiRisky); // Do scoring gBattleStruct->aiMoveOrAction[battler] = BattleAI_ChooseMoveOrAction(); @@ -4245,10 +4260,10 @@ static void HandleTurnActionSelectionState(void) *(gBattleStruct->monToSwitchIntoId + battler) = PARTY_SIZE; if (gBattleTypeFlags & BATTLE_TYPE_MULTI || (position & BIT_FLANK) == B_FLANK_LEFT - || gBattleStruct->absentBattlerFlags & (1u << GetBattlerAtPosition(BATTLE_PARTNER(position))) + || gBattleStruct->battlerState[GetBattlerAtPosition(BATTLE_PARTNER(position))].absentBattlerFlags || gBattleCommunication[GetBattlerAtPosition(BATTLE_PARTNER(position))] == STATE_WAIT_ACTION_CONFIRMED) { - if ((gBattleStruct->absentBattlerFlags & (1u << battler)) || (gBattleStruct->commandingDondozo & (1u << battler))) + if (gBattleStruct->battlerState[battler].absentBattlerFlags || gBattleStruct->battlerState[battler].commandingDondozo) { gChosenActionByBattler[battler] = B_ACTION_NOTHING_FAINTED; if (!(gBattleTypeFlags & BATTLE_TYPE_MULTI)) @@ -4623,7 +4638,7 @@ static void HandleTurnActionSelectionState(void) if (((gBattleTypeFlags & BATTLE_TYPE_MULTI) || !IsDoubleBattle()) || (position & BIT_FLANK) != B_FLANK_LEFT - || (*(&gBattleStruct->absentBattlerFlags) & (1u << GetBattlerAtPosition(BATTLE_PARTNER(position))))) + || gBattleStruct->battlerState[GetBattlerAtPosition(BATTLE_PARTNER(position))].absentBattlerFlags) { BtlController_EmitLinkStandbyMsg(battler, BUFFER_A, LINK_STANDBY_MSG_STOP_BOUNCE, i); } @@ -4789,9 +4804,9 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) speed *= 2; else if (ability == ABILITY_SLOW_START && gDisableStructs[battler].slowStartTimer != 0) speed /= 2; - else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battler))) + else if (ability == ABILITY_PROTOSYNTHESIS && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && ((gBattleWeather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gDisableStructs[battler].boosterEnergyActivates)) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; - else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battler))) + else if (ability == ABILITY_QUARK_DRIVE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) && (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battler].boosterEnergyActivates)) speed = (GetHighestStatId(battler) == STAT_SPEED) ? (speed * 150) / 100 : speed; // stat stages @@ -4819,7 +4834,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) // various effects if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND) speed *= 2; - if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_UNBURDEN) + if (gDisableStructs[battler].unbrudenActive) speed *= 2; // paralysis drop @@ -4849,35 +4864,35 @@ s8 GetChosenMovePriority(u32 battler) else move = gBattleMons[battler].moves[*(gBattleStruct->chosenMovePositions + battler)]; - return GetMovePriority(battler, move); + return GetBattleMovePriority(battler, move); } -s8 GetMovePriority(u32 battler, u16 move) +s8 GetBattleMovePriority(u32 battler, u16 move) { s8 priority; u16 ability = GetBattlerAbility(battler); - if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(move)) + if (GetActiveGimmick(battler) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move)) move = GetUsableZMove(battler, move); - priority = gMovesInfo[move].priority; + priority = GetMovePriority(move); // Max Guard check - if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) - return gMovesInfo[MOVE_MAX_GUARD].priority; + if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS) + return GetMovePriority(MOVE_MAX_GUARD); if (ability == ABILITY_GALE_WINGS - && (B_GALE_WINGS < GEN_7 || IsBattlerAtMaxHp(battler)) - && gMovesInfo[move].type == TYPE_FLYING) + && (GetGenConfig(GEN_CONFIG_GALE_WINGS) < GEN_7 || IsBattlerAtMaxHp(battler)) + && GetMoveType(move) == TYPE_FLYING) { priority++; } - else if (ability == ABILITY_PRANKSTER && IS_MOVE_STATUS(move)) + else if (ability == ABILITY_PRANKSTER && IsBattleMoveStatus(move)) { gProtectStructs[battler].pranksterElevated = 1; priority++; } - else if (gMovesInfo[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_DYNAMAX && !IsGimmickSelected(battler, GIMMICK_DYNAMAX)) + else if (GetMoveEffect(move) == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battler) && GetActiveGimmick(gBattlerAttacker) != GIMMICK_DYNAMAX && !IsGimmickSelected(battler, GIMMICK_DYNAMAX)) { priority++; } @@ -4903,8 +4918,8 @@ s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMov // Lagging Tail - always last bool32 battler1HasQuickEffect = gProtectStructs[battler1].quickDraw || gProtectStructs[battler1].usedCustapBerry; bool32 battler2HasQuickEffect = gProtectStructs[battler2].quickDraw || gProtectStructs[battler2].usedCustapBerry; - bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || (ability1 == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gChosenMoveByBattler[battler1])); - bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || (ability2 == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gChosenMoveByBattler[battler2])); + bool32 battler1HasStallingAbility = ability1 == ABILITY_STALL || (ability1 == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gChosenMoveByBattler[battler1])); + bool32 battler2HasStallingAbility = ability2 == ABILITY_STALL || (ability2 == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gChosenMoveByBattler[battler2])); if (battler1HasQuickEffect && !battler2HasQuickEffect) strikesFirst = 1; @@ -5172,9 +5187,10 @@ static void TurnValuesCleanUp(bool8 var0) gBattleMons[i].status2 &= ~STATUS2_SUBSTITUTE; if (!(gStatuses3[i] & STATUS3_COMMANDER)) - gBattleStruct->commandingDondozo &= ~(1u << i); + gBattleStruct->battlerState[i].commandingDondozo = FALSE; gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF; + gBattleStruct->battlerState[i].usedEjectItem = FALSE; } gSideStatuses[B_SIDE_PLAYER] &= ~(SIDE_STATUS_QUICK_GUARD | SIDE_STATUS_WIDE_GUARD | SIDE_STATUS_CRAFTY_SHIELD | SIDE_STATUS_MAT_BLOCK); @@ -5182,11 +5198,8 @@ static void TurnValuesCleanUp(bool8 var0) gSideTimers[B_SIDE_PLAYER].followmeTimer = 0; gSideTimers[B_SIDE_OPPONENT].followmeTimer = 0; - gBattleStruct->usedEjectItem = 0; - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; gBattleStruct->pledgeMove = FALSE; // combined pledge move may not have been used due to a canceller + ClearPursuitValues(); ClearDamageCalcResults(); } @@ -5250,14 +5263,14 @@ static bool32 TryDoMoveEffectsBeforeMoves(void) SortBattlersBySpeed(battlers, FALSE); for (i = 0; i < gBattlersCount; i++) { - if (!(gBattleStruct->focusPunchBattlers & (1u << battlers[i])) + if (!gBattleStruct->battlerState[battlers[i]].focusPunchBattlers && !(gBattleMons[battlers[i]].status1 & STATUS1_SLEEP) && !(gDisableStructs[battlers[i]].truantCounter) && !(gProtectStructs[battlers[i]].noValidMoves)) { - gBattleStruct->focusPunchBattlers |= 1u << battlers[i]; + gBattleStruct->battlerState[battlers[i]].focusPunchBattlers = TRUE; gBattlerAttacker = battlers[i]; - switch (gMovesInfo[gChosenMoveByBattler[gBattlerAttacker]].effect) + switch (GetMoveEffect(gChosenMoveByBattler[gBattlerAttacker])) { case EFFECT_FOCUS_PUNCH: BattleScriptExecute(BattleScript_FocusPunchSetUp); @@ -5306,7 +5319,7 @@ static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2) // Battler 1 // Quick Draw - if (ability1 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler1]) && gBattleStruct->quickDrawRandom[battler1]) + if (ability1 == ABILITY_QUICK_DRAW && !IsBattleMoveStatus(gChosenMoveByBattler[battler1]) && gBattleStruct->quickDrawRandom[battler1]) gProtectStructs[battler1].quickDraw = TRUE; // Quick Claw and Custap Berry if (!gProtectStructs[battler1].quickDraw @@ -5316,7 +5329,7 @@ static void TryChangingTurnOrderEffects(u32 battler1, u32 battler2) // Battler 2 // Quick Draw - if (ability2 == ABILITY_QUICK_DRAW && !IS_MOVE_STATUS(gChosenMoveByBattler[battler2]) && gBattleStruct->quickDrawRandom[battler2]) + if (ability2 == ABILITY_QUICK_DRAW && !IsBattleMoveStatus(gChosenMoveByBattler[battler2]) && gBattleStruct->quickDrawRandom[battler2]) gProtectStructs[battler2].quickDraw = TRUE; // Quick Claw and Custap Berry if (!gProtectStructs[battler2].quickDraw @@ -5376,9 +5389,9 @@ static void CheckChangingTurnOrderEffects(void) gCurrentActionFuncId = gActionsByTurnOrder[0]; gBattleStruct->dynamicMoveType = 0; gBattleStruct->effectsBeforeUsingMoveDone = FALSE; - gBattleStruct->focusPunchBattlers = 0; for (i = 0; i < MAX_BATTLERS_COUNT; i++) { + gBattleStruct->battlerState[i].focusPunchBattlers = FALSE; gBattleStruct->ateBoost[i] = FALSE; gSpecialStatuses[i].gemBoost = FALSE; } @@ -5398,7 +5411,7 @@ static void RunTurnActionsFunctions(void) // Mega Evolve / Focus Punch-like moves after switching, items, running, but before using a move. if (gCurrentActionFuncId == B_ACTION_USE_MOVE && !gBattleStruct->effectsBeforeUsingMoveDone) { - if (!gBattleStruct->pursuitTarget) + if (!IsPursuitTargetSet()) { if (TryDoGimmicksBeforeMoves()) return; @@ -5672,6 +5685,12 @@ static void FreeResetData_ReturnToOvOrDoEvolutions(void) { gIsFishingEncounter = FALSE; gIsSurfingEncounter = FALSE; + if (gDexNavBattle && (gBattleOutcome == B_OUTCOME_WON || gBattleOutcome == B_OUTCOME_CAUGHT)) + IncrementDexNavChain(); + else + gSaveBlock3Ptr->dexNavChain = 0; + + gDexNavBattle = FALSE; ResetSpriteData(); if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK @@ -5809,7 +5828,7 @@ bool32 TrySetAteType(u32 move, u32 battlerAtk, u32 attackerAbility) { u32 ateType; - switch (gMovesInfo[move].effect) + switch (GetMoveEffect(move)) { case EFFECT_TERA_BLAST: if (GetActiveGimmick(battlerAtk) == GIMMICK_TERA) @@ -5861,8 +5880,8 @@ bool32 TrySetAteType(u32 move, u32 battlerAtk, u32 attackerAbility) // NULL can be passed to ateBoost to avoid applying ate-ability boosts when opening the summary screen in-battle. u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost) { - u32 moveType = gMovesInfo[move].type; - u32 moveEffect = gMovesInfo[move].effect; + u32 moveType = GetMoveType(move); + u32 moveEffect = GetMoveEffect(move); u32 species, heldItem, holdEffect, ability, type1, type2, type3; if (move == MOVE_STRUGGLE) @@ -5948,16 +5967,19 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost) | ((GetMonData(mon, MON_DATA_SPDEF_IV) & 1) << 5); } - // Subtract 6 instead of 1 below because 5 types are excluded (TYPE_NONE, TYPE_NORMAL, TYPE_MYSTERY, TYPE_FAIRY and TYPE_STELLAR) - // The final + 2 skips past TYPE_NONE and Normal. - moveType = ((NUMBER_OF_MON_TYPES - 6) * typeBits) / 63 + 2; - if (moveType >= TYPE_MYSTERY) - moveType++; - return ((moveType | F_DYNAMIC_TYPE_IGNORE_PHYSICALITY) & 0x3F); + u32 hpTypes[NUMBER_OF_MON_TYPES] = {0}; + u32 i, hpTypeCount = 0; + for (i = 0; i < NUMBER_OF_MON_TYPES; i++) + { + if (gTypesInfo[i].isHiddenPowerType) + hpTypes[hpTypeCount++] = i; + } + moveType = ((hpTypeCount - 1) * typeBits) / 63; + return ((hpTypes[moveType] | F_DYNAMIC_TYPE_IGNORE_PHYSICALITY) & 0x3F); } break; case EFFECT_CHANGE_TYPE_ON_ITEM: - if (holdEffect == gMovesInfo[move].argument.holdEffect) + if (holdEffect == GetMoveEffectArg_HoldEffect(move)) return ItemId_GetSecondaryId(heldItem); break; case EFFECT_REVELATION_DANCE: @@ -5966,11 +5988,11 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost) u32 teraType; if (GetActiveGimmick(battler) == GIMMICK_TERA && ((teraType = GetMonData(mon, MON_DATA_TERA_TYPE)) != TYPE_STELLAR)) return teraType; - else if (type1 != TYPE_MYSTERY && !(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST && type1 == TYPE_FLYING)) + else if (type1 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type1 == TYPE_FLYING)) return type1; - else if (type2 != TYPE_MYSTERY && !(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST && type2 == TYPE_FLYING)) + else if (type2 != TYPE_MYSTERY && !(gDisableStructs[battler].roostActive && type2 == TYPE_FLYING)) return type2; - else if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST) + else if (gDisableStructs[battler].roostActive) return (B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY); else if (type3 != TYPE_MYSTERY) return type3; @@ -6065,7 +6087,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost) *ateBoost = TRUE; return TYPE_NORMAL; } - else if (gMovesInfo[move].soundMove && ability == ABILITY_LIQUID_VOICE) + else if (IsSoundMove(move) && ability == ABILITY_LIQUID_VOICE) { return TYPE_WATER; } @@ -6094,13 +6116,13 @@ void SetTypeBeforeUsingMove(u32 move, u32 battler) if (moveType != TYPE_NONE) gBattleStruct->dynamicMoveType = moveType | F_DYNAMIC_TYPE_SET; - moveType = GetMoveType(move); + moveType = GetBattleMoveType(move); if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && moveType == TYPE_NORMAL) || gStatuses4[battler] & STATUS4_ELECTRIFIED) gBattleStruct->dynamicMoveType = TYPE_ELECTRIC | F_DYNAMIC_TYPE_SET; // Check if a gem should activate. - if (holdEffect == HOLD_EFFECT_GEMS && GetMoveType(move) == ItemId_GetSecondaryId(heldItem)) + if (holdEffect == HOLD_EFFECT_GEMS && GetBattleMoveType(move) == ItemId_GetSecondaryId(heldItem)) { gSpecialStatuses[battler].gemParam = GetBattlerHoldEffectParam(battler); gSpecialStatuses[battler].gemBoost = TRUE; @@ -6114,6 +6136,8 @@ void ScriptSetTotemBoost(struct ScriptContext *ctx) u32 stat; u32 i; + Script_RequestEffects(SCREFF_V1); + for (i = 0; i < (NUM_BATTLE_STATS - 1); i++) { stat = VarGet(ScriptReadHalfword(ctx)); diff --git a/src/battle_message.c b/src/battle_message.c index 662473eb5d0d..a977bcd83c72 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -915,15 +915,17 @@ const u16 gMentalHerbCureStringIds[] = const u16 gStartingStatusStringIds[B_MSG_STARTING_STATUS_COUNT] = { - [B_MSG_TERRAIN_SET_MISTY] = STRINGID_TERRAINBECOMESMISTY, - [B_MSG_TERRAIN_SET_ELECTRIC] = STRINGID_TERRAINBECOMESELECTRIC, - [B_MSG_TERRAIN_SET_PSYCHIC] = STRINGID_TERRAINBECOMESPSYCHIC, - [B_MSG_TERRAIN_SET_GRASSY] = STRINGID_TERRAINBECOMESGRASSY, - [B_MSG_SET_TRICK_ROOM] = STRINGID_DIMENSIONSWERETWISTED, - [B_MSG_SET_MAGIC_ROOM] = STRINGID_BIZARREARENACREATED, - [B_MSG_SET_WONDER_ROOM] = STRINGID_BIZARREAREACREATED, - [B_MSG_SET_TAILWIND_PLAYER] = STRINGID_TAILWINDBLEW, - [B_MSG_SET_TAILWIND_OPPONENT] = STRINGID_TAILWINDBLEW, + [B_MSG_TERRAIN_SET_MISTY] = STRINGID_TERRAINBECOMESMISTY, + [B_MSG_TERRAIN_SET_ELECTRIC] = STRINGID_TERRAINBECOMESELECTRIC, + [B_MSG_TERRAIN_SET_PSYCHIC] = STRINGID_TERRAINBECOMESPSYCHIC, + [B_MSG_TERRAIN_SET_GRASSY] = STRINGID_TERRAINBECOMESGRASSY, + [B_MSG_SET_TRICK_ROOM] = STRINGID_DIMENSIONSWERETWISTED, + [B_MSG_SET_MAGIC_ROOM] = STRINGID_BIZARREARENACREATED, + [B_MSG_SET_WONDER_ROOM] = STRINGID_BIZARREAREACREATED, + [B_MSG_SET_TAILWIND] = STRINGID_TAILWINDBLEW, + [B_MSG_SET_RAINBOW] = STRINGID_ARAINBOWAPPEAREDONSIDE, + [B_MSG_SET_SEA_OF_FIRE] = STRINGID_SEAOFFIREENVELOPEDSIDE, + [B_MSG_SET_SWAMP] = STRINGID_SWAMPENVELOPEDSIDE, }; const u16 gTerrainStringIds[B_MSG_TERRAIN_COUNT] = @@ -1013,20 +1015,25 @@ const u16 gMoveWeatherChangeStringIds[] = const u16 gWeatherEndsStringIds[B_MSG_WEATHER_END_COUNT] = { - [B_MSG_WEATHER_END_RAIN] = STRINGID_RAINSTOPPED, - [B_MSG_WEATHER_END_SANDSTORM] = STRINGID_SANDSTORMSUBSIDED, - [B_MSG_WEATHER_END_SUN] = STRINGID_SUNLIGHTFADED, - [B_MSG_WEATHER_END_HAIL] = STRINGID_HAILSTOPPED, + [B_MSG_WEATHER_END_RAIN] = STRINGID_RAINSTOPPED, + [B_MSG_WEATHER_END_SUN] = STRINGID_SUNLIGHTFADED, + [B_MSG_WEATHER_END_SANDSTORM] = STRINGID_SANDSTORMSUBSIDED, + [B_MSG_WEATHER_END_HAIL] = STRINGID_HAILSTOPPED, + [B_MSG_WEATHER_END_SNOW] = STRINGID_SNOWSTOPPED, + [B_MSG_WEATHER_END_FOG] = STRINGID_FOGLIFTED, [B_MSG_WEATHER_END_STRONG_WINDS] = STRINGID_STRONGWINDSDISSIPATED, - [B_MSG_WEATHER_END_SNOW] = STRINGID_SNOWSTOPPED, - [B_MSG_WEATHER_END_FOG] = STRINGID_FOGLIFTED, }; -const u16 gSandStormHailSnowContinuesStringIds[] = +const u16 gWeatherTurnStringIds[] = { - [B_MSG_SANDSTORM] = STRINGID_SANDSTORMRAGES, - [B_MSG_HAIL] = STRINGID_HAILCONTINUES, - [B_MSG_SNOW] = STRINGID_SNOWCONTINUES, + [B_MSG_WEATHER_TURN_RAIN] = STRINGID_RAINCONTINUES, + [B_MSG_WEATHER_TURN_DOWNPOUR] = STRINGID_DOWNPOURCONTINUES, + [B_MSG_WEATHER_TURN_SUN] = STRINGID_SUNLIGHTSTRONG, + [B_MSG_WEATHER_TURN_SANDSTORM] = STRINGID_SANDSTORMRAGES, + [B_MSG_WEATHER_TURN_HAIL] = STRINGID_HAILCONTINUES, + [B_MSG_WEATHER_TURN_SNOW] = STRINGID_SNOWCONTINUES, + [B_MSG_WEATHER_TURN_FOG] = STRINGID_FOGISDEEP, + [B_MSG_WEATHER_TURN_STRONG_WINDS] = STRINGID_MYSTERIOUSAIRCURRENTBLOWSON, }; const u16 gSandStormHailDmgStringIds[] = @@ -1035,20 +1042,6 @@ const u16 gSandStormHailDmgStringIds[] = [B_MSG_HAIL] = STRINGID_PKMNPELTEDBYHAIL }; -const u16 gSandStormHailSnowEndStringIds[] = -{ - [B_MSG_SANDSTORM] = STRINGID_SANDSTORMSUBSIDED, - [B_MSG_HAIL] = STRINGID_HAILSTOPPED, - [B_MSG_SNOW] = STRINGID_SNOWSTOPPED, -}; - -const u16 gRainContinuesStringIds[] = -{ - [B_MSG_RAIN_CONTINUES] = STRINGID_RAINCONTINUES, - [B_MSG_DOWNPOUR_CONTINUES] = STRINGID_DOWNPOURCONTINUES, - [B_MSG_RAIN_STOPPED] = STRINGID_RAINSTOPPED -}; - const u16 gProtectLikeUsedStringIds[] = { [B_MSG_PROTECTED_ITSELF] = STRINGID_PKMNPROTECTEDITSELF2, @@ -1406,8 +1399,8 @@ const u8 gText_PkmnIsEvolving[] = _("What?\n{STR_VAR_1} is evolving!"); const u8 gText_CongratsPkmnEvolved[] = _("Congratulations! Your {STR_VAR_1}\nevolved into {STR_VAR_2}!{WAIT_SE}\p"); const u8 gText_PkmnStoppedEvolving[] = _("Huh? {STR_VAR_1}\nstopped evolving!\p"); const u8 gText_EllipsisQuestionMark[] = _("……?\p"); -const u8 gText_WhatWillPkmnDo[] = _("What will {B_BUFF1} do?"); -const u8 gText_WhatWillPkmnDo2[] = _("What will {B_PLAYER_NAME} do?"); +const u8 gText_WhatWillPkmnDo[] = _("What will\n{B_BUFF1} do?"); +const u8 gText_WhatWillPkmnDo2[] = _("What will\n{B_PLAYER_NAME} do?"); const u8 gText_WhatWillWallyDo[] = _("What will\nWALLY do?"); const u8 gText_LinkStandby[] = _("{PAUSE 16}Link standby…"); const u8 gText_BattleMenu[] = _("Battle{CLEAR_TO 56}Bag\nPokémon{CLEAR_TO 56}Run"); @@ -3567,8 +3560,10 @@ struct TrainerSlide const u8 *msgDynamax; }; -static const struct TrainerSlide sTrainerSlides[] = +static const struct TrainerSlide sTrainerSlides[DIFFICULTY_COUNT][TRAINERS_COUNT] = { + [DIFFICULTY_NORMAL] = + { /* Put any trainer slide-in messages inside this array. Example: { @@ -3587,7 +3582,14 @@ static const struct TrainerSlide sTrainerSlides[] = .msgBeforeFirstTurn = sText_GravityIntensified, .msgDynamax = sText_TargetWokeUp, }, + }, + [DIFFICULTY_EASY] = + { + }, + [DIFFICULTY_HARD] = + { */ + }, }; static u32 GetEnemyMonCount(u32 firstId, u32 lastId, bool32 onlyAlive) @@ -3664,118 +3666,120 @@ u32 ShouldDoTrainerSlide(u32 battler, u32 which) trainerId = gTrainerBattleOpponent_A; } + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(trainerId); + for (i = 0; i < ARRAY_COUNT(sTrainerSlides); i++) { - if (trainerId == sTrainerSlides[i].trainerId - && (((gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && sTrainerSlides[i].isFrontierTrainer) - || (!(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && !sTrainerSlides[i].isFrontierTrainer))) + if (trainerId == sTrainerSlides[difficulty]->trainerId + && (((gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && sTrainerSlides[difficulty]->isFrontierTrainer) + || (!(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && !sTrainerSlides[difficulty]->isFrontierTrainer))) { gBattleScripting.battler = battler; switch (which) { case TRAINER_SLIDE_LAST_SWITCHIN: - if (sTrainerSlides[i].msgLastSwitchIn != NULL && !CanBattlerSwitch(battler)) + if (sTrainerSlides[difficulty]->msgLastSwitchIn != NULL && !CanBattlerSwitch(battler)) { - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgLastSwitchIn; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgLastSwitchIn; return retValue; } break; case TRAINER_SLIDE_LAST_LOW_HP: - if (sTrainerSlides[i].msgLastLowHp != NULL + if (sTrainerSlides[difficulty]->msgLastLowHp != NULL && GetEnemyMonCount(firstId, lastId, TRUE) == 1 && BattlerHPPercentage(battler, LESS_THAN_OR_EQUAL, 4) && !gBattleStruct->trainerSlideLowHpMsgDone) { gBattleStruct->trainerSlideLowHpMsgDone = TRUE; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgLastLowHp; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgLastLowHp; return retValue; } break; case TRAINER_SLIDE_FIRST_DOWN: - if (sTrainerSlides[i].msgFirstDown != NULL && GetEnemyMonCount(firstId, lastId, TRUE) == GetEnemyMonCount(firstId, lastId, FALSE) - 1) + if (sTrainerSlides[difficulty]->msgFirstDown != NULL && GetEnemyMonCount(firstId, lastId, TRUE) == GetEnemyMonCount(firstId, lastId, FALSE) - 1) { - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstDown; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgFirstDown; return retValue; } break; case TRAINER_SLIDE_LAST_HALF_HP: - if (sTrainerSlides[i].msgLastHalfHp != NULL + if (sTrainerSlides[difficulty]->msgLastHalfHp != NULL && GetEnemyMonCount(firstId, lastId, TRUE) == GetEnemyMonCount(firstId, lastId, FALSE) - 1 && BattlerHPPercentage(battler, LESS_THAN_OR_EQUAL, 2) && BattlerHPPercentage(battler, GREATER_THAN, 4) && !gBattleStruct->trainerSlideHalfHpMsgDone) { gBattleStruct->trainerSlideHalfHpMsgDone = TRUE; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgLastHalfHp; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgLastHalfHp; return TRUE; } break; case TRAINER_SLIDE_FIRST_CRITICAL_HIT: - if (sTrainerSlides[i].msgFirstCriticalHit != NULL && gBattleStruct->trainerSlideFirstCriticalHitMsgState == 1) + if (sTrainerSlides[difficulty]->msgFirstCriticalHit != NULL && gBattleStruct->trainerSlideFirstCriticalHitMsgState == 1) { gBattleStruct->trainerSlideFirstCriticalHitMsgState = 2; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstCriticalHit; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgFirstCriticalHit; return TRUE; } break; case TRAINER_SLIDE_FIRST_SUPER_EFFECTIVE_HIT: - if (sTrainerSlides[i].msgFirstSuperEffectiveHit != NULL + if (sTrainerSlides[difficulty]->msgFirstSuperEffectiveHit != NULL && gBattleStruct->trainerSlideFirstSuperEffectiveHitMsgState == 1 && gBattleMons[battler].hp) { gBattleStruct->trainerSlideFirstSuperEffectiveHitMsgState = 2; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstSuperEffectiveHit; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgFirstSuperEffectiveHit; return TRUE; } break; case TRAINER_SLIDE_FIRST_STAB_MOVE: - if (sTrainerSlides[i].msgFirstSTABMove != NULL + if (sTrainerSlides[difficulty]->msgFirstSTABMove != NULL && gBattleStruct->trainerSlideFirstSTABMoveMsgState == 1 && GetEnemyMonCount(firstId, lastId, TRUE) == GetEnemyMonCount(firstId, lastId, FALSE)) { gBattleStruct->trainerSlideFirstSTABMoveMsgState = 2; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstSTABMove; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgFirstSTABMove; return TRUE; } break; case TRAINER_SLIDE_PLAYER_MON_UNAFFECTED: - if (sTrainerSlides[i].msgPlayerMonUnaffected != NULL + if (sTrainerSlides[difficulty]->msgPlayerMonUnaffected != NULL && gBattleStruct->trainerSlidePlayerMonUnaffectedMsgState == 1 && GetEnemyMonCount(firstId, lastId, TRUE) == GetEnemyMonCount(firstId, lastId, FALSE)) { gBattleStruct->trainerSlidePlayerMonUnaffectedMsgState = 2; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgPlayerMonUnaffected; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgPlayerMonUnaffected; return TRUE; } break; case TRAINER_SLIDE_MEGA_EVOLUTION: - if (sTrainerSlides[i].msgMegaEvolution != NULL && !gBattleStruct->trainerSlideMegaEvolutionMsgDone) + if (sTrainerSlides[difficulty]->msgMegaEvolution != NULL && !gBattleStruct->trainerSlideMegaEvolutionMsgDone) { gBattleStruct->trainerSlideMegaEvolutionMsgDone = TRUE; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgMegaEvolution; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgMegaEvolution; return TRUE; } break; case TRAINER_SLIDE_Z_MOVE: - if (sTrainerSlides[i].msgZMove != NULL && !gBattleStruct->trainerSlideZMoveMsgDone) + if (sTrainerSlides[difficulty]->msgZMove != NULL && !gBattleStruct->trainerSlideZMoveMsgDone) { gBattleStruct->trainerSlideZMoveMsgDone = TRUE; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgZMove; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgZMove; return TRUE; } break; case TRAINER_SLIDE_BEFORE_FIRST_TURN: - if (sTrainerSlides[i].msgBeforeFirstTurn != NULL && !gBattleStruct->trainerSlideBeforeFirstTurnMsgDone) + if (sTrainerSlides[difficulty]->msgBeforeFirstTurn != NULL && !gBattleStruct->trainerSlideBeforeFirstTurnMsgDone) { gBattleStruct->trainerSlideBeforeFirstTurnMsgDone = TRUE; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgBeforeFirstTurn; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgBeforeFirstTurn; return TRUE; } break; case TRAINER_SLIDE_DYNAMAX: - if (sTrainerSlides[i].msgDynamax != NULL && !gBattleStruct->trainerSlideDynamaxMsgDone) + if (sTrainerSlides[difficulty]->msgDynamax != NULL && !gBattleStruct->trainerSlideDynamaxMsgDone) { gBattleStruct->trainerSlideDynamaxMsgDone = TRUE; - gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgDynamax; + gBattleStruct->trainerSlideMsg = sTrainerSlides[difficulty]->msgDynamax; return TRUE; } break; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 13c24466f54b..b4d668a0df36 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -47,6 +47,7 @@ #include "pokenav.h" #include "menu_specialized.h" #include "data.h" +#include "move.h" #include "constants/abilities.h" #include "constants/battle_anim.h" #include "constants/battle_move_effects.h" @@ -1103,7 +1104,7 @@ static const u8 sTerrainToType[BATTLE_TERRAIN_COUNT] = static bool32 NoTargetPresent(u8 battler, u32 move) { if (!IsBattlerAlive(gBattlerTarget)) - gBattlerTarget = GetMoveTarget(move, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(move, NO_TARGET_OVERRIDE); switch (GetBattlerMoveTargetType(battler, move)) { @@ -1146,7 +1147,7 @@ bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef) if (!gSpecialStatuses[battlerDef].distortedTypeMatchups && gBattleMons[battlerDef].species == SPECIES_TERAPAGOS_TERASTAL && gBattleMons[battlerDef].hp == gBattleMons[battlerDef].maxHP - && !IS_MOVE_STATUS(move) + && !IsBattleMoveStatus(move) && MoveResultHasEffect(battlerDef) && GetBattlerAbility(battlerDef) == ABILITY_TERA_SHELL) return TRUE; @@ -1156,7 +1157,7 @@ bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef) bool32 IsMoveNotAllowedInSkyBattles(u32 move) { - return ((gBattleStruct->isSkyBattle) && (gMovesInfo[gCurrentMove].skyBattleBanned)); + return (gBattleStruct->isSkyBattle && IsMoveSkyBattleBanned(gCurrentMove)); } static void Cmd_attackcanceler(void) @@ -1165,9 +1166,9 @@ static void Cmd_attackcanceler(void) s32 i; - if (gBattleStruct->usedEjectItem & (1u << gBattlerAttacker)) + if (gBattleStruct->battlerState[gBattlerAttacker].usedEjectItem) { - gBattleStruct->usedEjectItem = 0; + gBattleStruct->battlerState[gBattlerAttacker].usedEjectItem = FALSE; gCurrentActionFuncId = B_ACTION_TRY_FINISH; return; } @@ -1178,7 +1179,9 @@ static void Cmd_attackcanceler(void) return; } - if (!IsBattlerAlive(gBattlerAttacker) && gMovesInfo[gCurrentMove].effect != EFFECT_EXPLOSION && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) + u32 effect = GetMoveEffect(gCurrentMove); + + if (!IsBattlerAlive(gBattlerAttacker) && effect != EFFECT_EXPLOSION && !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) { gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; gBattlescriptCurrInstr = BattleScript_MoveEnd; @@ -1214,21 +1217,22 @@ static void Cmd_attackcanceler(void) // Check if no available target present on the field or if Sky Battles ban the move if ((NoTargetPresent(gBattlerAttacker, gCurrentMove) - && (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) + && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) || (IsMoveNotAllowedInSkyBattles(gCurrentMove))) { - if (gMovesInfo[gCurrentMove].effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. + if (effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling. gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem; else gBattlescriptCurrInstr = BattleScript_FailedFromAtkString; - if (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) + if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) CancelMultiTurnMoves(gBattlerAttacker); return; } + u32 isBounceable = MoveCanBeBouncedBack(gCurrentMove); if (gProtectStructs[gBattlerTarget].bounceMove - && gMovesInfo[gCurrentMove].magicCoatAffected + && isBounceable && !gBattleStruct->bouncedMoveIsUsed) { gBattleStruct->bouncedMoveIsUsed = TRUE; @@ -1249,7 +1253,7 @@ static void Cmd_attackcanceler(void) } return; } - else if (gMovesInfo[gCurrentMove].magicCoatAffected && !gBattleStruct->bouncedMoveIsUsed) + else if (isBounceable && !gBattleStruct->bouncedMoveIsUsed) { u32 battler = gBattlerTarget; @@ -1259,7 +1263,7 @@ static void Cmd_attackcanceler(void) gBattleStruct->bouncedMoveIsUsed = TRUE; } else if (IsDoubleBattle() - && gMovesInfo[gCurrentMove].target == MOVE_TARGET_OPPONENTS_FIELD + && GetBattlerMoveTargetType(battler, gCurrentMove) == MOVE_TARGET_OPPONENTS_FIELD && GetBattlerAbility(BATTLE_PARTNER(gBattlerTarget)) == ABILITY_MAGIC_BOUNCE) { gBattlerTarget = battler = BATTLE_PARTNER(gBattlerTarget); @@ -1287,7 +1291,7 @@ static void Cmd_attackcanceler(void) for (i = 0; i < gBattlersCount; i++) { - if ((gProtectStructs[gBattlerByTurnOrder[i]].stealMove) && gMovesInfo[gCurrentMove].snatchAffected) + if ((gProtectStructs[gBattlerByTurnOrder[i]].stealMove) && MoveCanBeSnatched(gCurrentMove)) { gProtectStructs[gBattlerByTurnOrder[i]].stealMove = FALSE; gBattleStruct->snatchedMoveIsUsed = TRUE; @@ -1316,9 +1320,9 @@ static void Cmd_attackcanceler(void) } else if (IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove) && (gCurrentMove != MOVE_CURSE || IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) - && (!gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) - && gMovesInfo[gCurrentMove].effect != EFFECT_SUCKER_PUNCH - && gMovesInfo[gCurrentMove].effect != EFFECT_UPPER_HAND) + && (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) + && effect != EFFECT_SUCKER_PUNCH + && effect != EFFECT_UPPER_HAND) { if (IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE; @@ -1398,9 +1402,10 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) { u32 effect = FALSE; u32 ability = ABILITY_NONE; + u32 moveEffect = GetMoveEffect(move); if ((gStatuses3[battler] & STATUS3_ALWAYS_HITS && gDisableStructs[battler].battlerWithSureHit == gBattlerAttacker) - || (B_TOXIC_NEVER_MISS >= GEN_6 && gMovesInfo[move].effect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON)) + || (B_TOXIC_NEVER_MISS >= GEN_6 && moveEffect == EFFECT_TOXIC && IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_POISON)) || gStatuses4[battler] & STATUS4_GLAIVE_RUSH) { effect = TRUE; @@ -1408,14 +1413,14 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) // If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits. else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD && !(gStatuses3[battler] & STATUS3_COMMANDER) - && (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == 0xFF)) + && (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == 0xFF)) { effect = TRUE; ability = ABILITY_NO_GUARD; } // If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits. else if (GetBattlerAbility(battler) == ABILITY_NO_GUARD - && (gMovesInfo[move].effect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == 0xFF)) + && (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == 0xFF)) { effect = TRUE; ability = ABILITY_NO_GUARD; @@ -1423,11 +1428,11 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) // If the target is under the effects of Telekinesis, and the move isn't a OH-KO move, move hits. else if (gStatuses3[battler] & STATUS3_TELEKINESIS && !(gStatuses3[battler] & STATUS3_SEMI_INVULNERABLE) - && gMovesInfo[move].effect != EFFECT_OHKO) + && moveEffect != EFFECT_OHKO) { effect = TRUE; } - else if (gBattleStruct->pursuitTarget & (1u << battler)) + else if (gBattleStruct->battlerState[battler].pursuitTarget) { effect = TRUE; } @@ -1437,9 +1442,9 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) } else if ((gStatuses3[battler] & STATUS3_COMMANDER) || (gStatuses3[battler] & STATUS3_PHANTOM_FORCE) - || ((gStatuses3[battler] & STATUS3_ON_AIR) && !(gMovesInfo[move].damagesAirborne || gMovesInfo[move].damagesAirborneDoubleDamage)) - || ((gStatuses3[battler] & STATUS3_UNDERGROUND) && !gMovesInfo[move].damagesUnderground) - || ((gStatuses3[battler] & STATUS3_UNDERWATER) && !gMovesInfo[move].damagesUnderwater)) + || ((gStatuses3[battler] & STATUS3_ON_AIR) && !(MoveDamagesAirborne(move) || MoveDamagesAirborneDoubleDamage(move))) + || ((gStatuses3[battler] & STATUS3_UNDERGROUND) && !MoveDamagesUnderground(move)) + || ((gStatuses3[battler] & STATUS3_UNDERWATER) && !MoveDamagesUnderWater(move))) { gBattleStruct->moveResultFlags[battler] |= MOVE_RESULT_MISSED; effect = TRUE; @@ -1447,10 +1452,10 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) if (WEATHER_HAS_EFFECT) { - if ((gMovesInfo[move].effect == EFFECT_THUNDER || gMovesInfo[move].effect == EFFECT_RAIN_ALWAYS_HIT) + if ((moveEffect == EFFECT_THUNDER || moveEffect == EFFECT_RAIN_ALWAYS_HIT) && IsBattlerWeatherAffected(battler, B_WEATHER_RAIN)) effect = TRUE; - else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && gMovesInfo[move].effect == EFFECT_BLIZZARD) + else if ((gBattleWeather & (B_WEATHER_HAIL | B_WEATHER_SNOW)) && moveEffect == EFFECT_BLIZZARD) effect = TRUE; if (effect) @@ -1459,11 +1464,11 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler) if (B_MINIMIZE_DMG_ACC >= GEN_6 && (gStatuses3[battler] & STATUS3_MINIMIZED) - && gMovesInfo[move].minimizeDoubleDamage) + && MoveIncreasesPowerToMinimizedTargets(move)) { effect = TRUE; } - else if (gMovesInfo[move].accuracy == 0) + else if (GetMoveAccuracy(move) == 0) { effect = TRUE; } @@ -1489,7 +1494,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (atkAbility == ABILITY_UNAWARE || atkAbility == ABILITY_KEEN_EYE || atkAbility == ABILITY_MINDS_EYE || (B_ILLUMINATE_EFFECT >= GEN_9 && atkAbility == ABILITY_ILLUMINATE)) evasionStage = DEFAULT_STAT_STAGE; - if (gMovesInfo[move].ignoresTargetDefenseEvasionStages) + if (MoveIgnoresDefenseEvasionStages(move)) evasionStage = DEFAULT_STAT_STAGE; if (defAbility == ABILITY_UNAWARE) accStage = DEFAULT_STAT_STAGE; @@ -1504,12 +1509,12 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u if (buff > MAX_STAT_STAGE) buff = MAX_STAT_STAGE; - moveAcc = gMovesInfo[move].accuracy; + moveAcc = GetMoveAccuracy(move); // Check Thunder and Hurricane on sunny weather. - if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && gMovesInfo[move].effect == EFFECT_THUNDER) + if (IsBattlerWeatherAffected(battlerDef, B_WEATHER_SUN) && GetMoveEffect(move) == EFFECT_THUNDER) moveAcc = 50; // Check Wonder Skin. - if (defAbility == ABILITY_WONDER_SKIN && IS_MOVE_STATUS(move) && moveAcc > 50) + if (defAbility == ABILITY_WONDER_SKIN && IsBattleMoveStatus(move) && moveAcc > 50) moveAcc = 50; calc = gAccuracyStageRatios[buff].dividend * moveAcc; @@ -1525,7 +1530,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u calc = (calc * 110) / 100; // 1.1 victory star boost break; case ABILITY_HUSTLE: - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) calc = (calc * 80) / 100; // 1.2 hustle loss break; } @@ -1576,7 +1581,7 @@ u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u break; } - if (gBattleStruct->usedMicleBerry & 1u << battlerAtk) + if (gBattleStruct->battlerState[battlerAtk].usedMicleBerry) { if (atkAbility == ABILITY_RIPEN) calc = (calc * 140) / 100; // ripen gives 40% acc boost @@ -1604,6 +1609,8 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u if (move == ACC_CURR_MOVE) move = gCurrentMove; + u32 effect = GetMoveEffect(move); + abilityAtk = GetBattlerAbility(gBattlerAttacker); holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); @@ -1626,16 +1633,16 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u else if (gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_2ND_HIT || (gSpecialStatuses[gBattlerAttacker].multiHitOn && (abilityAtk == ABILITY_SKILL_LINK || holdEffectAtk == HOLD_EFFECT_LOADED_DICE - || !(gMovesInfo[move].effect == EFFECT_TRIPLE_KICK || gMovesInfo[move].effect == EFFECT_POPULATION_BOMB)))) + || !(effect == EFFECT_TRIPLE_KICK || effect == EFFECT_POPULATION_BOMB)))) { // No acc checks for second hit of Parental Bond or multi hit moves, except Triple Kick/Triple Axel/Population Bomb gBattlescriptCurrInstr = nextInstr; } else { - u32 moveType = GetMoveType(move); + u32 moveType = GetBattleMoveType(move); u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); - bool32 calcSpreadMove = IsSpreadMove(moveTarget) && !IS_MOVE_STATUS(move); + bool32 calcSpreadMove = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(move); for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { @@ -1666,7 +1673,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u if (holdEffectAtk == HOLD_EFFECT_BLUNDER_POLICY) gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks - if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS + if (effect == EFFECT_DRAGON_DARTS && !recalcDragonDarts // So we don't jump back and forth between targets && CanTargetPartner(gBattlerAttacker, battlerDef) && !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(battlerDef))) @@ -1677,7 +1684,7 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u return; } - if (gMovesInfo[move].power) + if (GetMovePower(move) != 0) CalcTypeEffectivenessMultiplier(move, moveType, gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); } } @@ -1734,7 +1741,7 @@ static void Cmd_ppreduce(void) if (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY || moveTarget == MOVE_TARGET_ALL_BATTLERS - || gMovesInfo[gCurrentMove].forcePressure) + || MoveForcesPressure(gCurrentMove)) { for (i = 0; i < gBattlersCount; i++) { @@ -1835,7 +1842,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec critChance = CRITICAL_HIT_BLOCKED; } else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS - || gMovesInfo[move].alwaysCriticalHit + || MoveAlwaysCrits(move) || (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) { critChance = CRITICAL_HIT_ALWAYS; @@ -1844,7 +1851,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec { critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0) + 1 * ((gBattleMons[battlerAtk].status2 & STATUS2_DRAGON_CHEER) != 0) - + gMovesInfo[move].criticalHitStage + + GetMoveCriticalHitStage(move) + GetHoldEffectCritChanceIncrease(battlerAtk, holdEffectAtk) + 2 * (B_AFFECTION_MECHANICS == TRUE && GetBattlerAffectionHearts(battlerAtk) == AFFECTION_FIVE_HEARTS) + (abilityAtk == ABILITY_SUPER_LUCK) @@ -1869,8 +1876,8 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec return critChance; } -#undef CRIT_BLOCKED -#undef ALWAYS_CRITS +#undef CRITICAL_HIT_BLOCKED +#undef CRITICAL_HIT_ALWAYS s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordAbility) { @@ -1898,7 +1905,7 @@ s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec u32 farfetchdLeekScaler = 8; s32 critChance = 0; - s32 moveCritStage = gMovesInfo[gCurrentMove].criticalHitStage; + s32 moveCritStage = GetMoveCriticalHitStage(gCurrentMove); s32 bonusCritStage = gBattleStruct->bonusCritStages[battlerAtk]; // G-Max Chi Strike u32 abilityAtk = GetBattlerAbility(battlerAtk); u32 abilityDef = GetBattlerAbility(battlerDef); @@ -1942,7 +1949,7 @@ s32 CalcCritChanceStageGen1(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec // Guaranteed crits else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS - || gMovesInfo[move].alwaysCriticalHit == TRUE + || MoveAlwaysCrits(move) || (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)) { critChance = -2; @@ -1965,7 +1972,7 @@ static void Cmd_critcalc(void) u32 partySlot = gBattlerPartyIndexes[gBattlerAttacker]; u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IS_MOVE_STATUS(gCurrentMove); + bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(gCurrentMove); gPotentialItemEffectBattler = gBattlerAttacker; for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) @@ -2019,8 +2026,8 @@ static void Cmd_critcalc(void) static inline void GetShellSideArmCategory(u32 battlerDef) { - if (gMovesInfo[gCurrentMove].effect == EFFECT_SHELL_SIDE_ARM) - gBattleStruct->swapDamageCategory = (gBattleStruct->shellSideArmCategory[gBattlerAttacker][battlerDef] != gMovesInfo[gCurrentMove].category); + if (GetMoveEffect(gCurrentMove) == EFFECT_SHELL_SIDE_ARM) + gBattleStruct->swapDamageCategory = (gBattleStruct->shellSideArmCategory[gBattlerAttacker][battlerDef] != GetMoveCategory(gCurrentMove)); } static void Cmd_damagecalc(void) @@ -2038,7 +2045,7 @@ static void Cmd_damagecalc(void) struct DamageCalculationData damageCalcData; damageCalcData.battlerAtk = gBattlerAttacker; damageCalcData.move = gCurrentMove; - damageCalcData.moveType = GetMoveType(gCurrentMove); + damageCalcData.moveType = GetBattleMoveType(gCurrentMove); damageCalcData.randomFactor = TRUE; damageCalcData.updateFlags = TRUE; @@ -2085,7 +2092,7 @@ static void Cmd_typecalc(void) if (!IsSpreadMove(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove))) // Handled in CANCELLER_MULTI_TARGET_MOVES for Spread Moves { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE); } @@ -2101,7 +2108,8 @@ static void Cmd_adjustdamage(void) u32 rand = Random() % 100; u32 affectionScore = GetBattlerAffectionHearts(gBattlerTarget); u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IS_MOVE_STATUS(gCurrentMove); + u32 moveEffect = GetMoveEffect(gCurrentMove); + bool32 calcSpreadMoveDamage = IsSpreadMove(moveTarget) && !IsBattleMoveStatus(gCurrentMove); for (battlerDef = 0; battlerDef < gBattlersCount; battlerDef++) { @@ -2116,25 +2124,25 @@ static void Cmd_adjustdamage(void) continue; if (DoesSubstituteBlockMove(gBattlerAttacker, battlerDef, gCurrentMove)) - goto END; + continue; if (DoesDisguiseBlockMove(battlerDef, gCurrentMove)) { - gBattleStruct->enduredDamage |= 1u << battlerDef; - goto END; + gSpecialStatuses[battlerDef].enduredDamage = TRUE; + continue; } - if (GetBattlerAbility(battlerDef) == ABILITY_ICE_FACE && IS_MOVE_PHYSICAL(gCurrentMove) && gBattleMons[battlerDef].species == SPECIES_EISCUE) + if (GetBattlerAbility(battlerDef) == ABILITY_ICE_FACE && IsBattleMovePhysical(gCurrentMove) && gBattleMons[battlerDef].species == SPECIES_EISCUE) { // Damage deals typeless 0 HP. gBattleStruct->moveResultFlags[battlerDef] &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_NOT_VERY_EFFECTIVE); gBattleStruct->moveDamage[battlerDef] = 0; RecordAbilityBattle(gBattlerTarget, ABILITY_ICE_FACE); - gBattleResources->flags->flags[battlerDef] |= RESOURCE_FLAG_ICE_FACE; + gDisableStructs[battlerDef].iceFaceActivationPrevention = TRUE; // Form change will be done after attack animation in Cmd_resultmessage. - goto END; + continue; } if (gBattleMons[gBattlerTarget].hp > gBattleStruct->moveDamage[battlerDef]) - goto END; + continue; holdEffect = GetBattlerHoldEffect(battlerDef, TRUE); param = GetBattlerHoldEffectParam(battlerDef); @@ -2164,17 +2172,17 @@ static void Cmd_adjustdamage(void) gSpecialStatuses[battlerDef].affectionEndured = TRUE; } - if (gMovesInfo[gCurrentMove].effect != EFFECT_FALSE_SWIPE + if (moveEffect != EFFECT_FALSE_SWIPE && !gProtectStructs[battlerDef].endured && !gSpecialStatuses[battlerDef].focusBanded && !gSpecialStatuses[battlerDef].focusSashed && (B_AFFECTION_MECHANICS == FALSE || !gSpecialStatuses[battlerDef].affectionEndured) && !gSpecialStatuses[battlerDef].sturdied) - goto END; + continue; // Handle reducing the dmg to 1 hp. gBattleStruct->moveDamage[battlerDef] = gBattleMons[battlerDef].hp - 1; - gBattleStruct->enduredDamage |= 1u << battlerDef; + gSpecialStatuses[battlerDef].enduredDamage = TRUE; if (gProtectStructs[battlerDef].endured) { @@ -2196,10 +2204,6 @@ static void Cmd_adjustdamage(void) { gBattleStruct->moveResultFlags[battlerDef] |= MOVE_RESULT_FOE_ENDURED_AFFECTION; } - - END: - if (!(gBattleStruct->moveResultFlags[battlerDef] & MOVE_RESULT_NO_EFFECT) && gBattleStruct->moveDamage[battlerDef] >= 1) - gSpecialStatuses[gBattlerAttacker].damagedMons |= 1u << battlerDef; } if (calcSpreadMoveDamage) @@ -2210,7 +2214,7 @@ static void Cmd_adjustdamage(void) && MoveResultHasEffect(gBattlerTarget) && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gBattleMons[gBattlerAttacker].item - && gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE + && moveEffect != EFFECT_PLEDGE && gCurrentMove != MOVE_STRUGGLE) { BattleScriptPushCursor(); @@ -2305,7 +2309,7 @@ static inline bool32 TryStrongWindsWeakenAttack(u32 battlerDef, u32 moveType) { if (gBattleWeather & B_WEATHER_STRONG_WINDS && WEATHER_HAS_EFFECT) { - if (gMovesInfo[gCurrentMove].category != DAMAGE_CATEGORY_STATUS + if (GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS && IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING) && gTypeEffectivenessTable[moveType][TYPE_FLYING] >= UQ_4_12(2.0) && !gBattleStruct->printedStrongWindsWeakenedAttack) @@ -2353,7 +2357,7 @@ static inline bool32 TryActivateWeakenessBerry(u32 battlerDef) static bool32 ProcessPreAttackAnimationFuncs(void) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (IsDoubleSpreadMove()) { u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); @@ -2415,7 +2419,7 @@ static void Cmd_attackanimation(void) && gCurrentMove != MOVE_SUBSTITUTE && gCurrentMove != MOVE_ALLY_SWITCH // In a wild double battle gotta use the teleport animation if two wild pokemon are alive. - && !(gMovesInfo[gCurrentMove].effect == EFFECT_TELEPORT && WILD_DOUBLE_BATTLE && GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT && IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)))) + && !(GetMoveEffect(gCurrentMove) == EFFECT_TELEPORT && WILD_DOUBLE_BATTLE && GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT && IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)))) { BattleScriptPush(cmd->nextInstr); gBattlescriptCurrInstr = BattleScript_Pausex20; @@ -2572,16 +2576,11 @@ static void Cmd_datahpupdate(void) { if (gDisableStructs[battler].substituteHP >= gBattleStruct->moveDamage[battler]) { - if (gSpecialStatuses[battler].shellBellDmg == 0) - gSpecialStatuses[battler].shellBellDmg = gBattleStruct->moveDamage[battler]; gDisableStructs[battler].substituteHP -= gBattleStruct->moveDamage[battler]; - gHpDealt = gBattleStruct->moveDamage[battler]; } else { - if (gSpecialStatuses[battler].shellBellDmg == 0) - gSpecialStatuses[battler].shellBellDmg = gDisableStructs[battler].substituteHP; - gHpDealt = gDisableStructs[battler].substituteHP; + gBattleStruct->moveDamage[battler] = gDisableStructs[battler].substituteHP; gDisableStructs[battler].substituteHP = 0; } // check substitute fading @@ -2639,25 +2638,22 @@ static void Cmd_datahpupdate(void) if (gBattleMons[battler].hp > gBattleStruct->moveDamage[battler]) { gBattleMons[battler].hp -= gBattleStruct->moveDamage[battler]; - gHpDealt = gBattleStruct->moveDamage[battler]; } else { - gHpDealt = gBattleMons[battler].hp; + gBattleStruct->moveDamage[battler] = gBattleMons[battler].hp; gBattleMons[battler].hp = 0; } - // Record damage for Shell Bell - if (gSpecialStatuses[battler].shellBellDmg == 0 && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE)) - gSpecialStatuses[battler].shellBellDmg = gHpDealt; + u32 effect = GetMoveEffect(gCurrentMove); // Note: While physicalDmg/specialDmg below are only distinguished between for Counter/Mirror Coat, they are // used in combination as general damage trackers for other purposes. specialDmg is additionally used // to help determine if a fire move should defrost the target. - if (IS_MOVE_PHYSICAL(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && gMovesInfo[gCurrentMove].effect != EFFECT_PAIN_SPLIT) + if (IsBattleMovePhysical(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && effect != EFFECT_PAIN_SPLIT) { - gProtectStructs[battler].physicalDmg = gHpDealt; - gSpecialStatuses[battler].physicalDmg = gHpDealt; + gProtectStructs[battler].physicalDmg = gBattleStruct->moveDamage[battler]; + gSpecialStatuses[battler].physicalDmg = gBattleStruct->moveDamage[battler]; if (cmd->battler == BS_TARGET) { gProtectStructs[battler].physicalBattlerId = gBattlerAttacker; @@ -2669,11 +2665,11 @@ static void Cmd_datahpupdate(void) gSpecialStatuses[battler].physicalBattlerId = gBattlerTarget; } } - else if (!IS_MOVE_PHYSICAL(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && gMovesInfo[gCurrentMove].effect != EFFECT_PAIN_SPLIT) + else if (!IsBattleMovePhysical(gCurrentMove) && !(gHitMarker & HITMARKER_PASSIVE_DAMAGE) && effect != EFFECT_PAIN_SPLIT) { // Record special damage/attacker for Mirror Coat - gProtectStructs[battler].specialDmg = gHpDealt; - gSpecialStatuses[battler].specialDmg = gHpDealt; + gProtectStructs[battler].specialDmg = gBattleStruct->moveDamage[battler]; + gSpecialStatuses[battler].specialDmg = gBattleStruct->moveDamage[battler]; if (cmd->battler == BS_TARGET) { gProtectStructs[battler].specialBattlerId = gBattlerAttacker; @@ -2692,13 +2688,7 @@ static void Cmd_datahpupdate(void) MarkBattlerForControllerExec(battler); } } - else - { - // MOVE_RESULT_NO_EFFECT was set - battler = GetBattlerForBattleScript(cmd->battler); - if (gSpecialStatuses[battler].shellBellDmg == 0) - gSpecialStatuses[battler].shellBellDmg = IGNORE_SHELL_BELL; - } + gBattlescriptCurrInstr = cmd->nextInstr; } @@ -2814,9 +2804,9 @@ static void Cmd_resultmessage(void) // TODO: Convert this to a proper FORM_CHANGE type. // Do Ice Face form change which was set up in Cmd_adjustdamage. - if (gBattleResources->flags->flags[gBattlerTarget] & RESOURCE_FLAG_ICE_FACE) + if (gDisableStructs[gBattlerTarget].iceFaceActivationPrevention) { - gBattleResources->flags->flags[gBattlerTarget] &= ~(RESOURCE_FLAG_ICE_FACE); + gDisableStructs[gBattlerTarget].iceFaceActivationPrevention = FALSE; gBattleMons[gBattlerTarget].species = SPECIES_EISCUE_NOICE; gBattleScripting.battler = gBattlerTarget; // For STRINGID_PKMNTRANSFORMED BattleScriptPushCursor(); @@ -2827,7 +2817,7 @@ static void Cmd_resultmessage(void) if (*moveResultFlags & MOVE_RESULT_MISSED && (!(*moveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) || gBattleStruct->missStringId[gBattlerTarget] > B_MSG_AVOIDED_ATK)) { - if (gMultiHitCounter && gMultiHitCounter < gMovesInfo[gCurrentMove].strikeCount) + if (gMultiHitCounter && gMultiHitCounter < GetMoveStrikeCount(gCurrentMove)) { gMultiHitCounter = 0; *moveResultFlags &= ~MOVE_RESULT_MISSED; @@ -3010,6 +3000,8 @@ static void Cmd_waitmessage(void) else { u16 toWait = cmd->time; + if (gTestRunnerHeadless) + gPauseCounterBattle = toWait; if (++gPauseCounterBattle >= toWait) { gPauseCounterBattle = 0; @@ -3067,7 +3059,7 @@ static void CheckSetUnburden(u8 battler) { if (GetBattlerAbility(battler) == ABILITY_UNBURDEN) { - gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_UNBURDEN; + gDisableStructs[battler].unbrudenActive = TRUE; RecordAbilityBattle(battler, ABILITY_UNBURDEN); } } @@ -3089,7 +3081,8 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem) { RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem)); gBattleMons[battlerStealer].item = gLastUsedItem; - gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN; + + gDisableStructs[battlerStealer].unbrudenActive = FALSE; BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item MarkBattlerForControllerExec(battlerStealer); } @@ -3177,15 +3170,9 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattleScripting.moveEffect &= ~MOVE_EFFECT_CERTAIN; if (!primary && affectsUser != MOVE_EFFECT_AFFECTS_USER - && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) - && (battlerAbility == ABILITY_SHIELD_DUST || GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_COVERT_CLOAK)) - { - if (battlerAbility == ABILITY_SHIELD_DUST) - RecordAbilityBattle(gEffectBattler, battlerAbility); - else - RecordItemEffectBattle(gEffectBattler, HOLD_EFFECT_COVERT_CLOAK); + && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) + && IsMoveEffectBlockedByTarget(battlerAbility)) INCREMENT_RESET_RETURN - } if (gSideStatuses[GetBattlerSide(gEffectBattler)] & SIDE_STATUS_SAFEGUARD && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && !primary && gBattleScripting.moveEffect <= MOVE_EFFECT_CONFUSION) @@ -3193,7 +3180,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) if (!(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) && TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) - && !(gMovesInfo[gCurrentMove].effect == EFFECT_ORDER_UP && gBattleStruct->commanderActive[gBattlerAttacker]) + && !(GetMoveEffect(gCurrentMove) == EFFECT_ORDER_UP && gBattleStruct->commanderActive[gBattlerAttacker]) && !primary && gBattleScripting.moveEffect != MOVE_EFFECT_CHARGING) INCREMENT_RESET_RETURN @@ -3223,7 +3210,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) if (i != gBattlersCount) break; - if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler), BLOCKED_BY_SLEEP_CLAUSE) && !(gBattleStruct->sleepClauseEffectExempt & (1u << gEffectBattler))) + if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler), BLOCKED_BY_SLEEP_CLAUSE) && !gBattleStruct->battlerState[gEffectBattler].sleepClauseEffectExempt) break; cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler); @@ -3300,7 +3287,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) if (B_STATUS_TYPE_IMMUNITY == GEN_1) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (primary == FALSE && certain == FALSE && IS_BATTLER_OF_TYPE(gEffectBattler, moveType)) break; } @@ -3313,7 +3300,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) case STATUS1_FREEZE: if (B_STATUS_TYPE_IMMUNITY == GEN_1) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (primary == FALSE && certain == FALSE && IS_BATTLER_OF_TYPE(gEffectBattler, moveType)) break; } @@ -3354,7 +3341,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) } if (B_STATUS_TYPE_IMMUNITY == GEN_1) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (primary == FALSE && certain == FALSE && IS_BATTLER_OF_TYPE(gEffectBattler, moveType)) break; } @@ -3424,7 +3411,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) case STATUS1_FROSTBITE: if (B_STATUS_TYPE_IMMUNITY == GEN_1) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (primary == FALSE && certain == FALSE && IS_BATTLER_OF_TYPE(gEffectBattler, moveType)) break; } @@ -3579,7 +3566,7 @@ void SetMoveEffect(bool32 primary, bool32 certain) // For a move that hits multiple targets (i.e. Make it Rain) // we only want to print the message on the final hit - if (!(IsSpreadMove(moveTarget) && GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT)) + if (!(NumAffectedSpreadMoveTargets() > 1 && GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT)) { BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = BattleScript_MoveEffectPayDay; @@ -4008,9 +3995,11 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattleMons[gBattlerAttacker].status2 |= STATUS2_ESCAPE_PREVENTION; break; case MOVE_EFFECT_REMOVE_ARG_TYPE: + { + u32 type = GetMoveArgType(gCurrentMove); // This seems unnecessary but is done to make it work properly with Parental Bond BattleScriptPush(gBattlescriptCurrInstr + 1); - switch (gMovesInfo[gCurrentMove].argument.type) + switch (type) { case TYPE_FIRE: // Burn Up gBattlescriptCurrInstr = BattleScript_RemoveFireType; @@ -4022,8 +4011,9 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattlescriptCurrInstr = BattleScript_RemoveGenericType; break; } - RemoveBattlerType(gEffectBattler, gMovesInfo[gCurrentMove].argument.type); + RemoveBattlerType(gEffectBattler, type); break; + } case MOVE_EFFECT_ROUND: TryUpdateRoundTurnOrder(); // If another Pokémon uses Round before the user this turn, the user will use Round directly after it gBattlescriptCurrInstr++; @@ -4335,12 +4325,10 @@ void SetMoveEffect(bool32 primary, bool32 certain) static bool32 CanApplyAdditionalEffect(const struct AdditionalEffect *additionalEffect) { - u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); - // Self-targeting move effects only apply after the last mon has been hit if (additionalEffect->self - && IsSpreadMove(moveTarget) - && GetNextTarget(moveTarget, TRUE) != MAX_BATTLERS_COUNT) + && NumAffectedSpreadMoveTargets() > 1 + && GetNextTarget(GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove), TRUE) != MAX_BATTLERS_COUNT) return FALSE; // Certain move effects only apply if the target raised stats this turn (e.g. Burning Jealousy) @@ -4360,10 +4348,11 @@ static void Cmd_setadditionaleffects(void) if (MoveResultHasEffect(gBattlerTarget)) { - if (gMovesInfo[gCurrentMove].numAdditionalEffects > gBattleStruct->additionalEffectsCounter) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(gCurrentMove); + if (numAdditionalEffects > gBattleStruct->additionalEffectsCounter) { u32 percentChance; - const struct AdditionalEffect *additionalEffect = &gMovesInfo[gCurrentMove].additionalEffects[gBattleStruct->additionalEffectsCounter]; + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(gCurrentMove, gBattleStruct->additionalEffectsCounter); const u8 *currentPtr = gBattlescriptCurrInstr; // Various checks for if this move effect can be applied this turn @@ -4389,7 +4378,7 @@ static void Cmd_setadditionaleffects(void) // Call setadditionaleffects again in the case of a move with multiple effects gBattleStruct->additionalEffectsCounter++; - if (gMovesInfo[gCurrentMove].numAdditionalEffects > gBattleStruct->additionalEffectsCounter) + if (numAdditionalEffects > gBattleStruct->additionalEffectsCounter) gBattleScripting.moveEffect = MOVE_EFFECT_CONTINUE; else gBattleScripting.moveEffect = gBattleStruct->additionalEffectsCounter = 0; @@ -5513,6 +5502,8 @@ static void Cmd_pause(void) if (gBattleControllerExecFlags == 0) { u16 value = cmd->frames; + if (gTestRunnerHeadless) + gPauseCounterBattle = value; if (++gPauseCounterBattle >= value) { gPauseCounterBattle = 0; @@ -5591,7 +5582,7 @@ static void Cmd_setroost(void) { CMD_ARGS(); - gBattleResources->flags->flags[gBattlerAttacker] |= RESOURCE_FLAG_ROOST; + gDisableStructs[gBattlerAttacker].roostActive = TRUE; gBattleStruct->roostTypes[gBattlerAttacker][0] = gBattleMons[gBattlerAttacker].types[0]; gBattleStruct->roostTypes[gBattlerAttacker][1] = gBattleMons[gBattlerAttacker].types[1]; @@ -5903,7 +5894,7 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent) if (battler != gBattlerAttacker && !(excludeCurrent && battler == gBattlerTarget) && IsBattlerAlive(battler) - && !(gBattleStruct->targetsDone[gBattlerAttacker] & (1u << battler)) + && !gBattleStruct->battlerState[gBattlerAttacker].targetsDone[battler] && (GetBattlerSide(battler) != GetBattlerSide(gBattlerAttacker) || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) break; } @@ -5930,21 +5921,23 @@ static void Cmd_moveend(void) endState = cmd->endState; holdEffectAtk = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - moveType = GetMoveType(gCurrentMove); + moveType = GetBattleMoveType(gCurrentMove); + + u32 moveEffect = GetMoveEffect(gCurrentMove); do { switch (gBattleScripting.moveendState) { case MOVEEND_SUM_DAMAGE: // Sum and store damage dealt for multi strike recoil - gBattleScripting.savedDmg += gHpDealt; + gBattleScripting.savedDmg += gBattleStruct->moveDamage[gBattlerTarget]; gBattleScripting.moveendState++; break; case MOVEEND_PROTECT_LIKE_EFFECT: if (gProtectStructs[gBattlerAttacker].touchedProtectLike) { if (gProtectStructs[gBattlerTarget].spikyShielded - && gMovesInfo[gCurrentMove].effect != EFFECT_COUNTER + && moveEffect != EFFECT_COUNTER && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; @@ -5979,7 +5972,8 @@ static void Cmd_moveend(void) gBattlescriptCurrInstr = BattleScript_BanefulBunkerEffect; effect = 1; } - else if (gProtectStructs[gBattlerTarget].obstructed && gMovesInfo[gCurrentMove].effect != EFFECT_SUCKER_PUNCH && gMovesInfo[gCurrentMove].effect != EFFECT_UPPER_HAND) + else if (gProtectStructs[gBattlerTarget].obstructed + && moveEffect != EFFECT_SUCKER_PUNCH && moveEffect != EFFECT_UPPER_HAND) { gProtectStructs[gBattlerAttacker].touchedProtectLike = FALSE; i = gBattlerAttacker; @@ -6027,18 +6021,18 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_ABSORB: - if (gMovesInfo[gCurrentMove].effect == EFFECT_ABSORB + if (moveEffect == EFFECT_ABSORB && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && IsBattlerTurnDamaged(gBattlerTarget)) { - if (gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && gMovesInfo[gCurrentMove].healingMove) + if (gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && IsHealingMove(gCurrentMove)) { gBattleScripting.moveendState++; break; } else if (IsBattlerAlive(gBattlerAttacker) && MoveResultHasEffect(gBattlerTarget)) { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * gMovesInfo[gCurrentMove].argument.absorbPercentage / 100)); + gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100)); gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]); gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE; effect = TRUE; @@ -6067,7 +6061,7 @@ static void Cmd_moveend(void) && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget) && MoveResultHasEffect(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget) - && !IS_MOVE_STATUS(gCurrentMove) + && !IsBattleMoveStatus(gCurrentMove) && CompareStat(gBattlerTarget, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) { SET_STATCHANGER(STAT_ATK, 1, FALSE); @@ -6079,6 +6073,7 @@ static void Cmd_moveend(void) break; case MOVEEND_DEFROST: // defrosting check if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE + && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerTarget) && gBattlerAttacker != gBattlerTarget && (moveType == TYPE_FIRE || CanBurnHitThaw(gCurrentMove)) @@ -6094,7 +6089,7 @@ static void Cmd_moveend(void) if (gBattleMons[gBattlerTarget].status1 & STATUS1_FROSTBITE && IsBattlerAlive(gBattlerTarget) && gBattlerAttacker != gBattlerTarget - && gMovesInfo[originallyUsedMove].thawsUser + && MoveThawsUser(originallyUsedMove) && MoveResultHasEffect(gBattlerTarget)) { gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE; @@ -6107,30 +6102,31 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_RECOIL: + { + u32 moveRecoil = GetMoveRecoil(gCurrentMove); if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) { gBattleScripting.moveendState++; break; } - else if (gMovesInfo[gCurrentMove].recoil > 0 + else if (moveRecoil > 0 && MoveResultHasEffect(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker) && gBattleScripting.savedDmg != 0) // Some checks may be redundant alongside this one { - gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, gMovesInfo[gCurrentMove].recoil) / 100); + gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleScripting.savedDmg * max(1, moveRecoil) / 100); BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil; effect = TRUE; } - else if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION && !IsAbilityOnField(ABILITY_DAMP)) + else if (moveEffect == EFFECT_EXPLOSION && !IsAbilityOnField(ABILITY_DAMP)) { gBattleStruct->moveDamage[gBattlerAttacker] = 0; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_FaintAttackerForExplosion; effect = TRUE; } - else if ((gMovesInfo[gCurrentMove].effect == EFFECT_MAX_HP_50_RECOIL - || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN) + else if ((moveEffect == EFFECT_MAX_HP_50_RECOIL || moveEffect == EFFECT_MIND_BLOWN) && IsBattlerAlive(gBattlerAttacker) && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) @@ -6142,6 +6138,7 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + } case MOVEEND_ITEM_EFFECTS_ATTACKER: if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker, FALSE)) effect = TRUE; @@ -6187,8 +6184,7 @@ static void Cmd_moveend(void) && gChosenMove != MOVE_STRUGGLE && (*choicedMoveAtk == MOVE_NONE || *choicedMoveAtk == MOVE_UNAVAILABLE)) { - if ((gMovesInfo[gChosenMove].effect == EFFECT_BATON_PASS - || gMovesInfo[gChosenMove].effect == EFFECT_HEALING_WISH) + if ((moveEffect == EFFECT_BATON_PASS || moveEffect == EFFECT_HEALING_WISH) && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED)) { gBattleScripting.moveendState++; @@ -6256,18 +6252,21 @@ static void Cmd_moveend(void) } break; case MOVE_EFFECT_REMOVE_STATUS: // Smelling salts, Wake-Up Slap, Sparkling Aria - if ((gBattleMons[gBattlerTarget].status1 & gMovesInfo[gCurrentMove].argument.status) + { + u32 argStatus = GetMoveEffectArg_Status(gCurrentMove); + if ((gBattleMons[gBattlerTarget].status1 & argStatus) && IsBattlerAlive(gBattlerTarget) - && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove)) + && !DoesSubstituteBlockMove(gBattlerAttacker, gBattlerTarget, gCurrentMove) + && (NumAffectedSpreadMoveTargets() > 1 || !IsMoveEffectBlockedByTarget(GetBattlerAbility(gBattlerTarget)))) { - gBattleMons[gBattlerTarget].status1 &= ~(gMovesInfo[gCurrentMove].argument.status); + gBattleMons[gBattlerTarget].status1 &= ~(argStatus); BtlController_EmitSetMonData(gBattlerTarget, 0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gBattlerTarget].status1); MarkBattlerForControllerExec(gBattlerTarget); effect = TRUE; BattleScriptPush(gBattlescriptCurrInstr); - switch (gMovesInfo[gCurrentMove].argument.status) + switch (argStatus) { case STATUS1_PARALYSIS: gBattlescriptCurrInstr = BattleScript_TargetPRLZHeal; @@ -6294,6 +6293,7 @@ static void Cmd_moveend(void) } break; // MOVE_EFFECT_REMOVE_STATUS } + } gBattleStruct->moveEffect2 = 0; gBattleScripting.moveendState++; break; // MOVEEND_MOVE_EFFECTS2 @@ -6349,7 +6349,7 @@ static void Cmd_moveend(void) break; case MOVEEND_NUM_HITS: if (gBattlerAttacker != gBattlerTarget - && gMovesInfo[gCurrentMove].category != DAMAGE_CATEGORY_STATUS + && GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS && MoveResultHasEffect(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget)) { @@ -6396,12 +6396,12 @@ static void Cmd_moveend(void) if ((gBattleStruct->moveResultFlags[gBattlerTarget] & (MOVE_RESULT_FAILED | MOVE_RESULT_DOESNT_AFFECT_FOE)) || (gBattleMons[gBattlerAttacker].status2 & (STATUS2_FLINCHED)) || gProtectStructs[gBattlerAttacker].prlzImmobility) - gBattleStruct->lastMoveFailed |= 1u << gBattlerAttacker; + gBattleStruct->battlerState[gBattlerAttacker].lastMoveFailed = TRUE; else - gBattleStruct->lastMoveFailed &= ~(1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].lastMoveFailed = FALSE; // Set ShellTrap to activate after the attacker's turn if target was hit by a physical move. - if (gMovesInfo[gChosenMoveByBattler[gBattlerTarget]].effect == EFFECT_SHELL_TRAP + if (GetMoveEffect(gChosenMoveByBattler[gBattlerTarget]) == EFFECT_SHELL_TRAP && gBattlerTarget != gBattlerAttacker && GetBattlerSide(gBattlerTarget) != GetBattlerSide(gBattlerAttacker) && gProtectStructs[gBattlerTarget].physicalDmg @@ -6434,10 +6434,10 @@ static void Cmd_moveend(void) gBattleStruct->dynamax.lastUsedBaseMove = gBattleStruct->dynamax.baseMoves[gBattlerAttacker]; } } + u32 originalEffect = GetMoveEffect(originallyUsedMove); if (!(gAbsentBattlerFlags & (1u << gBattlerAttacker)) - && !(gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker)) - && gMovesInfo[originallyUsedMove].effect != EFFECT_BATON_PASS - && gMovesInfo[originallyUsedMove].effect != EFFECT_HEALING_WISH) + && !gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags + && originalEffect != EFFECT_BATON_PASS && originalEffect != EFFECT_HEALING_WISH) { if (gHitMarker & HITMARKER_OBEYS) { @@ -6446,7 +6446,7 @@ static void Cmd_moveend(void) gLastMoves[gBattlerAttacker] = gChosenMove; RecordKnownMove(gBattlerAttacker, gChosenMove); gLastResultingMoves[gBattlerAttacker] = gCurrentMove; - gLastUsedMoveType[gBattlerAttacker] = GetMoveType(gCurrentMove); + gLastUsedMoveType[gBattlerAttacker] = GetBattleMoveType(gCurrentMove); } } else @@ -6468,7 +6468,7 @@ static void Cmd_moveend(void) else { gLastLandedMoves[gBattlerTarget] = gCurrentMove; - gLastHitByType[gBattlerTarget] = GetMoveType(gCurrentMove); + gLastHitByType[gBattlerTarget] = GetBattleMoveType(gCurrentMove); } } else @@ -6480,8 +6480,8 @@ static void Cmd_moveend(void) break; case MOVEEND_MIRROR_MOVE: // mirror move if (!(gAbsentBattlerFlags & (1u << gBattlerAttacker)) - && !(gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker)) - && !gMovesInfo[originallyUsedMove].mirrorMoveBanned + && !gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags + && !IsMoveMirrorMoveBanned(originallyUsedMove) && gHitMarker & HITMARKER_OBEYS && gBattlerAttacker != gBattlerTarget && !(gHitMarker & HITMARKER_FAINTED(gBattlerTarget)) @@ -6500,7 +6500,7 @@ static void Cmd_moveend(void) && MoveResultHasEffect(gBattlerTarget)) gProtectStructs[gBattlerAttacker].targetAffected = TRUE; - gBattleStruct->targetsDone[gBattlerAttacker] |= 1u << gBattlerTarget; + gBattleStruct->battlerState[gBattlerAttacker].targetsDone[gBattlerTarget] = TRUE; if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && IsDoubleBattle() && !gProtectStructs[gBattlerAttacker].chargingTurn @@ -6518,10 +6518,10 @@ static void Cmd_moveend(void) MoveValuesCleanUp(); gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect; - if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION) + if (moveEffect == EFFECT_EXPLOSION) BattleScriptPush(gBattleMoveEffects[EFFECT_HIT].battleScript); // Edge case for Explosion not changing targets else - BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); + BattleScriptPush(GetMoveBattleScript(gCurrentMove)); gBattlescriptCurrInstr = BattleScript_FlushMessageBox; return; } @@ -6531,9 +6531,9 @@ static void Cmd_moveend(void) u8 originalBounceTarget = gBattlerAttacker; gBattleStruct->bouncedMoveIsUsed = FALSE; gBattlerAttacker = gBattleStruct->attackerBeforeBounce; - gBattleStruct->targetsDone[gBattlerAttacker] |= 1u << originalBounceTarget; - gBattleStruct->targetsDone[originalBounceTarget] = 0; - + gBattleStruct->battlerState[gBattlerAttacker].targetsDone[originalBounceTarget] = TRUE; + for (i = 0; i < gBattlersCount; i++) + gBattleStruct->battlerState[originalBounceTarget].targetsDone[i] = FALSE; nextTarget = GetNextTarget(moveTarget, FALSE); if (nextTarget != MAX_BATTLERS_COUNT) { @@ -6543,7 +6543,7 @@ static void Cmd_moveend(void) gBattleScripting.animTurn = 0; gBattleScripting.animTargetsHit = 0; MoveValuesCleanUp(); - BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); + BattleScriptPush(GetMoveBattleScript(gCurrentMove)); gBattlescriptCurrInstr = BattleScript_FlushMessageBox; return; } @@ -6561,17 +6561,17 @@ static void Cmd_moveend(void) if (MoveResultHasEffect(gBattlerTarget) && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gMultiHitCounter - && !(gMovesInfo[gCurrentMove].effect == EFFECT_PRESENT && gBattleStruct->presentBasePower == 0)) // Silly edge case + && !(moveEffect == EFFECT_PRESENT && gBattleStruct->presentBasePower == 0)) // Silly edge case { gMultiHitCounter--; - if (!IsBattlerAlive(gBattlerTarget) && gMovesInfo[gCurrentMove].effect != EFFECT_DRAGON_DARTS) + if (!IsBattlerAlive(gBattlerTarget) && moveEffect != EFFECT_DRAGON_DARTS) gMultiHitCounter = 0; gBattleScripting.multihitString[4]++; if (gMultiHitCounter == 0) { BattleScriptPushCursor(); - if (gMovesInfo[gCurrentMove].argument.moveProperty == MOVE_EFFECT_SCALE_SHOT && !NoAliveMonsForEitherParty()) + if (GetMoveEffectArg_MoveProperty(gCurrentMove) == MOVE_EFFECT_SCALE_SHOT && !NoAliveMonsForEitherParty()) gBattlescriptCurrInstr = BattleScript_ScaleShot; else gBattlescriptCurrInstr = BattleScript_MultiHitPrintStrings; @@ -6579,7 +6579,7 @@ static void Cmd_moveend(void) } else { - if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS + if (moveEffect == EFFECT_DRAGON_DARTS && !(gBattleStruct->moveResultFlags[BATTLE_PARTNER(gBattlerTarget)] & MOVE_RESULT_MISSED) // didn't miss the other target && CanTargetPartner(gBattlerAttacker, gBattlerTarget) && !TargetFullyImmuneToCurrMove(gBattlerAttacker, BATTLE_PARTNER(gBattlerTarget))) @@ -6601,7 +6601,7 @@ static void Cmd_moveend(void) gSpecialStatuses[gBattlerTarget].focusSashed = 0; // Delete this line to make Focus Sash last for the duration of the whole move turn. gSpecialStatuses[gBattlerAttacker].multiHitOn = TRUE; MoveValuesCleanUp(); - BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); + BattleScriptPush(GetMoveBattleScript(gCurrentMove)); gBattlescriptCurrInstr = BattleScript_FlushMessageBox; return; } @@ -6694,36 +6694,34 @@ static void Cmd_moveend(void) if (IsBattlerAlive(battler) && CountUsablePartyMons(battler) > 0 // Has mon to switch into // Does not activate if attacker used Parting Shot and can switch out - && !(gMovesInfo[gCurrentMove].effect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(gBattlerAttacker)) + && !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(gBattlerAttacker)) ) { gBattleScripting.battler = battler; gLastUsedItem = gBattleMons[battler].item; - if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE) + if (moveEffect == EFFECT_HIT_ESCAPE) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection - effect = TRUE; - BattleScriptPushCursor(); - gBattleStruct->usedEjectItem |= 1u << battler; if (ejectButtonBattlers & (1u << battler)) { + effect = TRUE; + gBattleStruct->battlerState[battler].usedEjectItem = TRUE; + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EjectButtonActivates; AI_DATA->ejectButtonSwitch = TRUE; } else // Eject Pack { - if (gBattleResources->flags->flags[gBattlerTarget] & RESOURCE_FLAG_EMERGENCY_EXIT) - { - gBattlescriptCurrInstr = BattleScript_EjectPackMissesTiming; - gProtectStructs[battler].statFell = FALSE; - } - else + if (!gDisableStructs[gBattlerTarget].startEmergencyExit + && !(gMovesInfo[gCurrentMove].effect == EFFECT_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker))) { + effect = TRUE; + gBattleStruct->battlerState[battler].usedEjectItem = TRUE; + BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_EjectPackActivates; AI_DATA->ejectPackSwitch = TRUE; - // Are these 2 lines below needed? - gProtectStructs[battler].statFell = FALSE; gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = TRUE; } + gProtectStructs[battler].statFell = FALSE; } break; // Only the fastest Eject item activates } @@ -6756,7 +6754,7 @@ static void Cmd_moveend(void) redCardBattlers |= (1u << i); } if (redCardBattlers - && (gMovesInfo[gCurrentMove].effect != EFFECT_HIT_SWITCH_TARGET || gBattleStruct->hitSwitchTargetFailed) + && (moveEffect != EFFECT_HIT_SWITCH_TARGET || gBattleStruct->hitSwitchTargetFailed) && IsBattlerAlive(gBattlerAttacker) && !TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove) && GetBattlerAbility(gBattlerAttacker) != ABILITY_GUARD_DOG) @@ -6781,7 +6779,7 @@ static void Cmd_moveend(void) gBattleScripting.battler = battler; gEffectBattler = gBattlerAttacker; gBattleStruct->redCardActivates = TRUE; - if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE) + if (moveEffect == EFFECT_HIT_ESCAPE) gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection BattleScriptPushCursor(); if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE) @@ -6844,7 +6842,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_DANCER: // Special case because it's so annoying - if (gMovesInfo[gCurrentMove].danceMove && !gBattleStruct->snatchedMoveIsUsed) + if (IsDanceMove(gCurrentMove) && !gBattleStruct->snatchedMoveIsUsed) { u32 battler, nextDancer = 0; bool32 hasDancerTriggered = FALSE; @@ -6891,12 +6889,12 @@ static void Cmd_moveend(void) { if (gBattleStruct->redCardActivates) { - gBattleResources->flags->flags[i] &= ~RESOURCE_FLAG_EMERGENCY_EXIT; + gDisableStructs[i].startEmergencyExit = FALSE; continue; } - if (gBattleResources->flags->flags[i] & RESOURCE_FLAG_EMERGENCY_EXIT) + if (gDisableStructs[i].startEmergencyExit) { - gBattleResources->flags->flags[i] &= ~RESOURCE_FLAG_EMERGENCY_EXIT; + gDisableStructs[i].startEmergencyExit = FALSE; gSpecialStatuses[i].emergencyExited = TRUE; gBattlerTarget = gBattlerAbility = i; BattleScriptPushCursor(); @@ -6978,13 +6976,11 @@ static void Cmd_moveend(void) DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!"); // #endif } - gBattleStruct->targetsDone[gBattlerAttacker] = 0; gProtectStructs[gBattlerAttacker].targetAffected = FALSE; gProtectStructs[gBattlerAttacker].shellTrap = FALSE; gBattleStruct->ateBoost[gBattlerAttacker] = FALSE; gStatuses3[gBattlerAttacker] &= ~STATUS3_ME_FIRST; gSpecialStatuses[gBattlerAttacker].gemBoost = FALSE; - gSpecialStatuses[gBattlerAttacker].damagedMons = 0; gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage = 0; gSpecialStatuses[gBattlerTarget].berryReduced = FALSE; gSpecialStatuses[gBattlerTarget].distortedTypeMatchups = FALSE; @@ -6995,12 +6991,11 @@ static void Cmd_moveend(void) gBattleStruct->categoryOverride = FALSE; gBattleStruct->bouncedMoveIsUsed = FALSE; gBattleStruct->snatchedMoveIsUsed = FALSE; - gBattleStruct->enduredDamage = 0; gBattleStruct->additionalEffectsCounter = 0; gBattleStruct->poisonPuppeteerConfusion = FALSE; gBattleStruct->fickleBeamBoosted = FALSE; gBattleStruct->redCardActivates = FALSE; - gBattleStruct->usedMicleBerry &= ~(1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].usedMicleBerry = FALSE; if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) gBattleStruct->pledgeMove = FALSE; if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE) @@ -7012,6 +7007,8 @@ static void Cmd_moveend(void) for (i = 0; i < gBattlersCount; i++) { + gBattleStruct->battlerState[gBattlerAttacker].targetsDone[i] = FALSE; + if (gBattleStruct->commanderActive[i] != SPECIES_NONE && !IsBattlerAlive(i)) { u32 partner = BATTLE_PARTNER(i); @@ -7024,7 +7021,7 @@ static void Cmd_moveend(void) gBattleScripting.moveendState++; break; case MOVEEND_PURSUIT_NEXT_ACTION: - if (gBattleStruct->pursuitTarget & (1u << gBattlerTarget)) + if (gBattleStruct->battlerState[gBattlerTarget].pursuitTarget) { u32 storedTarget = gBattlerTarget; if (SetTargetToNextPursuiter(gBattlerTarget)) @@ -7041,9 +7038,7 @@ static void Cmd_moveend(void) else gBattlescriptCurrInstr = BattleScript_DoSwitchOut; *(gBattleStruct->monToSwitchIntoId + gBattlerTarget) = gBattleStruct->pursuitStoredSwitch; - gBattleStruct->pursuitTarget = 0; - gBattleStruct->pursuitSwitchByMove = FALSE; - gBattleStruct->pursuitStoredSwitch = 0; + ClearPursuitValues(); effect = TRUE; } } @@ -7165,7 +7160,7 @@ static void Cmd_switchindataupdate(void) u32 side = GetBattlerSide(battler); u32 partyIndex = gBattlerPartyIndexes[battler]; if (TestRunner_Battle_GetForcedAbility(side, partyIndex)) - gBattleMons[battler].ability = gBattleStruct->overwrittenAbilities[battler] = TestRunner_Battle_GetForcedAbility(side, partyIndex); + gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = TestRunner_Battle_GetForcedAbility(side, partyIndex); } #endif @@ -7176,7 +7171,7 @@ static void Cmd_switchindataupdate(void) gBattleMons[battler].item = ITEM_NONE; } - if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS) + if (GetMoveEffect(gCurrentMove) == EFFECT_BATON_PASS) { for (i = 0; i < NUM_BATTLE_STATS; i++) { @@ -7206,7 +7201,7 @@ static void Cmd_switchinanim(void) { u32 battler; - CMD_ARGS(u8 battler, bool8 dontClearSubstitute); + CMD_ARGS(u8 battler, bool8 dontClearTransform, bool8 dontClearSubstitute); if (gBattleControllerExecFlags) return; @@ -7223,7 +7218,7 @@ static void Cmd_switchinanim(void) gAbsentBattlerFlags &= ~(1u << battler); - BtlController_EmitSwitchInAnim(battler, BUFFER_A, gBattlerPartyIndexes[battler], cmd->dontClearSubstitute); + BtlController_EmitSwitchInAnim(battler, BUFFER_A, gBattlerPartyIndexes[battler], cmd->dontClearTransform, cmd->dontClearSubstitute); MarkBattlerForControllerExec(battler); gBattlescriptCurrInstr = cmd->nextInstr; @@ -7726,20 +7721,20 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) } // Healing Wish activates before hazards. // Starting from Gen8 - it heals only pokemon which can be healed. In gens 5,6,7 the effect activates anyways. - else if (((gBattleStruct->storedHealingWish & (1u << battler)) || (gBattleStruct->storedLunarDance & (1u << battler))) + else if ((gBattleStruct->battlerState[battler].storedHealingWish || gBattleStruct->battlerState[battler].storedLunarDance) && (gBattleMons[battler].hp != gBattleMons[battler].maxHP || gBattleMons[battler].status1 != 0 || B_HEALING_WISH_SWITCH < GEN_8)) { - if (gBattleStruct->storedHealingWish & (1u << battler)) + if (gBattleStruct->battlerState[battler].storedHealingWish) { BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_HealingWishActivates; - gBattleStruct->storedHealingWish &= ~(1u << battler); + gBattleStruct->battlerState[battler].storedHealingWish = FALSE; } else // Lunar Dance { BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_LunarDanceActivates; - gBattleStruct->storedLunarDance &= ~(1u << battler); + gBattleStruct->battlerState[battler].storedLunarDance = FALSE; } } else if (!(gDisableStructs[battler].spikesDone) @@ -7762,7 +7757,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { gDisableStructs[battler].stealthRockDone = TRUE; - gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(gMovesInfo[MOVE_STEALTH_ROCK].type, battler); + gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_POINTED_STONES, battler); if (gBattleStruct->moveDamage[battler] != 0) SetDmgHazardsBattlescript(battler, B_MSG_STEALTHROCKDMG); @@ -7821,7 +7816,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) && GetBattlerAbility(battler) != ABILITY_MAGIC_GUARD) { gDisableStructs[battler].steelSurgeDone = TRUE; - gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(gMovesInfo[MOVE_G_MAX_STEELSURGE].type, battler); + gBattleStruct->moveDamage[battler] = GetStealthHazardDamage(TYPE_SIDE_HAZARD_SHARP_STEEL, battler); if (gBattleStruct->moveDamage[battler] != 0) SetDmgHazardsBattlescript(battler, B_MSG_SHARPSTEELDMG); @@ -7888,7 +7883,7 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) gBattleStruct->hpOnSwitchout[GetBattlerSide(i)] = gBattleMons[i].hp; } - gBattleStruct->forcedSwitch &= ~(1u << battler); + gBattleStruct->battlerState[battler].forcedSwitch = FALSE; return FALSE; } @@ -7904,7 +7899,7 @@ static void Cmd_switchineffects(void) { // Multiple mons fainted and are being switched-in. Their abilities/hazards will play according to speed ties. case BS_FAINTED_MULTIPLE_1: // Saves the battlers. - gBattleStruct->multipleSwitchInBattlers |= 1 << battler; + gBattleStruct->battlerState[battler].multipleSwitchInBattlers = TRUE; UpdateSentMonFlags(battler); // Increment fainted battler. @@ -7933,14 +7928,16 @@ static void Cmd_switchineffects(void) for (; gBattleStruct->multipleSwitchInCursor < gBattlersCount; gBattleStruct->multipleSwitchInCursor++) { gBattlerFainted = gBattleStruct->multipleSwitchInSortedBattlers[gBattleStruct->multipleSwitchInCursor]; - if (gBattleStruct->multipleSwitchInBattlers & (1 << (gBattlerFainted))) + if (gBattleStruct->battlerState[gBattlerFainted].multipleSwitchInBattlers) { if (DoSwitchInEffectsForBattler(gBattlerFainted)) return; } } // All battlers done, end - gBattleStruct->multipleSwitchInBattlers = 0; + for (i = 0; i < gBattlersCount; i++) + gBattleStruct->battlerState[i].multipleSwitchInBattlers = FALSE; + gBattleStruct->multipleSwitchInState = 0; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -8445,7 +8442,7 @@ static void Cmd_jumptocalledmove(void) else gChosenMove = gCurrentMove = gCalledMove; - gBattlescriptCurrInstr = GET_MOVE_BATTLESCRIPT(gCurrentMove); + gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove); } static void Cmd_statusanimation(void) @@ -8610,7 +8607,7 @@ static void BestowItem(u32 battlerAtk, u32 battlerDef) gBattleMons[battlerDef].item = gLastUsedItem; BtlController_EmitSetMonData(battlerDef, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[battlerDef].item), &gBattleMons[battlerDef].item); MarkBattlerForControllerExec(battlerDef); - gBattleResources->flags->flags[battlerDef] &= ~RESOURCE_FLAG_UNBURDEN; + gDisableStructs[battlerDef].unbrudenActive = FALSE; } // Called by Cmd_removeitem. itemId represents the item that was removed, not being given. @@ -8656,7 +8653,7 @@ static void Cmd_removeitem(void) // Popped Air Balloon cannot be restored by any means. // Corroded items cannot be restored either. if (GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_AIR_BALLOON - && gMovesInfo[gCurrentMove].effect != EFFECT_CORROSIVE_GAS) + && GetMoveEffect(gCurrentMove) != EFFECT_CORROSIVE_GAS) gBattleStruct->usedHeldItems[gBattlerPartyIndexes[battler]][GetBattlerSide(battler)] = itemId; // Remember if switched out gBattleMons[battler].item = ITEM_NONE; @@ -9085,7 +9082,7 @@ static void Cmd_useitemonopponent(void) static bool32 HasAttackerFaintedTarget(void) { if (MoveResultHasEffect(gBattlerTarget) - && !IS_MOVE_STATUS(gCurrentMove) + && !IsBattleMoveStatus(gCurrentMove) && (gLastHitBy[gBattlerTarget] == 0xFF || gLastHitBy[gBattlerTarget] == gBattlerAttacker) && gBattleStruct->moveTarget[gBattlerAttacker] == gBattlerTarget && gBattlerTarget != gBattlerAttacker @@ -9348,11 +9345,11 @@ static bool32 IsElectricAbilityAffected(u32 battler, u32 ability) u32 moveType; if (gBattleStruct->dynamicMoveType == 0) - moveType = gMovesInfo[gCurrentMove].type; + moveType = GetMoveType(gCurrentMove); else if (!(gBattleStruct->dynamicMoveType & F_DYNAMIC_TYPE_IGNORE_PHYSICALITY)) moveType = gBattleStruct->dynamicMoveType & DYNAMIC_TYPE_MASK; else - moveType = gMovesInfo[gCurrentMove].type; + moveType = GetMoveType(gCurrentMove); if (moveType == TYPE_ELECTRIC && (ability != ABILITY_LIGHTNING_ROD || B_REDIRECT_ABILITY_IMMUNITY >= GEN_5) @@ -9392,8 +9389,10 @@ static bool32 IsTeatimeAffected(u32 battler) sideTimerOpp->structField = BATTLE_OPPOSITE(temp); \ } \ -static void CourtChangeSwapSideStatuses(void) +void BS_CourtChangeSwapSideStatuses(void) { + NATIVE_ARGS(); + struct SideTimer *sideTimerPlayer = &gSideTimers[B_SIDE_PLAYER]; struct SideTimer *sideTimerOpp = &gSideTimers[B_SIDE_OPPONENT]; u32 temp; @@ -9434,6 +9433,8 @@ static void CourtChangeSwapSideStatuses(void) // Swap what type set the Gigantamax damage over time effect SWAP(sideTimerPlayer->damageNonTypesType, sideTimerOpp->damageNonTypesType, temp); + + gBattlescriptCurrInstr = cmd->nextInstr; } static void HandleScriptMegaPrimalBurst(u32 caseId, u32 battler, u32 type) @@ -9712,7 +9713,7 @@ static void Cmd_various(void) case VARIOUS_TRACE_ABILITY: { VARIOUS_ARGS(); - gBattleMons[battler].ability = gBattleStruct->overwrittenAbilities[battler] = gBattleStruct->tracedAbility[battler]; + gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = gBattleStruct->tracedAbility[battler]; break; } case VARIOUS_TRY_ILLUSION_OFF: @@ -9857,7 +9858,7 @@ static void Cmd_various(void) case VARIOUS_GET_MOVE_TARGET: { VARIOUS_ARGS(); - gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); break; } case VARIOUS_GET_BATTLER_FAINTED: @@ -10051,7 +10052,7 @@ static void Cmd_various(void) case VARIOUS_SET_ALREADY_STATUS_MOVE_ATTEMPT: { VARIOUS_ARGS(); - gBattleStruct->alreadyStatusedMoveAttempt |= 1u << battler; + gBattleStruct->battlerState[battler].alreadyStatusedMoveAttempt = TRUE; break; } case VARIOUS_PALACE_TRY_ESCAPE_STATUS: @@ -10242,7 +10243,7 @@ static void Cmd_various(void) case VARIOUS_TRY_ACTIVATE_FELL_STINGER: { VARIOUS_ARGS(); - if (gMovesInfo[gCurrentMove].effect == EFFECT_FELL_STINGER + if (GetMoveEffect(gCurrentMove) == EFFECT_FELL_STINGER && HasAttackerFaintedTarget() && !NoAliveMonsForEitherParty() && CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN)) @@ -10286,7 +10287,7 @@ static void Cmd_various(void) gBattlescriptCurrInstr = cmd->failInstr; else if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)) gBattlescriptCurrInstr = cmd->failInstr; - else if (IS_MOVE_STATUS(gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]])) + else if (IsBattleMoveStatus(gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]])) gBattlescriptCurrInstr = cmd->failInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -10312,7 +10313,7 @@ static void Cmd_various(void) gSpecialStatuses[gBattlerTarget].neutralizingGasRemoved = TRUE; gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = ABILITY_SIMPLE; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = ABILITY_SIMPLE; gBattlescriptCurrInstr = cmd->nextInstr; } return; @@ -10340,7 +10341,7 @@ static void Cmd_various(void) } else { - gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = gBattleMons[gBattlerAttacker].ability; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gBattleMons[gBattlerAttacker].ability; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -10368,12 +10369,12 @@ static void Cmd_various(void) { VARIOUS_ARGS(const u8 *failInstr); u16 move = gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]; - if (IS_MOVE_STATUS(move) || gMovesInfo[move].meFirstBanned + if (IsBattleMoveStatus(move) || IsMoveMeFirstBanned(move) || GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)) gBattlescriptCurrInstr = cmd->failInstr; else { - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(move)) + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move)) { gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move; gCalledMove = GetTypeBasedZMove(move); @@ -10383,7 +10384,7 @@ static void Cmd_various(void) gCalledMove = move; } gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gStatuses3[gBattlerAttacker] |= STATUS3_ME_FIRST; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -10417,15 +10418,16 @@ static void Cmd_various(void) VARIOUS_ARGS(const u8 *failInstr); u32 types[3]; GetBattlerTypes(gBattlerTarget, FALSE, types); - if ((types[0] == gMovesInfo[gCurrentMove].type && types[1] == gMovesInfo[gCurrentMove].type) + u32 moveType = GetMoveType(gCurrentMove); + if ((types[0] == moveType && types[1] == moveType) || GetActiveGimmick(gBattlerTarget) == GIMMICK_TERA) { gBattlescriptCurrInstr = cmd->failInstr; } else { - SET_BATTLER_TYPE(gBattlerTarget, gMovesInfo[gCurrentMove].type); - PREPARE_TYPE_BUFFER(gBattleTextBuff1, gMovesInfo[gCurrentMove].type); + SET_BATTLER_TYPE(gBattlerTarget, moveType); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType); gBattlescriptCurrInstr = cmd->nextInstr; } return; @@ -10448,7 +10450,7 @@ static void Cmd_various(void) // Change stats. else if (cmd->case_ == 1) { - RecalcBattlerStats(battler, mon); + RecalcBattlerStats(battler, mon, FALSE); } // Update healthbox. else @@ -10470,7 +10472,7 @@ static void Cmd_various(void) case VARIOUS_SET_ARG_TO_BATTLE_DAMAGE: { VARIOUS_ARGS(); - gBattleStruct->moveDamage[gBattlerTarget] = gMovesInfo[gCurrentMove].argument.fixedDamage; + gBattleStruct->moveDamage[gBattlerTarget] = GetMoveFixedDamage(gCurrentMove); break; } case VARIOUS_TRY_AUTOTOMIZE: @@ -10492,8 +10494,8 @@ static void Cmd_various(void) VARIOUS_ARGS(const u8 *failInstr); u16 move = gLastPrintedMoves[gBattlerTarget]; if (move == MOVE_NONE || move == MOVE_UNAVAILABLE || MoveHasAdditionalEffectSelf(move, MOVE_EFFECT_RECHARGE) - || gMovesInfo[move].instructBanned - || gBattleMoveEffects[gMovesInfo[move].effect].twoTurnEffect + || IsMoveInstructBanned(move) + || gBattleMoveEffects[GetMoveEffect(move)].twoTurnEffect || (GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX) || IsZMove(move) || IsMaxMove(move)) @@ -10675,6 +10677,7 @@ static void Cmd_various(void) { gBattlerSpriteIds[BATTLE_PARTNER(battler)] = gBattleScripting.savedDmg >> 8; gBattlerSpriteIds[battler] = gBattleScripting.savedDmg & 0xFF; + gBattleScripting.savedDmg = 0; if (IsBattlerAlive(battler)) { SetBattlerShadowSpriteCallback(battler, gBattleMons[battler].species); @@ -10742,14 +10745,15 @@ static void Cmd_various(void) case VARIOUS_TRY_THIRD_TYPE: { VARIOUS_ARGS(const u8 *failInstr); - if (IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument.type) || GetActiveGimmick(battler) == GIMMICK_TERA) + u32 type = GetMoveArgType(gCurrentMove); + if (IS_BATTLER_OF_TYPE(battler, type) || GetActiveGimmick(battler) == GIMMICK_TERA) { gBattlescriptCurrInstr = cmd->failInstr; } else { - gBattleMons[battler].types[2] = gMovesInfo[gCurrentMove].argument.type; - PREPARE_TYPE_BUFFER(gBattleTextBuff1, gMovesInfo[gCurrentMove].argument.type); + gBattleMons[battler].types[2] = type; + PREPARE_TYPE_BUFFER(gBattleTextBuff1, type); gBattlescriptCurrInstr = cmd->nextInstr; } return; @@ -11102,7 +11106,7 @@ static void Cmd_various(void) case VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL: { VARIOUS_ARGS(const u8 *jumpInstr); - if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) == SPECIES_NONE) + if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) == gBattleMons[battler].species) gBattlescriptCurrInstr = cmd->jumpInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -11302,44 +11306,6 @@ static void Cmd_various(void) gBattleMons[battler].item = gLastUsedItem; break; } - case VARIOUS_SWAP_SIDE_STATUSES: - { - VARIOUS_ARGS(); - CourtChangeSwapSideStatuses(); - break; - } - case VARIOUS_SWAP_STATS: - { - VARIOUS_ARGS(u8 stat); - - u8 stat = cmd->stat; - u16 temp; - - switch (stat) - { - case STAT_HP: - SWAP(gBattleMons[gBattlerAttacker].hp, gBattleMons[gBattlerTarget].hp, temp); - break; - case STAT_ATK: - SWAP(gBattleMons[gBattlerAttacker].attack, gBattleMons[gBattlerTarget].attack, temp); - break; - case STAT_DEF: - SWAP(gBattleMons[gBattlerAttacker].defense, gBattleMons[gBattlerTarget].defense, temp); - break; - case STAT_SPEED: - SWAP(gBattleMons[gBattlerAttacker].speed, gBattleMons[gBattlerTarget].speed, temp); - break; - case STAT_SPATK: - SWAP(gBattleMons[gBattlerAttacker].spAttack, gBattleMons[gBattlerTarget].spAttack, temp); - break; - case STAT_SPDEF: - SWAP(gBattleMons[gBattlerAttacker].spDefense, gBattleMons[gBattlerTarget].spDefense, temp); - break; - } - PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); - gBattlescriptCurrInstr = cmd->nextInstr; - return; - } } // End of switch (cmd->id) gBattlescriptCurrInstr = cmd->nextInstr; @@ -11348,9 +11314,10 @@ static void Cmd_various(void) static void TryResetProtectUseCounter(u32 battler) { u32 lastMove = gLastResultingMoves[battler]; + u32 lastEffect = GetMoveEffect(lastMove); if (lastMove == MOVE_UNAVAILABLE - || (!gBattleMoveEffects[gMovesInfo[lastMove].effect].usesProtectCounter - && (B_ALLY_SWITCH_FAIL_CHANCE >= GEN_9 && gMovesInfo[lastMove].effect != EFFECT_ALLY_SWITCH))) + || (!gBattleMoveEffects[lastEffect].usesProtectCounter + && (B_ALLY_SWITCH_FAIL_CHANCE >= GEN_9 && lastEffect != EFFECT_ALLY_SWITCH))) gDisableStructs[battler].protectUses = 0; } @@ -11369,9 +11336,9 @@ static void Cmd_setprotectlike(void) || (gCurrentMove == MOVE_WIDE_GUARD && B_WIDE_GUARD != GEN_5) || (gCurrentMove == MOVE_QUICK_GUARD && B_QUICK_GUARD != GEN_5)) { - if (!gMovesInfo[gCurrentMove].argument.protect.side) // Protects one mon only. + if (!GetMoveProtectSide(gCurrentMove)) // Protects one mon only. { - if (gMovesInfo[gCurrentMove].effect == EFFECT_ENDURE) + if (GetMoveEffect(gCurrentMove) == EFFECT_ENDURE) { gProtectStructs[gBattlerAttacker].endured = TRUE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_BRACED_ITSELF; @@ -11534,7 +11501,7 @@ static void SetMoveForMirrorMove(u32 move) { gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; // Edge case, we used Z Mirror Move, got the stat boost and now need to use the Z-move - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(move)) + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(move)) { gBattleStruct->zmove.baseMoves[gBattlerAttacker] = move; gCurrentMove = GetTypeBasedZMove(move); @@ -11545,8 +11512,8 @@ static void SetMoveForMirrorMove(u32 move) } SetAtkCancellerForCalledMove(); - gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - gBattlescriptCurrInstr = GET_MOVE_BATTLESCRIPT(gCurrentMove); + gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove); } static void Cmd_trymirrormove(void) @@ -11589,9 +11556,9 @@ static void Cmd_setfieldweather(void) { CMD_ARGS(u8 weather); - u8 weather = cmd->weather; + u8 battleWeatherId = cmd->weather; - if (!TryChangeBattleWeather(gBattlerAttacker, weather, FALSE)) + if (!TryChangeBattleWeather(gBattlerAttacker, battleWeatherId, FALSE)) { gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; @@ -11599,21 +11566,21 @@ static void Cmd_setfieldweather(void) return; } - switch (weather) + switch (battleWeatherId) { - case ENUM_WEATHER_RAIN: + case BATTLE_WEATHER_RAIN: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_RAIN; break; - case ENUM_WEATHER_SUN: + case BATTLE_WEATHER_SUN: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SUNLIGHT; break; - case ENUM_WEATHER_SANDSTORM: + case BATTLE_WEATHER_SANDSTORM: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SANDSTORM; break; - case ENUM_WEATHER_HAIL: + case BATTLE_WEATHER_HAIL: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_HAIL; break; - case ENUM_WEATHER_SNOW: + case BATTLE_WEATHER_SNOW: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SNOW; break; } @@ -11926,10 +11893,7 @@ static void Cmd_setdrainedhp(void) { CMD_ARGS(); - if (gMovesInfo[gCurrentMove].argument.absorbPercentage != 0) - gBattleStruct->moveDamage[gBattlerAttacker] = (gHpDealt * gMovesInfo[gCurrentMove].argument.absorbPercentage / 100); - else - gBattleStruct->moveDamage[gBattlerAttacker] = (gHpDealt / 2); + gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100); if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) gBattleStruct->moveDamage[gBattlerAttacker] = 1; @@ -12347,7 +12311,7 @@ static void Cmd_twoturnmoveschargestringandanimation(void) { CMD_ARGS(const u8 *animationThenStringPtr); - gBattleScripting.savedStringId = gMovesInfo[gCurrentMove].argument.twoTurnAttack.stringId; + gBattleScripting.savedStringId = GetMoveTwoTurnAttackStringId(gCurrentMove); if (B_UPDATED_MOVE_DATA < GEN_5 || MoveHasChargeTurnAdditionalEffect(gCurrentMove)) gBattlescriptCurrInstr = cmd->animationThenStringPtr; else @@ -12526,7 +12490,7 @@ static void Cmd_forcerandomswitch(void) { *(gBattleStruct->battlerPartyIndexes + gBattlerTarget) = gBattlerPartyIndexes[gBattlerTarget]; gBattlescriptCurrInstr = BattleScript_RoarSuccessSwitch; - gBattleStruct->forcedSwitch |= 1u << gBattlerTarget; + gBattleStruct->battlerState[gBattlerTarget].forcedSwitch = TRUE; *(gBattleStruct->monToSwitchIntoId + gBattlerTarget) = validMons[RandomUniform(RNG_FORCE_RANDOM_SWITCH, 0, validMonsCount - 1)]; if (!IsMultiBattle()) @@ -12576,7 +12540,7 @@ static void Cmd_tryconversiontypechange(void) { if (gBattleMons[gBattlerAttacker].moves[moveChecked] != MOVE_NONE) { - moveType = gMovesInfo[gBattleMons[gBattlerAttacker].moves[moveChecked]].type; + moveType = GetMoveType(gBattleMons[gBattlerAttacker].moves[moveChecked]); break; } } @@ -12604,7 +12568,7 @@ static void Cmd_tryconversiontypechange(void) for (moveChecked = 0; moveChecked < validMoves; moveChecked++) { - moveType = gMovesInfo[gBattleMons[gBattlerAttacker].moves[moveChecked]].type; + moveType = GetMoveType(gBattleMons[gBattlerAttacker].moves[moveChecked]); if (moveType == TYPE_MYSTERY) { @@ -12631,7 +12595,7 @@ static void Cmd_tryconversiontypechange(void) { while ((moveChecked = MOD(Random(), MAX_MON_MOVES)) >= validMoves); - moveType = gMovesInfo[gBattleMons[gBattlerAttacker].moves[moveChecked]].type; + moveType = GetMoveType(gBattleMons[gBattlerAttacker].moves[moveChecked]); if (moveType == TYPE_MYSTERY) { @@ -12747,7 +12711,7 @@ static void Cmd_tryKO(void) } else { - u16 odds = gMovesInfo[gCurrentMove].accuracy + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level); + u16 odds = GetMoveAccuracy(gCurrentMove) + (gBattleMons[gBattlerAttacker].level - gBattleMons[gBattlerTarget].level); if (B_SHEER_COLD_ACC >= GEN_7 && gCurrentMove == MOVE_SHEER_COLD && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ICE)) odds -= 10; if (RandomPercentage(RNG_ACCURACY, odds) && gBattleMons[gBattlerAttacker].level >= gBattleMons[gBattlerTarget].level) @@ -12910,14 +12874,15 @@ static void Cmd_setfocusenergy(void) { CMD_ARGS(u8 battler); u8 battler = GetBattlerForBattleScript(cmd->battler); + u32 effect = GetMoveEffect(gCurrentMove); - if ((gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && (!(IsDoubleBattle()) || (gAbsentBattlerFlags & (1u << battler)))) + if ((effect == EFFECT_DRAGON_CHEER && (!(IsDoubleBattle()) || (gAbsentBattlerFlags & (1u << battler)))) || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) { gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_FAILED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FOCUS_ENERGY_FAILED; } - else if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && !IS_BATTLER_OF_TYPE(battler, TYPE_DRAGON)) + else if (effect == EFFECT_DRAGON_CHEER && !IS_BATTLER_OF_TYPE(battler, TYPE_DRAGON)) { gBattleMons[battler].status2 |= STATUS2_DRAGON_CHEER; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED; @@ -12968,11 +12933,12 @@ static void Cmd_transformdataexecution(void) for (i = 0; i < offsetof(struct BattlePokemon, pp); i++) battleMonAttacker[i] = battleMonTarget[i]; - gBattleStruct->overwrittenAbilities[gBattlerAttacker] = GetBattlerAbility(gBattlerTarget); + gDisableStructs[gBattlerAttacker].overwrittenAbility = GetBattlerAbility(gBattlerTarget); for (i = 0; i < MAX_MON_MOVES; i++) { - if (gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].pp < 5) - gBattleMons[gBattlerAttacker].pp[i] = gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].pp; + u32 pp = GetMovePP(gBattleMons[gBattlerAttacker].moves[i]); + if (pp < 5) + gBattleMons[gBattlerAttacker].pp[i] = pp; else gBattleMons[gBattlerAttacker].pp[i] = 5; } @@ -12991,7 +12957,7 @@ static void Cmd_setsubstitute(void) { CMD_ARGS(); - u32 factor = gMovesInfo[gCurrentMove].effect == EFFECT_SHED_TAIL ? 2 : 4; + u32 factor = GetMoveEffect(gCurrentMove) == EFFECT_SHED_TAIL ? 2 : 4; u32 hp; if (factor == 2) @@ -13030,7 +12996,7 @@ static void Cmd_mimicattackcopy(void) { CMD_ARGS(const u8 *failInstr); - if ((gMovesInfo[gLastMoves[gBattlerTarget]].mimicBanned) + if ((IsMoveMimicBanned(gLastMoves[gBattlerTarget])) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED) || gLastMoves[gBattlerTarget] == MOVE_NONE || gLastMoves[gBattlerTarget] == MOVE_UNAVAILABLE) @@ -13051,8 +13017,9 @@ static void Cmd_mimicattackcopy(void) { gChosenMove = 0xFFFF; gBattleMons[gBattlerAttacker].moves[gCurrMovePos] = gLastMoves[gBattlerTarget]; - if (gMovesInfo[gLastMoves[gBattlerTarget]].pp < 5) - gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = gMovesInfo[gLastMoves[gBattlerTarget]].pp; + u32 pp = GetMovePP(gLastMoves[gBattlerTarget]); + if (pp < 5) + gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = pp; else gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = 5; @@ -13070,8 +13037,8 @@ static void Cmd_mimicattackcopy(void) static bool32 InvalidMetronomeMove(u32 move) { - return gMovesInfo[move].effect == EFFECT_PLACEHOLDER - || gMovesInfo[move].metronomeBanned; + return GetMoveEffect(move) == EFFECT_PLACEHOLDER + || IsMoveMetronomeBanned(move); } static void Cmd_metronome(void) @@ -13101,8 +13068,8 @@ static void Cmd_metronome(void) gCurrentMove = RandomUniformExcept(RNG_METRONOME, 1, moveCount - 1, InvalidMetronomeMove); SetAtkCancellerForCalledMove(); PrepareStringBattle(STRINGID_WAGGLINGAFINGER, gBattlerAttacker); - gBattlescriptCurrInstr = GET_MOVE_BATTLESCRIPT(gCurrentMove); - gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove); + gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); } static void Cmd_dmgtolevel(void) @@ -13229,7 +13196,7 @@ static void Cmd_trysetencore(void) } } - if ((gMovesInfo[gLastMoves[gBattlerTarget]].encoreBanned) + if ((IsMoveEncoreBanned(gLastMoves[gBattlerTarget])) || gLastMoves[gBattlerTarget] == MOVE_NONE || gLastMoves[gBattlerTarget] == MOVE_UNAVAILABLE) { @@ -13265,7 +13232,6 @@ static void Cmd_painsplitdmgcalc(void) gBattleStruct->moveDamage[gBattlerTarget] = GetNonDynamaxHP(gBattlerTarget) - hpDiff; gBattleStruct->moveDamage[gBattlerAttacker] = gBattleMons[gBattlerAttacker].hp - hpDiff; - gSpecialStatuses[gBattlerTarget].shellBellDmg = IGNORE_SHELL_BELL; gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -13288,7 +13254,7 @@ static void Cmd_settypetorandomresistance(void) { gBattlescriptCurrInstr = cmd->failInstr; } - else if (gBattleMoveEffects[gMovesInfo[gLastLandedMoves[gBattlerAttacker]].effect].twoTurnEffect + else if (gBattleMoveEffects[GetMoveEffect(gLastLandedMoves[gBattlerAttacker])].twoTurnEffect && gBattleMons[gLastHitBy[gBattlerAttacker]].status2 & STATUS2_MULTIPLETURNS) { gBattlescriptCurrInstr = cmd->failInstr; @@ -13417,7 +13383,7 @@ static void Cmd_copymovepermanently(void) if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_TRANSFORMED) && gLastPrintedMoves[gBattlerTarget] != MOVE_UNAVAILABLE - && !gMovesInfo[gLastPrintedMoves[gBattlerTarget]].sketchBanned) + && !IsMoveSketchBanned(gLastPrintedMoves[gBattlerTarget])) { s32 i; @@ -13438,7 +13404,7 @@ static void Cmd_copymovepermanently(void) struct MovePpInfo movePpData; gBattleMons[gBattlerAttacker].moves[gCurrMovePos] = gLastPrintedMoves[gBattlerTarget]; - gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = gMovesInfo[gLastPrintedMoves[gBattlerTarget]].pp; + gBattleMons[gBattlerAttacker].pp[gCurrMovePos] = GetMovePP(gLastPrintedMoves[gBattlerTarget]); for (i = 0; i < MAX_MON_MOVES; i++) { @@ -13469,8 +13435,8 @@ static void Cmd_trychoosesleeptalkmove(void) for (i = 0; i < MAX_MON_MOVES; i++) { - if (gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].sleepTalkBanned - || gBattleMoveEffects[gMovesInfo[gBattleMons[gBattlerAttacker].moves[i]].effect].twoTurnEffect) + if (IsMoveSleepTalkBanned(gBattleMons[gBattlerAttacker].moves[i]) + || gBattleMoveEffects[GetMoveEffect(gBattleMons[gBattlerAttacker].moves[i])].twoTurnEffect) { unusableMovesBits |= (1 << (i)); } @@ -13490,7 +13456,7 @@ static void Cmd_trychoosesleeptalkmove(void) movePosition = MOD(Random(), MAX_MON_MOVES); } while ((1u << movePosition) & unusableMovesBits); - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(gBattleMons[gBattlerAttacker].moves[movePosition])) + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gBattleMons[gBattlerAttacker].moves[movePosition])) { gBattleStruct->zmove.baseMoves[gBattlerAttacker] = gBattleMons[gBattlerAttacker].moves[movePosition]; gCalledMove = GetTypeBasedZMove(gBattleMons[gBattlerAttacker].moves[movePosition]); @@ -13501,7 +13467,7 @@ static void Cmd_trychoosesleeptalkmove(void) } gCurrMovePos = movePosition; gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gBattlescriptCurrInstr = cmd->failInstr; } } @@ -13590,7 +13556,7 @@ static void Cmd_tryspiteppreduce(void) { s32 ppToDeduct = B_PP_REDUCED_BY_SPITE >= GEN_4 ? 4 : (Random() & 3) + 2; // G-Max Depletion only deducts 2 PP. - if (IsMaxMove(gCurrentMove) && gMovesInfo[gCurrentMove].argument.maxEffect == MAX_EFFECT_SPITE) + if (IsMaxMove(gCurrentMove) && GetMoveMaxEffect(gCurrentMove) == MAX_EFFECT_SPITE) ppToDeduct = 2; if (gBattleMons[gBattlerTarget].pp[i] < ppToDeduct) @@ -14034,7 +14000,7 @@ static bool32 SetTargetToNextPursuiter(u32 battlerDef) { u32 battler = gBattlerByTurnOrder[i]; if (gChosenActionByBattler[battler] == B_ACTION_USE_MOVE - && gMovesInfo[gChosenMoveByBattler[battler]].effect == EFFECT_PURSUIT + && GetMoveEffect(gChosenMoveByBattler[battler]) == EFFECT_PURSUIT && IsBattlerAlive(battlerDef) && IsBattlerAlive(battler) && GetBattlerSide(battler) != GetBattlerSide(battlerDef) @@ -14059,7 +14025,7 @@ static void Cmd_jumpifnopursuitswitchdmg(void) if (SetTargetToNextPursuiter(gBattlerAttacker)) { ChangeOrderTargetAfterAttacker(); - gBattleStruct->pursuitTarget = 1u << gBattlerAttacker; + gBattleStruct->battlerState[gBattlerAttacker].pursuitTarget = TRUE; gBattleStruct->pursuitSwitchByMove = gActionsByTurnOrder[gCurrentTurnActionNumber] == B_ACTION_USE_MOVE; gBattleStruct->pursuitStoredSwitch = gBattleStruct->monToSwitchIntoId[gBattlerAttacker]; *(gBattleStruct->moveTarget + gBattlerTarget) = gBattlerAttacker; @@ -14315,7 +14281,7 @@ static void Cmd_trydobeatup(void) gBattlescriptCurrInstr = cmd->nextInstr; gBattleStruct->moveDamage[gBattlerTarget] = gSpeciesInfo[GetMonData(&party[gBattleCommunication[0]], MON_DATA_SPECIES)].baseAttack; - gBattleStruct->moveDamage[gBattlerTarget] *= gMovesInfo[gCurrentMove].power; + gBattleStruct->moveDamage[gBattlerTarget] *= GetMovePower(gCurrentMove); gBattleStruct->moveDamage[gBattlerTarget] *= (GetMonData(&party[gBattleCommunication[0]], MON_DATA_LEVEL) * 2 / 5 + 2); gBattleStruct->moveDamage[gBattlerTarget] /= gSpeciesInfo[gBattleMons[gBattlerTarget].species].baseDefense; gBattleStruct->moveDamage[gBattlerTarget] = (gBattleStruct->moveDamage[gBattlerTarget] / 50) + 2; @@ -14340,9 +14306,9 @@ static void Cmd_setsemiinvulnerablebit(void) { CMD_ARGS(bool8 clear); - if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == TRUE) + if (gBattleMoveEffects[GetMoveEffect(gCurrentMove)].semiInvulnerableEffect == TRUE) { - u32 semiInvulnerableEffect = UNCOMPRESS_BITS(gMovesInfo[gCurrentMove].argument.twoTurnAttack.status); + u32 semiInvulnerableEffect = GetMoveTwoTurnAttackStatus(gCurrentMove); if (cmd->clear) gStatuses3[gBattlerAttacker] &= ~semiInvulnerableEffect; else @@ -14355,7 +14321,7 @@ static void Cmd_setsemiinvulnerablebit(void) static bool32 CheckIfCanFireTwoTurnMoveNow(u8 battler, bool8 checkChargeTurnEffects) { // Semi-invulnerable moves cannot skip their charge turn (except with Power Herb) - if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == TRUE) + if (gBattleMoveEffects[GetMoveEffect(gCurrentMove)].semiInvulnerableEffect == TRUE) return FALSE; // If this move has charge turn effects, it must charge, activate them, then try to fire @@ -14366,7 +14332,7 @@ static bool32 CheckIfCanFireTwoTurnMoveNow(u8 battler, bool8 checkChargeTurnEffe // Certain two-turn moves may fire on the first turn in the right weather (Solar Beam, Electro Shot) // By default, all two-turn moves have the option of adding weather to their argument - if (IsBattlerWeatherAffected(battler, gMovesInfo[gCurrentMove].argument.twoTurnAttack.status)) + if (IsBattlerWeatherAffected(battler, GetMoveTwoTurnAttackWeather(gCurrentMove))) return TRUE; return FALSE; @@ -14437,7 +14403,7 @@ static void Cmd_setforcedtarget(void) gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer = 1; gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTarget = gBattlerTarget; - gSideTimers[GetBattlerSide(gBattlerTarget)].followmePowder = gMovesInfo[gCurrentMove].powderMove; + gSideTimers[GetBattlerSide(gBattlerTarget)].followmePowder = IsPowderMove(gCurrentMove); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -14462,8 +14428,8 @@ static void Cmd_callterrainattack(void) gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; gCurrentMove = GetNaturePowerMove(gBattlerAttacker); - gBattlerTarget = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); - BattleScriptPush(GET_MOVE_BATTLESCRIPT(gCurrentMove)); + gBattlerTarget = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + BattleScriptPush(GetMoveBattleScript(gCurrentMove)); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -14495,7 +14461,7 @@ static void Cmd_curestatuswithmove(void) CMD_ARGS(const u8 *failInstr); u32 shouldHeal; - if (gMovesInfo[gCurrentMove].effect == EFFECT_REFRESH) + if (GetMoveEffect(gCurrentMove) == EFFECT_REFRESH) shouldHeal = gBattleMons[gBattlerAttacker].status1 & STATUS1_REFRESH; else // Take Heart shouldHeal = gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY; @@ -14695,8 +14661,8 @@ static void Cmd_tryswapitems(void) } else if (oldItemAtk == ITEM_NONE && *newItemAtk != ITEM_NONE) { - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gBattleResources->flags->flags[gBattlerAttacker] & RESOURCE_FLAG_UNBURDEN) - gBattleResources->flags->flags[gBattlerAttacker] &= ~RESOURCE_FLAG_UNBURDEN; + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gDisableStructs[gBattlerAttacker].unbrudenActive) + gDisableStructs[gBattlerAttacker].unbrudenActive = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_TAKEN; // nothing -> <- target's item } @@ -14720,7 +14686,7 @@ static void Cmd_trycopyability(void) if (gBattleMons[battler].ability == defAbility || defAbility == ABILITY_NONE || gAbilitiesInfo[gBattleMons[battler].ability].cantBeSuppressed - || (IsBattlerAlive(BATTLE_PARTNER(battler)) && gAbilitiesInfo[gBattleMons[BATTLE_PARTNER(battler)].ability].cantBeSuppressed && gMovesInfo[gCurrentMove].effect == EFFECT_DOODLE) + || (IsBattlerAlive(BATTLE_PARTNER(battler)) && gAbilitiesInfo[gBattleMons[BATTLE_PARTNER(battler)].ability].cantBeSuppressed && GetMoveEffect(gCurrentMove) == EFFECT_DOODLE) || gAbilitiesInfo[defAbility].cantBeCopied) { gBattlescriptCurrInstr = cmd->failInstr; @@ -14728,7 +14694,7 @@ static void Cmd_trycopyability(void) else { gBattleScripting.abilityPopupOverwrite = gBattleMons[battler].ability; - gBattleMons[battler].ability = gBattleStruct->overwrittenAbilities[battler] = defAbility; + gBattleMons[battler].ability = gDisableStructs[battler].overwrittenAbility = defAbility; gLastUsedAbility = defAbility; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -14874,7 +14840,7 @@ static void Cmd_setroom(void) { CMD_ARGS(); - switch (gMovesInfo[gCurrentMove].effect) + switch (GetMoveEffect(gCurrentMove)) { case EFFECT_TRICK_ROOM: HandleRoomMove(STATUS_FIELD_TRICK_ROOM, &gFieldTimers.trickRoomTimer, 0); @@ -14919,8 +14885,8 @@ static void Cmd_tryswapabilities(void) if (GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerAttacker].ability; gLastUsedAbility = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = gBattleMons[gBattlerAttacker].ability; - gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gLastUsedAbility; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gBattleMons[gBattlerAttacker].ability; + gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gLastUsedAbility; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -15039,7 +15005,7 @@ static void Cmd_assistattackselect(void) { u16 move = GetMonData(&party[monId], MON_DATA_MOVE1 + moveId); - if (gMovesInfo[move].assistBanned) + if (IsMoveAssistBanned(move)) continue; validMoves[chooseableMovesNo++] = move; @@ -15051,7 +15017,7 @@ static void Cmd_assistattackselect(void) { gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; gCalledMove = validMoves[Random() % chooseableMovesNo]; - gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gBattlescriptCurrInstr = cmd->nextInstr; } else @@ -15160,8 +15126,9 @@ static void Cmd_jumpifnotcurrentmoveargtype(void) u8 battler = GetBattlerForBattleScript(cmd->battler); const u8 *failInstr = cmd->failInstr; + u32 type = GetMoveArgType(gCurrentMove); - if (!IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument.type)) + if (!IS_BATTLER_OF_TYPE(battler, type)) gBattlescriptCurrInstr = failInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -15255,7 +15222,7 @@ static void Cmd_settypebasedhalvers(void) bool8 worked = FALSE; - if (gMovesInfo[gCurrentMove].effect == EFFECT_MUD_SPORT) + if (GetMoveEffect(gCurrentMove) == EFFECT_MUD_SPORT) { if (B_SPORT_TURNS >= GEN_6) { @@ -15310,7 +15277,7 @@ bool32 DoesSubstituteBlockMove(u32 battlerAtk, u32 battlerDef, u32 move) { if (!(gBattleMons[battlerDef].status2 & STATUS2_SUBSTITUTE)) return FALSE; - else if (gMovesInfo[move].ignoresSubstitute) + else if (MoveIgnoresSubstitute(move)) return FALSE; else if (GetBattlerAbility(battlerAtk) == ABILITY_INFILTRATOR) return FALSE; @@ -15322,7 +15289,7 @@ bool32 DoesDisguiseBlockMove(u32 battler, u32 move) { if (!(gBattleMons[battler].species == SPECIES_MIMIKYU_DISGUISED || gBattleMons[battler].species == SPECIES_MIMIKYU_TOTEM_DISGUISED) || gBattleMons[battler].status2 & STATUS2_TRANSFORMED - || (!gProtectStructs[battler].confusionSelfDmg && (IS_MOVE_STATUS(move) || gHitMarker & HITMARKER_PASSIVE_DAMAGE)) + || (!gProtectStructs[battler].confusionSelfDmg && (IsBattleMoveStatus(move) || gHitMarker & HITMARKER_PASSIVE_DAMAGE)) || gHitMarker & HITMARKER_IGNORE_DISGUISE || GetBattlerAbility(battler) != ABILITY_DISGUISE) return FALSE; @@ -15421,7 +15388,7 @@ static void Cmd_pursuitdoubles(void) if (IsDoubleBattle() && !(gAbsentBattlerFlags & (1u << battler)) && gChosenActionByBattler[battler] == B_ACTION_USE_MOVE - && gMovesInfo[gChosenMoveByBattler[battler]].effect == EFFECT_PURSUIT) + && GetMoveEffect(gChosenMoveByBattler[battler]) == EFFECT_PURSUIT) { gActionsByTurnOrder[battler] = B_ACTION_TRY_FINISH; gCurrentMove = gChosenMoveByBattler[battler]; @@ -16228,7 +16195,7 @@ static void Cmd_tryworryseed(void) else { gBattleScripting.abilityPopupOverwrite = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = ABILITY_INSOMNIA; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = ABILITY_INSOMNIA; gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -16431,10 +16398,10 @@ static bool32 CriticalCapture(u32 odds) bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler) { if (move != MOVE_NONE && move != MOVE_UNAVAILABLE && move != MOVE_STRUGGLE - && !gMovesInfo[move].parentalBondBanned - && gMovesInfo[move].category != DAMAGE_CATEGORY_STATUS - && gMovesInfo[move].strikeCount < 2 - && gMovesInfo[move].effect != EFFECT_MULTI_HIT) + && !IsMoveParentalBondBanned(move) + && GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS + && GetMoveStrikeCount(move) < 2 + && GetMoveEffect(move) != EFFECT_MULTI_HIT) { if (IsDoubleBattle()) { @@ -16489,9 +16456,11 @@ static bool8 CanBurnHitThaw(u16 move) if (B_BURN_HIT_THAW >= GEN_6) { - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); + for (i = 0; i < numAdditionalEffects; i++) { - if (gMovesInfo[move].additionalEffects[i].moveEffect == MOVE_EFFECT_BURN) + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); + if (additionalEffect->moveEffect == MOVE_EFFECT_BURN) return TRUE; } } @@ -16920,11 +16889,20 @@ void BS_JumpIfElectricAbilityAffected(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfArgument(void) +void BS_ApplySaltCure(void) +{ + NATIVE_ARGS(u8 battler); + + u8 battler = GetBattlerForBattleScript(cmd->battler); + gStatuses4[battler] |= STATUS4_SALT_CURE; + gBattlescriptCurrInstr = cmd->nextInstr; +} + +void BS_JumpIfMovePropertyArgument(void) { NATIVE_ARGS(u8 argument, const u8 *jumpInstr); - if (gMovesInfo[gCurrentMove].argument.moveProperty == cmd->argument) + if (GetMoveEffectArg_MoveProperty(gCurrentMove) == cmd->argument) gBattlescriptCurrInstr = cmd->jumpInstr; else gBattlescriptCurrInstr = cmd->nextInstr; @@ -16935,7 +16913,7 @@ void BS_SetRemoveTerrain(void) NATIVE_ARGS(const u8 *jumpInstr); u32 statusFlag = 0; - switch (gMovesInfo[gCurrentMove].effect) + switch (GetMoveEffect(gCurrentMove)) { case EFFECT_MISTY_TERRAIN: statusFlag = STATUS_FIELD_MISTY_TERRAIN; @@ -16954,7 +16932,7 @@ void BS_SetRemoveTerrain(void) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; break; case EFFECT_HIT_SET_REMOVE_TERRAIN: - switch (gMovesInfo[gCurrentMove].argument.moveProperty) + switch (GetMoveEffectArg_MoveProperty(gCurrentMove)) { case ARG_SET_PSYCHIC_TERRAIN: // Genesis Supernova statusFlag = STATUS_FIELD_PSYCHIC_TERRAIN; @@ -16988,7 +16966,7 @@ void BS_SetRemoveTerrain(void) { u32 atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE); - gFieldStatuses &= ~(STATUS_FIELD_TERRAIN_ANY | STATUS_FIELD_TERRAIN_PERMANENT); + gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; gFieldStatuses |= statusFlag; gFieldTimers.terrainTimer = (atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) ? 8 : 5; gBattlescriptCurrInstr = cmd->nextInstr; @@ -17143,7 +17121,7 @@ void BS_SetPledge(void) && GetBattlerTurnOrderNum(gBattlerAttacker) < GetBattlerTurnOrderNum(partner) && !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) && gCurrentMove != partnerMove - && gMovesInfo[partnerMove].effect == EFFECT_PLEDGE) + && GetMoveEffect(partnerMove) == EFFECT_PLEDGE) { u32 currPledgeUser = 0; u32 newTurnOrder[] = {0xFF, 0xFF}; @@ -17269,9 +17247,9 @@ void BS_TryHealPulse(void) } else { - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MEGA_LAUNCHER && gMovesInfo[gCurrentMove].pulseMove) + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_MEGA_LAUNCHER && IsPulseMove(gCurrentMove)) gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 75 / 100); - else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && gMovesInfo[gCurrentMove].argument.moveProperty == MOVE_EFFECT_FLORAL_HEALING) + else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && GetMoveEffectArg_MoveProperty(gCurrentMove) == MOVE_EFFECT_FLORAL_HEALING) gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) * 2 / 3); else gBattleStruct->moveDamage[gBattlerTarget] = -(GetNonDynamaxMaxHP(gBattlerTarget) / 2); @@ -17286,13 +17264,13 @@ void BS_TryCopycat(void) { NATIVE_ARGS(const u8 *failInstr); - if (gLastUsedMove == MOVE_NONE || gLastUsedMove == MOVE_UNAVAILABLE || gMovesInfo[gLastUsedMove].copycatBanned || IsZMove(gLastUsedMove)) + if (gLastUsedMove == MOVE_NONE || gLastUsedMove == MOVE_UNAVAILABLE || IsMoveCopycatBanned(gLastUsedMove) || IsZMove(gLastUsedMove)) { gBattlescriptCurrInstr = cmd->failInstr; } else { - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(gLastUsedMove)) + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gLastUsedMove)) { gBattleStruct->zmove.baseMoves[gBattlerAttacker] = gLastUsedMove; gCalledMove = GetTypeBasedZMove(gLastUsedMove); @@ -17307,7 +17285,7 @@ void BS_TryCopycat(void) } gHitMarker &= ~HITMARKER_ATTACKSTRING_PRINTED; - gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -17338,7 +17316,7 @@ void BS_TryUpperHand(void) if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget) || gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE - || IS_MOVE_STATUS(gChosenMoveByBattler[gBattlerTarget]) + || IsBattleMoveStatus(gChosenMoveByBattler[gBattlerTarget]) || GetChosenMovePriority(gBattlerTarget) < 1 || GetChosenMovePriority(gBattlerTarget) > 3) // Fails if priority is less than 1 or greater than 3, if target already moved, or if using a status gBattlescriptCurrInstr = cmd->failInstr; else @@ -17392,9 +17370,10 @@ void BS_AllySwitchFailChance(void) void BS_SetPhotonGeyserCategory(void) { NATIVE_ARGS(); - if (!((gMovesInfo[gCurrentMove].effect == EFFECT_TERA_BLAST && GetActiveGimmick(gBattlerAttacker) != GIMMICK_TERA) - || (gMovesInfo[gCurrentMove].effect == EFFECT_TERA_STARSTORM && GetActiveGimmick(gBattlerAttacker) != GIMMICK_TERA && gBattleMons[gBattlerAttacker].species == SPECIES_TERAPAGOS_STELLAR))) - gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) != gMovesInfo[gCurrentMove].category); + u32 effect = GetMoveEffect(gCurrentMove); + if (!((effect == EFFECT_TERA_BLAST && GetActiveGimmick(gBattlerAttacker) != GIMMICK_TERA) + || (effect == EFFECT_TERA_STARSTORM && GetActiveGimmick(gBattlerAttacker) != GIMMICK_TERA && gBattleMons[gBattlerAttacker].species == SPECIES_TERAPAGOS_STELLAR))) + gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) != GetMoveCategory(gCurrentMove)); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17644,11 +17623,11 @@ void BS_JumpIfSleepClause(void) // Can freely sleep own partner if (IsDoubleBattle() && IsSleepClauseEnabled() && GetBattlerSide(gBattlerAttacker) == GetBattlerSide(gBattlerTarget)) { - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerTarget); + gBattleStruct->battlerState[gBattlerTarget].sleepClauseEffectExempt = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; return; } - gBattleStruct->sleepClauseEffectExempt &= ~(1u << gBattlerTarget); + gBattleStruct->battlerState[gBattlerTarget].sleepClauseEffectExempt = FALSE; // Can't sleep if clause is active otherwise if (IsSleepClauseActiveForSide(GetBattlerSide(gBattlerTarget))) gBattlescriptCurrInstr = cmd->jumpInstr; @@ -17701,7 +17680,7 @@ void BS_JumpIfBlockedBySoundproof(void) { NATIVE_ARGS(u8 battler, const u8 *jumpInstr); u32 battler = GetBattlerForBattleScript(cmd->battler); - if (gMovesInfo[gCurrentMove].soundMove && GetBattlerAbility(battler) == ABILITY_SOUNDPROOF) + if (IsSoundMove(gCurrentMove) && GetBattlerAbility(battler) == ABILITY_SOUNDPROOF) { gLastUsedAbility = ABILITY_SOUNDPROOF; gBattlescriptCurrInstr = cmd->jumpInstr; @@ -17820,9 +17799,9 @@ void BS_StoreHealingWish(void) u32 battler = GetBattlerForBattleScript(cmd->battler); if (gCurrentMove == MOVE_LUNAR_DANCE) - gBattleStruct->storedLunarDance |= 1u << battler; + gBattleStruct->battlerState[battler].storedLunarDance = TRUE; else - gBattleStruct->storedHealingWish |= 1u << battler; + gBattleStruct->battlerState[battler].storedHealingWish = TRUE; gBattlescriptCurrInstr = cmd->nextInstr; } @@ -17996,3 +17975,35 @@ void BS_JumpIfCriticalHit(void) else gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_SwapStats(void) +{ + NATIVE_ARGS(u8 stat); + + u32 stat = cmd->stat; + u32 temp; + + switch (stat) + { + case STAT_HP: + SWAP(gBattleMons[gBattlerAttacker].hp, gBattleMons[gBattlerTarget].hp, temp); + break; + case STAT_ATK: + SWAP(gBattleMons[gBattlerAttacker].attack, gBattleMons[gBattlerTarget].attack, temp); + break; + case STAT_DEF: + SWAP(gBattleMons[gBattlerAttacker].defense, gBattleMons[gBattlerTarget].defense, temp); + break; + case STAT_SPEED: + SWAP(gBattleMons[gBattlerAttacker].speed, gBattleMons[gBattlerTarget].speed, temp); + break; + case STAT_SPATK: + SWAP(gBattleMons[gBattlerAttacker].spAttack, gBattleMons[gBattlerTarget].spAttack, temp); + break; + case STAT_SPDEF: + SWAP(gBattleMons[gBattlerAttacker].spDefense, gBattleMons[gBattlerTarget].spDefense, temp); + break; + } + PREPARE_STAT_BUFFER(gBattleTextBuff1, stat); + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_setup.c b/src/battle_setup.c index 0c13fcdd09ca..37204c1d8d80 100644 --- a/src/battle_setup.c +++ b/src/battle_setup.c @@ -1742,8 +1742,8 @@ static bool32 UpdateRandomTrainerRematches(const struct RematchTrainer *table, u for (i = 0; i <= REMATCH_SPECIAL_TRAINER_START; i++) { - if (DoesCurrentMapMatchRematchTrainerMap(i,table,mapGroup,mapNum) && !IsRematchForbidden(i)) - continue; + if (!DoesCurrentMapMatchRematchTrainerMap(i,table,mapGroup,mapNum) || IsRematchForbidden(i)) + continue; // Only check permitted trainers within the current map. if (gSaveBlock1Ptr->trainerRematches[i] != 0) { diff --git a/src/battle_tower.c b/src/battle_tower.c index 6f80823b9857..7fcdf1b8dd52 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -699,7 +699,7 @@ static const u8 *const *const sPartnerApprenticeTextTables[NUM_APPRENTICES] = #include "data/battle_frontier/battle_tent.h" #include "data/partner_parties.h" -const struct Trainer gBattlePartners[] = +const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT] = { #include "data/battle_partners.h" }; @@ -1355,6 +1355,7 @@ u8 GetFrontierTrainerFrontSpriteId(u16 trainerId) u8 GetFrontierOpponentClass(u16 trainerId) { u8 trainerClass = 0; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId); SetFacilityPtrsGetLevel(); #if FREE_BATTLE_TOWER_E_READER == FALSE @@ -1371,7 +1372,7 @@ u8 GetFrontierOpponentClass(u16 trainerId) } else if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) { - trainerClass = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass; + trainerClass = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass; } else if (trainerId < FRONTIER_TRAINERS_COUNT) { @@ -1441,6 +1442,7 @@ static u8 GetFrontierTrainerFacilityClass(u16 trainerId) void GetFrontierTrainerName(u8 *dst, u16 trainerId) { s32 i = 0; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId); SetFacilityPtrsGetLevel(); if (trainerId == TRAINER_EREADER) @@ -1457,8 +1459,8 @@ void GetFrontierTrainerName(u8 *dst, u16 trainerId) } else if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) { - for (i = 0; gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i] != EOS; i++) - dst[i] = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i]; + for (i = 0; gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i] != EOS; i++) + dst[i] = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName[i]; } else if (trainerId < FRONTIER_TRAINERS_COUNT) { @@ -1567,7 +1569,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 { u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; u16 move; - u32 personality, ability, friendship, j; + u32 personality = 0, ability, friendship, j; if (fmon->gender == TRAINER_MON_MALE) { @@ -1590,7 +1592,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 move = MOVE_FRUSTRATION; SetMonMoveSlot(dst, move, j); - if (gMovesInfo[move].effect == EFFECT_FRUSTRATION) + if (GetMoveEffect(move) == EFFECT_FRUSTRATION) friendship = 0; // Frustration is more powerful the lower the pokemon's friendship is. } @@ -1758,39 +1760,6 @@ static void FillTrainerParty(u16 trainerId, u8 firstMonId, u8 monCount) } } -// Probably an early draft before the 'CreateApprenticeMon' was written. -static void UNUSED Unused_CreateApprenticeMons(u16 trainerId, u8 firstMonId) -{ - s32 i, j; - u8 friendship = MAX_FRIENDSHIP; - u8 level = 0; - u8 fixedIV = 0; - struct Apprentice *apprentice = &gSaveBlock2Ptr->apprentices[0]; - - if (apprentice->numQuestions < 5) - fixedIV = 6; - else - fixedIV = 9; - - if (gSaveBlock2Ptr->frontier.lvlMode != FRONTIER_LVL_50) - level = FRONTIER_MAX_LEVEL_OPEN; - else - level = FRONTIER_MAX_LEVEL_50; - - for (i = 0; i != FRONTIER_PARTY_SIZE; i++) - { - CreateMonWithEVSpread(&gEnemyParty[firstMonId + i], apprentice->party[i].species, level, fixedIV, 8); - friendship = MAX_FRIENDSHIP; - for (j = 0; j < MAX_MON_MOVES; j++) - { - if (gMovesInfo[apprentice->party[i].moves[j]].effect == EFFECT_FRUSTRATION) - friendship = 0; - } - SetMonData(&gEnemyParty[firstMonId + i], MON_DATA_FRIENDSHIP, &friendship); - SetMonData(&gEnemyParty[firstMonId + i], MON_DATA_HELD_ITEM, &apprentice->party[i].item); - } -} - u16 GetRandomFrontierMonFromSet(u16 trainerId) { u8 level = SetFacilityPtrsGetLevel(); @@ -2998,6 +2967,7 @@ static void FillPartnerParty(u16 trainerId) u32 otID; u8 trainerName[(PLAYER_NAME_LENGTH * 3) + 1]; s32 ball = -1; + enum DifficultyLevel difficulty = GetBattlePartnerDifficultyLevel(trainerId); SetFacilityPtrsGetLevel(); if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) @@ -3005,10 +2975,10 @@ static void FillPartnerParty(u16 trainerId) for (i = 0; i < 3; i++) ZeroMonData(&gPlayerParty[i + 3]); - for (i = 0; i < 3 && i < gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].partySize; i++) + for (i = 0; i < 3 && i < gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].partySize; i++) { - const struct TrainerMon *partyData = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].party; - const u8 *partnerName = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; + const struct TrainerMon *partyData = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].party; + const u8 *partnerName = gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; for (k = 0; partnerName[k] != EOS && k < 3; k++) { @@ -3079,9 +3049,9 @@ static void FillPartnerParty(u16 trainerId) } CalculateMonStats(&gPlayerParty[i + 3]); - StringCopy(trainerName, gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName); + StringCopy(trainerName, gBattlePartners[difficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName); SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_NAME, trainerName); - j = gBattlePartners[SanitizeTrainerId(trainerId - TRAINER_PARTNER(PARTNER_NONE))].encounterMusic_gender >> 7; + j = gBattlePartners[difficulty][SanitizeTrainerId(trainerId - TRAINER_PARTNER(PARTNER_NONE))].encounterMusic_gender >> 7; SetMonData(&gPlayerParty[i + 3], MON_DATA_OT_GENDER, &j); } } diff --git a/src/battle_tv.c b/src/battle_tv.c index b03eee1ca9b3..e5be946d8170 100644 --- a/src/battle_tv.c +++ b/src/battle_tv.c @@ -774,7 +774,7 @@ void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags, struct DisableStruc tvPtr->side[atkSide].wishMonId = gBattlerPartyIndexes[gBattlerAttacker] + 1; tvPtr->side[atkSide].wishMoveSlot = moveSlot; } - if (gMovesInfo[move].effect == EFFECT_EXPLOSION) + if (GetMoveEffect(move) == EFFECT_EXPLOSION) { tvPtr->side[atkSide ^ BIT_SIDE].explosionMonId = gBattlerPartyIndexes[gBattlerAttacker] + 1; tvPtr->side[atkSide ^ BIT_SIDE].explosionMoveSlot = moveSlot; @@ -782,10 +782,11 @@ void BattleTv_SetDataBasedOnMove(u16 move, u16 weatherFlags, struct DisableStruc tvPtr->side[atkSide ^ BIT_SIDE].explosion = TRUE; } - AddMovePoints(PTS_REFLECT, move, gMovesInfo[move].power, 0); - AddMovePoints(PTS_LIGHT_SCREEN, move, gMovesInfo[move].power, 0); - AddMovePoints(PTS_WATER_SPORT, move, 0, 0); - AddMovePoints(PTS_MUD_SPORT, move, 0, 0); + u32 movePower = GetMovePower(move); + AddMovePoints(PTS_REFLECT, move, movePower, 0); + AddMovePoints(PTS_LIGHT_SCREEN, move, movePower, 0); + AddMovePoints(PTS_WATER_SPORT, move, 0, 0); + AddMovePoints(PTS_MUD_SPORT, move, 0, 0); } void BattleTv_SetDataBasedOnAnimation(u8 animationId) @@ -928,10 +929,10 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) { case PTS_MOVE_EFFECT: // arg1 -> move slot, arg2 -> move { - u8 baseFromEffect = gBattleMoveEffects[gMovesInfo[arg2].effect].battleTvScore; + u8 baseFromEffect = gBattleMoveEffects[GetMoveEffect(arg2)].battleTvScore; // Various cases to add/remove points - if (gMovesInfo[arg2].recoil > 0) + if (GetMoveRecoil(arg2) > 0) baseFromEffect++; // Recoil moves if (MoveHasAdditionalEffect(arg2, MOVE_EFFECT_RAPID_SPIN)) baseFromEffect++; @@ -1006,7 +1007,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) #define power arg2 case PTS_WATER_SPORT: // If used fire move during Water Sport - if (tvPtr->pos[defSide][0].waterSportMonId != -(tvPtr->pos[defSide][1].waterSportMonId) && gMovesInfo[move].type == TYPE_FIRE) + if (tvPtr->pos[defSide][0].waterSportMonId != -(tvPtr->pos[defSide][1].waterSportMonId) && GetMoveType(move) == TYPE_FIRE) { if (tvPtr->pos[defSide][0].waterSportMonId != 0) { @@ -1022,7 +1023,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) break; case PTS_MUD_SPORT: // If used Electric move during Mud Sport - if (tvPtr->pos[defSide][0].mudSportMonId != -(tvPtr->pos[defSide][1].mudSportMonId) && gMovesInfo[move].type == TYPE_ELECTRIC) + if (tvPtr->pos[defSide][0].mudSportMonId != -(tvPtr->pos[defSide][1].mudSportMonId) && GetMoveType(move) == TYPE_ELECTRIC) { if (tvPtr->pos[defSide][0].mudSportMonId != 0) { @@ -1038,7 +1039,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) break; case PTS_REFLECT: // If hit Reflect with damaging physical move - if (IS_MOVE_PHYSICAL(move) && power != 0 && tvPtr->side[defSide].reflectMonId != 0) + if (IsBattleMovePhysical(move) && power != 0 && tvPtr->side[defSide].reflectMonId != 0) { u32 id = (tvPtr->side[defSide].reflectMonId - 1) * 4; movePoints->points[defSide][id + tvPtr->side[defSide].reflectMoveSlot] += sPointsArray[caseId][0]; @@ -1046,7 +1047,7 @@ static void AddMovePoints(u8 caseId, u16 arg1, u8 arg2, u8 arg3) break; case PTS_LIGHT_SCREEN: // If hit Light Screen with damaging special move - if (IS_MOVE_SPECIAL(move) && power != 0 && tvPtr->side[defSide].lightScreenMonId != 0) + if (IsBattleMoveSpecial(move) && power != 0 && tvPtr->side[defSide].lightScreenMonId != 0) { u32 id = (tvPtr->side[defSide].lightScreenMonId - 1) * 4; movePoints->points[defSide][id + tvPtr->side[defSide].lightScreenMoveSlot] += sPointsArray[caseId][0]; @@ -1227,7 +1228,7 @@ static void TrySetBattleSeminarShow(void) return; else if (gBattleTypeFlags & (BATTLE_TYPE_PALACE | BATTLE_TYPE_PIKE | BATTLE_TYPE_PYRAMID)) return; - else if (IS_MOVE_STATUS(gBattleMons[gBattlerAttacker].moves[gMoveSelectionCursor[gBattlerAttacker]])) + else if (IsBattleMoveStatus(gBattleMons[gBattlerAttacker].moves[gMoveSelectionCursor[gBattlerAttacker]])) return; i = 0; @@ -1254,7 +1255,7 @@ static void TrySetBattleSeminarShow(void) damageCalcData.battlerAtk = gBattlerAttacker; damageCalcData.battlerDef = gBattlerTarget; damageCalcData.move = gCurrentMove; - damageCalcData.moveType = gMovesInfo[gCurrentMove].type; + damageCalcData.moveType = GetMoveType(gCurrentMove); damageCalcData.isCrit = FALSE; damageCalcData.randomFactor = FALSE; damageCalcData.updateFlags = FALSE; @@ -1296,7 +1297,7 @@ static void TrySetBattleSeminarShow(void) static bool8 ShouldCalculateDamage(u16 moveId, s32 *dmg, u16 *powerOverride) { - if (IS_MOVE_STATUS(moveId)) + if (IsBattleMoveStatus(moveId)) { *dmg = 0; return FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index c0038fd42a6a..fc916a76c497 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -96,6 +96,109 @@ static const u8 sPkblToEscapeFactor[][3] = { static const u8 sGoNearCounterToCatchFactor[] = {4, 3, 2, 1}; static const u8 sGoNearCounterToEscapeFactor[] = {4, 4, 4, 4}; + +struct BattleWeatherInfo +{ + u16 flag; + u8 rock; + u8 endMessage; + u8 continuesMessage; + u8 animation; +}; + +static const struct BattleWeatherInfo sBattleWeatherInfo[BATTLE_WEATHER_COUNT] = +{ + [BATTLE_WEATHER_RAIN] = + { + .flag = B_WEATHER_RAIN_NORMAL, + .rock = HOLD_EFFECT_DAMP_ROCK, + .endMessage = B_MSG_WEATHER_END_RAIN, + .continuesMessage = B_MSG_WEATHER_TURN_RAIN, + .animation = B_ANIM_RAIN_CONTINUES, + }, + + [BATTLE_WEATHER_RAIN_PRIMAL] = + { + .flag = B_WEATHER_RAIN_PRIMAL, + .rock = HOLD_EFFECT_DAMP_ROCK, + .endMessage = B_MSG_WEATHER_END_RAIN, + .continuesMessage = B_MSG_WEATHER_TURN_RAIN, + .animation = B_ANIM_RAIN_CONTINUES, + }, + + [BATTLE_WEATHER_RAIN_DOWNPOUR] = + { + .flag = B_WEATHER_RAIN_NORMAL, + .rock = HOLD_EFFECT_DAMP_ROCK, + .endMessage = B_MSG_WEATHER_END_RAIN, + .continuesMessage = B_MSG_WEATHER_TURN_DOWNPOUR, + .animation = B_ANIM_RAIN_CONTINUES, + }, + + [BATTLE_WEATHER_SUN] = + { + .flag = B_WEATHER_SUN_NORMAL, + .rock = HOLD_EFFECT_HEAT_ROCK, + .endMessage = B_MSG_WEATHER_END_SUN, + .continuesMessage = B_MSG_WEATHER_TURN_SUN, + .animation = B_ANIM_SUN_CONTINUES, + }, + + [BATTLE_WEATHER_SUN_PRIMAL] = + { + .flag = B_WEATHER_SUN_PRIMAL, + .rock = HOLD_EFFECT_HEAT_ROCK, + .endMessage = B_MSG_WEATHER_END_SUN, + .continuesMessage = B_MSG_WEATHER_TURN_SUN, + .animation = B_ANIM_SUN_CONTINUES, + }, + + [BATTLE_WEATHER_SANDSTORM] = + { + .flag = B_WEATHER_SANDSTORM, + .rock = HOLD_EFFECT_SMOOTH_ROCK, + .endMessage = B_MSG_WEATHER_END_SANDSTORM, + .continuesMessage = B_MSG_WEATHER_TURN_SANDSTORM, + .animation = B_ANIM_SANDSTORM_CONTINUES, + }, + + [BATTLE_WEATHER_HAIL] = + { + .flag = B_WEATHER_HAIL, + .rock = HOLD_EFFECT_ICY_ROCK, + .endMessage = B_MSG_WEATHER_END_HAIL, + .continuesMessage = B_MSG_WEATHER_TURN_HAIL, + .animation = B_ANIM_HAIL_CONTINUES, + }, + + [BATTLE_WEATHER_SNOW] = + { + .flag = B_WEATHER_SNOW, + .rock = HOLD_EFFECT_ICY_ROCK, + .endMessage = B_MSG_WEATHER_END_SNOW, + .continuesMessage = B_MSG_WEATHER_TURN_SNOW, + .animation = B_ANIM_SNOW_CONTINUES, + }, + + [BATTLE_WEATHER_FOG] = + { + .flag = B_WEATHER_FOG, + .rock = HOLD_EFFECT_NONE, + .endMessage = B_MSG_WEATHER_END_FOG, + .continuesMessage = B_MSG_WEATHER_TURN_FOG, + .animation = B_ANIM_FOG_CONTINUES, + }, + + [BATTLE_WEATHER_STRONG_WINDS] = + { + .flag = B_WEATHER_STRONG_WINDS, + .rock = HOLD_EFFECT_NONE, + .endMessage = B_MSG_WEATHER_END_STRONG_WINDS, + .continuesMessage = B_MSG_WEATHER_TURN_STRONG_WINDS, + .animation = B_ANIM_STRONG_WINDS, + }, +}; + static u8 CalcBeatUpPower(void) { u8 basePower; @@ -112,15 +215,15 @@ static u8 CalcBeatUpPower(void) bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) { u32 ability = GetBattlerAbility(battlerAtk); + u32 effect = GetMoveEffect(move); if (gSideTimers[defSide].followmeTimer == 0 || !IsBattlerAlive(gSideTimers[defSide].followmeTarget) - || gMovesInfo[move].effect == EFFECT_SNIPE_SHOT - || gMovesInfo[move].effect == EFFECT_SKY_DROP + || effect == EFFECT_SNIPE_SHOT || effect == EFFECT_SKY_DROP || ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART) return FALSE; - if (gMovesInfo[move].effect == EFFECT_PURSUIT && gBattleStruct->pursuitTarget) + if (effect == EFFECT_PURSUIT && IsPursuitTargetSet()) return FALSE; if (gSideTimers[defSide].followmePowder && !IsAffectedByPowder(battlerAtk, ability, GetBattlerHoldEffect(battlerAtk, TRUE))) @@ -132,12 +235,12 @@ bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move) // Functions void HandleAction_UseMove(void) { - u32 battler, i, side, moveType, var = 4; + u32 battler, i, side, moveType, ability, var = MAX_BATTLERS_COUNT; u16 moveTarget; gBattlerAttacker = gBattlerByTurnOrder[gCurrentTurnActionNumber]; - if (gBattleStruct->absentBattlerFlags & (1u << gBattlerAttacker) - || gBattleStruct->commandingDondozo & (1u << gBattlerAttacker) + if (gBattleStruct->battlerState[gBattlerAttacker].absentBattlerFlags + || gBattleStruct->battlerState[gBattlerAttacker].commandingDondozo || !IsBattlerAlive(gBattlerAttacker)) { gCurrentActionFuncId = B_ACTION_FINISHED; @@ -158,7 +261,7 @@ void HandleAction_UseMove(void) gProtectStructs[gBattlerAttacker].noValidMoves = FALSE; gCurrentMove = gChosenMove = MOVE_STRUGGLE; gHitMarker |= HITMARKER_NO_PPDEDUCT; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetBattleMoveTarget(MOVE_STRUGGLE, NO_TARGET_OVERRIDE); } else if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS || gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE) { @@ -170,7 +273,7 @@ void HandleAction_UseMove(void) { gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove; gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); } // check if the encored move wasn't overwritten else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE @@ -181,12 +284,12 @@ void HandleAction_UseMove(void) gDisableStructs[gBattlerAttacker].encoredMove = MOVE_NONE; gDisableStructs[gBattlerAttacker].encoredMovePos = 0; gDisableStructs[gBattlerAttacker].encoreTimer = 0; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); } else if (gBattleMons[gBattlerAttacker].moves[gCurrMovePos] != gChosenMoveByBattler[gBattlerAttacker]) { gCurrentMove = gChosenMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; - *(gBattleStruct->moveTarget + gBattlerAttacker) = GetMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); + *(gBattleStruct->moveTarget + gBattlerAttacker) = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE); } else { @@ -203,25 +306,27 @@ void HandleAction_UseMove(void) // Set dynamic move type. SetTypeBeforeUsingMove(gChosenMove, gBattlerAttacker); - moveType = GetMoveType(gCurrentMove); + moveType = GetBattleMoveType(gCurrentMove); // check Z-Move used - if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IS_MOVE_STATUS(gCurrentMove) && !IsZMove(gCurrentMove)) + if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_Z_MOVE && !IsBattleMoveStatus(gCurrentMove) && !IsZMove(gCurrentMove)) { - gBattleStruct->categoryOverride = gMovesInfo[gCurrentMove].category; + gBattleStruct->categoryOverride = GetMoveCategory(gCurrentMove); gCurrentMove = gChosenMove = GetUsableZMove(gBattlerAttacker, gCurrentMove); } // check Max Move used else if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX) { - gBattleStruct->categoryOverride = gMovesInfo[gCurrentMove].category; + gBattleStruct->categoryOverride = GetMoveCategory(gCurrentMove); gCurrentMove = gChosenMove = GetMaxMove(gBattlerAttacker, gCurrentMove); } moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove); + u32 moveEffect = GetMoveEffect(gCurrentMove); // choose target side = BATTLE_OPPOSITE(GetBattlerSide(gBattlerAttacker)); + ability = GetBattlerAbility(gBattleStruct->moveTarget[gBattlerAttacker]); if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove) && moveTarget == MOVE_TARGET_SELECTED && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget)) @@ -230,28 +335,30 @@ void HandleAction_UseMove(void) } else if (IsDoubleBattle() && gSideTimers[side].followmeTimer == 0 - && !(gBattleStruct->pursuitTarget & (1u << *(gBattleStruct->moveTarget + gBattlerAttacker))) - && (!IS_MOVE_STATUS(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) - && ((GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (GetBattlerAbility(*(gBattleStruct->moveTarget + gBattlerAttacker)) != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) + && !gBattleStruct->battlerState[*(gBattleStruct->moveTarget + gBattlerAttacker)].pursuitTarget + && (!IsBattleMoveStatus(gCurrentMove) || (moveTarget != MOVE_TARGET_USER && moveTarget != MOVE_TARGET_ALL_BATTLERS)) + && ((ability != ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (ability != ABILITY_STORM_DRAIN && moveType == TYPE_WATER))) { - side = GetBattlerSide(gBattlerAttacker); + // Find first battler that redirects the move (in turn order) for (battler = 0; battler < gBattlersCount; battler++) { - if (side != GetBattlerSide(battler) - && *(gBattleStruct->moveTarget + gBattlerAttacker) != battler - && ((GetBattlerAbility(battler) == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) - || (GetBattlerAbility(battler) == ABILITY_STORM_DRAIN && moveType == TYPE_WATER)) + ability = GetBattlerAbility(battler); + if ((B_REDIRECT_ABILITY_ALLIES >= GEN_4 || !IsAlly(gBattlerAttacker, battler)) + && battler != gBattlerAttacker + && gBattleStruct->moveTarget[gBattlerAttacker] != battler + && ((ability == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC) + || (ability == ABILITY_STORM_DRAIN && moveType == TYPE_WATER)) && GetBattlerTurnOrderNum(battler) < var - && gMovesInfo[gCurrentMove].effect != EFFECT_SNIPE_SHOT - && gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE + && moveEffect != EFFECT_SNIPE_SHOT + && moveEffect != EFFECT_PLEDGE && GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL && GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART) { var = GetBattlerTurnOrderNum(battler); } } - if (var == 4) + if (var == MAX_BATTLERS_COUNT) { if (moveTarget & MOVE_TARGET_RANDOM) { @@ -291,7 +398,7 @@ void HandleAction_UseMove(void) gBattlerTarget = battler; } } - else if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM) + else if (IsDoubleBattle() && moveTarget & MOVE_TARGET_RANDOM) { gBattlerTarget = SetRandomTarget(gBattlerAttacker); if (gAbsentBattlerFlags & (1u << gBattlerTarget) @@ -307,7 +414,7 @@ void HandleAction_UseMove(void) else gBattlerTarget = gBattlerAttacker; } - else if (IsDoubleBattle() && moveTarget == MOVE_TARGET_FOES_AND_ALLY) + else if (IsDoubleBattle() && moveTarget == MOVE_TARGET_FOES_AND_ALLY) { for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount; gBattlerTarget++) { @@ -356,7 +463,7 @@ void HandleAction_UseMove(void) } else { - gBattlescriptCurrInstr = GET_MOVE_BATTLESCRIPT(gCurrentMove); + gBattlescriptCurrInstr = GetMoveBattleScript(gCurrentMove); } if (gBattleTypeFlags & BATTLE_TYPE_ARENA) @@ -691,11 +798,11 @@ void HandleAction_ActionFinished(void) | HITMARKER_CHARGING | HITMARKER_NEVER_SET | HITMARKER_IGNORE_DISGUISE); // check if Stellar type boost should be used up - moveType = GetMoveType(gCurrentMove); + moveType = GetBattleMoveType(gCurrentMove); if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA && GetBattlerTeraType(gBattlerAttacker) == TYPE_STELLAR - && gMovesInfo[gCurrentMove].category != DAMAGE_CATEGORY_STATUS + && GetMoveCategory(gCurrentMove) != DAMAGE_CATEGORY_STATUS && IsTypeStellarBoosted(gBattlerAttacker, moveType)) { ExpendTypeStellarBoost(gBattlerAttacker, moveType); @@ -711,7 +818,7 @@ void HandleAction_ActionFinished(void) gBattleScripting.multihitMoveEffect = 0; gBattleResources->battleScriptsStack->size = 0; - if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove && !gBattleStruct->pursuitTarget) + if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove && !IsPursuitTargetSet()) { // i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already // taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action @@ -841,22 +948,22 @@ static void UNUSED MarkAllBattlersForControllerExec(void) else { for (i = 0; i < gBattlersCount; i++) - gBattleControllerExecFlags |= 1 << i; + gBattleControllerExecFlags |= 1u << i; } } bool32 IsBattlerMarkedForControllerExec(u32 battler) { if (gBattleTypeFlags & BATTLE_TYPE_LINK) - return (gBattleControllerExecFlags & (1 << (battler + 28))) != 0; + return (gBattleControllerExecFlags & (1u << (battler + 28))) != 0; else - return (gBattleControllerExecFlags & (1 << battler)) != 0; + return (gBattleControllerExecFlags & (1u << battler)) != 0; } void MarkBattlerForControllerExec(u32 battler) { if (gBattleTypeFlags & BATTLE_TYPE_LINK) - gBattleControllerExecFlags |= 1u << (32 - MAX_BATTLERS_COUNT); + gBattleControllerExecFlags |= 1u << (battler + 32 - MAX_BATTLERS_COUNT); else gBattleControllerExecFlags |= 1u << battler; } @@ -1104,7 +1211,7 @@ static bool32 IsGravityPreventingMove(u32 move) if (!(gFieldStatuses & STATUS_FIELD_GRAVITY)) return FALSE; - return gMovesInfo[move].gravityBanned; + return IsMoveGravityBanned(move); } bool32 IsHealBlockPreventingMove(u32 battler, u32 move) @@ -1112,12 +1219,12 @@ bool32 IsHealBlockPreventingMove(u32 battler, u32 move) if (!(gStatuses3[battler] & STATUS3_HEAL_BLOCK)) return FALSE; - return gMovesInfo[move].healingMove; + return IsHealingMove(move); } bool32 IsBelchPreventingMove(u32 battler, u32 move) { - if (gMovesInfo[move].effect != EFFECT_BELCH) + if (GetMoveEffect(move) != EFFECT_BELCH) return FALSE; return !(gBattleStruct->ateBerry[battler & BIT_SIDE] & (1u << gBattlerPartyIndexes[battler])); @@ -1133,6 +1240,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) u32 move = gBattleMons[battler].moves[moveId]; u32 holdEffect = GetBattlerHoldEffect(battler, TRUE); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; + u32 moveEffect = GetMoveEffect(move); if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[battler].disabledMove == move && move != MOVE_NONE) { @@ -1165,7 +1273,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[battler].tauntTimer != 0 && IS_MOVE_STATUS(move)) + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[battler].tauntTimer != 0 && IsBattleMoveStatus(move)) { if ((GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX)) gCurrentMove = MOVE_MAX_GUARD; @@ -1183,7 +1291,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer != 0 && gMovesInfo[move].soundMove) + if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[battler].throatChopTimer != 0 && IsSoundMove(move)) { gCurrentMove = move; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -1258,7 +1366,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (DYNAMAX_BYPASS_CHECK && gMovesInfo[move].effect == EFFECT_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) + if (DYNAMAX_BYPASS_CHECK && moveEffect == EFFECT_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) { gCurrentMove = move; if (gBattleTypeFlags & BATTLE_TYPE_PALACE) @@ -1273,7 +1381,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (gMovesInfo[move].cantUseTwice && move == gLastResultingMoves[battler]) + if (MoveCantBeUsedTwice(move) && move == gLastResultingMoves[battler]) { gCurrentMove = move; PREPARE_MOVE_BUFFER(gBattleTextBuff1, gCurrentMove); @@ -1305,7 +1413,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) limitations++; } } - else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && IS_MOVE_STATUS(move) && gMovesInfo[move].effect != EFFECT_ME_FIRST) + else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && IsBattleMoveStatus(move) && moveEffect != EFFECT_ME_FIRST) { if ((GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX)) gCurrentMove = MOVE_MAX_GUARD; @@ -1353,7 +1461,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler) } } - if (gMovesInfo[move].effect == EFFECT_PLACEHOLDER) + if (moveEffect == EFFECT_PLACEHOLDER) { if (gBattleTypeFlags & BATTLE_TYPE_PALACE) { @@ -1382,7 +1490,7 @@ u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) for (i = 0; i < MAX_MON_MOVES; i++) { move = gBattleMons[battler].moves[i]; - moveEffect = gMovesInfo[move].effect; + moveEffect = GetMoveEffect(move); // No move if (check & MOVE_LIMITATION_ZEROMOVE && move == MOVE_NONE) unusableMoves |= 1u << i; @@ -1399,7 +1507,7 @@ u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_TORMENTED && move == gLastMoves[battler] && gBattleMons[battler].status2 & STATUS2_TORMENT) unusableMoves |= 1u << i; // Taunt - else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IS_MOVE_STATUS(move)) + else if (check & MOVE_LIMITATION_TAUNT && gDisableStructs[battler].tauntTimer && IsBattleMoveStatus(move)) unusableMoves |= 1u << i; // Imprison else if (check & MOVE_LIMITATION_IMPRISON && GetImprisonedMovesCount(battler, move)) @@ -1411,7 +1519,7 @@ u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_CHOICE_ITEM && HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) unusableMoves |= 1u << i; // Assault Vest - else if (check & MOVE_LIMITATION_ASSAULT_VEST && holdEffect == HOLD_EFFECT_ASSAULT_VEST && IS_MOVE_STATUS(move) && gMovesInfo[move].effect != EFFECT_ME_FIRST) + else if (check & MOVE_LIMITATION_ASSAULT_VEST && holdEffect == HOLD_EFFECT_ASSAULT_VEST && IsBattleMoveStatus(move) && moveEffect != EFFECT_ME_FIRST) unusableMoves |= 1u << i; // Gravity else if (check & MOVE_LIMITATION_GRAVITY && IsGravityPreventingMove(move)) @@ -1423,7 +1531,7 @@ u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_BELCH && IsBelchPreventingMove(battler, move)) unusableMoves |= 1u << i; // Throat Chop - else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer && gMovesInfo[move].soundMove) + else if (check & MOVE_LIMITATION_THROAT_CHOP && gDisableStructs[battler].throatChopTimer && IsSoundMove(move)) unusableMoves |= 1u << i; // Stuff Cheeks else if (check & MOVE_LIMITATION_STUFF_CHEEKS && moveEffect == EFFECT_STUFF_CHEEKS && ItemId_GetPocket(gBattleMons[battler].item) != POCKET_BERRIES) @@ -1432,7 +1540,7 @@ u8 CheckMoveLimitations(u32 battler, u8 unusableMoves, u16 check) else if (check & MOVE_LIMITATION_CHOICE_ITEM && GetBattlerAbility(battler) == ABILITY_GORILLA_TACTICS && *choicedMove != MOVE_NONE && *choicedMove != MOVE_UNAVAILABLE && *choicedMove != move) unusableMoves |= 1u << i; // Can't Use Twice flag - else if (check & MOVE_LIMITATION_CANT_USE_TWICE && gMovesInfo[move].cantUseTwice && move == gLastResultingMoves[battler]) + else if (check & MOVE_LIMITATION_CANT_USE_TWICE && MoveCantBeUsedTwice(move) && move == gLastResultingMoves[battler]) unusableMoves |= 1u << i; } return unusableMoves; @@ -1522,12 +1630,7 @@ enum ENDTURN_SAFEGUARD, ENDTURN_TAILWIND, ENDTURN_WISH, - ENDTURN_RAIN, - ENDTURN_SANDSTORM, - ENDTURN_SUN, - ENDTURN_HAIL, - ENDTURN_SNOW, - ENDTURN_FOG, + ENDTURN_WEATHER, ENDTURN_DAMAGE_NON_TYPES, ENDTURN_GRAVITY, ENDTURN_WATER_SPORT, @@ -1554,7 +1657,7 @@ static bool32 EndTurnTerrain(u32 terrainFlag, u32 stringTableId) { if (terrainFlag & STATUS_FIELD_GRASSY_TERRAIN) BattleScriptExecute(BattleScript_GrassyTerrainHeals); - if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.terrainTimer == 0) + if (gFieldTimers.terrainTimer > 0 && --gFieldTimers.terrainTimer == 0) { gFieldStatuses &= ~terrainFlag; TryToRevertMimicryAndFlags(); @@ -1569,6 +1672,44 @@ static bool32 EndTurnTerrain(u32 terrainFlag, u32 stringTableId) return FALSE; } +static bool32 TryEndTurnWeather(void) +{ + u32 i = 0; + u32 effect = 0; + u32 currBattleWeather = 0xFF; + + for (i = 0; i < ARRAY_COUNT(sBattleWeatherInfo); i++) + { + if (gBattleWeather & sBattleWeatherInfo[i].flag) + { + currBattleWeather = i; + break; + } + } + + if (currBattleWeather == 0xFF) + return effect; + + if (gWishFutureKnock.weatherDuration > 0 && --gWishFutureKnock.weatherDuration == 0) + { + gBattleWeather = B_WEATHER_NONE; + for (i = 0; i < gBattlersCount; i++) + gDisableStructs[i].weatherAbilityDone = FALSE; + gBattleCommunication[MULTISTRING_CHOOSER] = sBattleWeatherInfo[currBattleWeather].endMessage; + BattleScriptExecute(BattleScript_WeatherFaded); + effect++; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = sBattleWeatherInfo[currBattleWeather].continuesMessage; + gBattleScripting.animArg1 = sBattleWeatherInfo[currBattleWeather].animation; + BattleScriptExecute(BattleScript_WeatherContinues); + effect++; + } + + return effect; +} + u8 DoFieldEndTurnEffects(void) { u8 effect = 0; @@ -1796,139 +1937,8 @@ u8 DoFieldEndTurnEffects(void) gBattleStruct->turnSideTracker = 0; } break; - case ENDTURN_RAIN: - if (gBattleWeather & B_WEATHER_RAIN) - { - if (!(gBattleWeather & B_WEATHER_RAIN_PERMANENT) - && !(gBattleWeather & B_WEATHER_RAIN_PRIMAL)) - { - if (--gWishFutureKnock.weatherDuration == 0) - { - gBattleWeather &= ~B_WEATHER_RAIN_TEMPORARY; - gBattleWeather &= ~B_WEATHER_RAIN_DOWNPOUR; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_RAIN_STOPPED; - } - else if (gBattleWeather & B_WEATHER_RAIN_DOWNPOUR) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOWNPOUR_CONTINUES; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_RAIN_CONTINUES; - } - } - else if (gBattleWeather & B_WEATHER_RAIN_DOWNPOUR) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_DOWNPOUR_CONTINUES; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_RAIN_CONTINUES; - } - - BattleScriptExecute(BattleScript_RainContinuesOrEnds); - effect++; - } - gBattleStruct->turnCountersTracker++; - break; - case ENDTURN_SANDSTORM: - if (gBattleWeather & B_WEATHER_SANDSTORM) - { - if (!(gBattleWeather & B_WEATHER_SANDSTORM_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) - { - gBattleWeather &= ~B_WEATHER_SANDSTORM_TEMPORARY; - gBattlescriptCurrInstr = BattleScript_SandStormHailSnowEnds; - } - else - { - gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues; - } - - gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SANDSTORM; - BattleScriptExecute(gBattlescriptCurrInstr); - effect++; - } - gBattleStruct->turnCountersTracker++; - break; - case ENDTURN_SUN: - if (gBattleWeather & B_WEATHER_SUN) - { - if (!(gBattleWeather & B_WEATHER_SUN_PERMANENT) - && !(gBattleWeather & B_WEATHER_SUN_PRIMAL) - && --gWishFutureKnock.weatherDuration == 0) - { - gBattleWeather &= ~B_WEATHER_SUN_TEMPORARY; - for (i = 0; i < gBattlersCount; i++) - gDisableStructs[i].weatherAbilityDone = FALSE; - gBattlescriptCurrInstr = BattleScript_SunlightFaded; - } - else - { - gBattlescriptCurrInstr = BattleScript_SunlightContinues; - } - - BattleScriptExecute(gBattlescriptCurrInstr); - effect++; - } - gBattleStruct->turnCountersTracker++; - break; - case ENDTURN_HAIL: - if (gBattleWeather & B_WEATHER_HAIL) - { - if (!(gBattleWeather & B_WEATHER_HAIL_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) - { - gBattleWeather &= ~B_WEATHER_HAIL_TEMPORARY; - gBattlescriptCurrInstr = BattleScript_SandStormHailSnowEnds; - } - else - { - gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues; - } - - gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_HAIL; - BattleScriptExecute(gBattlescriptCurrInstr); - effect++; - } - gBattleStruct->turnCountersTracker++; - break; - case ENDTURN_SNOW: - if (gBattleWeather & B_WEATHER_SNOW) - { - if (!(gBattleWeather & B_WEATHER_SNOW_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) - { - gBattleWeather &= ~B_WEATHER_SNOW_TEMPORARY; - gBattlescriptCurrInstr = BattleScript_SandStormHailSnowEnds; - } - else - { - gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues; - } - - gBattleScripting.animArg1 = B_ANIM_SNOW_CONTINUES; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SNOW; - BattleScriptExecute(gBattlescriptCurrInstr); - effect++; - } - gBattleStruct->turnCountersTracker++; - break; - case ENDTURN_FOG: - if (gBattleWeather & B_WEATHER_FOG) - { - if (!(gBattleWeather & B_WEATHER_FOG_PERMANENT) && --gWishFutureKnock.weatherDuration == 0) - { - gBattleWeather &= ~B_WEATHER_FOG_TEMPORARY; - gBattlescriptCurrInstr = BattleScript_FogEnded; - } - else - { - gBattlescriptCurrInstr = BattleScript_FogContinues; - } - - BattleScriptExecute(gBattlescriptCurrInstr); - effect++; - } + case ENDTURN_WEATHER: + effect = TryEndTurnWeather(); gBattleStruct->turnCountersTracker++; break; case ENDTURN_DAMAGE_NON_TYPES: @@ -2250,6 +2260,7 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; if (gBattleStruct->moveDamage[battler] == 0) gBattleStruct->moveDamage[battler] = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SANDSTORM; BattleScriptExecute(BattleScript_DamagingWeather); effect++; } @@ -2276,6 +2287,7 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->moveDamage[battler] = GetNonDynamaxMaxHP(battler) / 16; if (gBattleStruct->moveDamage[battler] == 0) gBattleStruct->moveDamage[battler] = 1; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_HAIL; BattleScriptExecute(BattleScript_DamagingWeather); effect++; } @@ -2773,8 +2785,8 @@ u8 DoBattlerEndTurnEffects(void) gBattleStruct->turnEffectsTracker++; break; case ENDTURN_ROOST: // Return flying type. - if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST) - gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_ROOST; + if (gDisableStructs[battler].roostActive) + gDisableStructs[battler].roostActive = FALSE; gBattleStruct->turnEffectsTracker++; break; case ENDTURN_ELECTRIFY: @@ -2940,7 +2952,6 @@ bool32 HandleWishPerishSongOnTurnEnd(void) gBattlerTarget = battler; gBattlerAttacker = gWishFutureKnock.futureSightBattlerIndex[battler]; - gSpecialStatuses[gBattlerTarget].shellBellDmg = IGNORE_SHELL_BELL; gCurrentMove = gWishFutureKnock.futureSightMove[battler]; party = GetSideParty(GetBattlerSide(gBattlerAttacker)); @@ -3222,7 +3233,7 @@ static void CancellerAsleep(u32 *effect) static void CancellerFrozen(u32 *effect) { - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE && !(gMovesInfo[gCurrentMove].thawsUser)) + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE && !MoveThawsUser(gCurrentMove)) { if (!RandomPercentage(RNG_FROZEN, 20)) { @@ -3272,7 +3283,7 @@ static void CancellerObedience(u32 *effect) break; case DISOBEYS_FALL_ASLEEP: if (IsSleepClauseEnabled()) - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep; gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED; break; @@ -3284,7 +3295,7 @@ static void CancellerObedience(u32 *effect) gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; SetAtkCancellerForCalledMove(); gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; - gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); + gBattlerTarget = GetBattleMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gHitMarker |= HITMARKER_DISOBEDIENT_MOVE; gHitMarker |= HITMARKER_OBEYS; break; @@ -3385,7 +3396,7 @@ static void CancellerGravity(u32 *effect) static void CancellerThroatChop(u32 *effect) { - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer && gMovesInfo[gCurrentMove].soundMove) + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer && IsSoundMove(gCurrentMove)) { gProtectStructs[gBattlerAttacker].usedThroatChopPreventedMove = TRUE; CancelMultiTurnMoves(gBattlerAttacker); @@ -3397,7 +3408,7 @@ static void CancellerThroatChop(u32 *effect) static void CancellerTaunted(u32 *effect) { - if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IS_MOVE_STATUS(gCurrentMove)) + if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IsBattleMoveStatus(gCurrentMove)) { gProtectStructs[gBattlerAttacker].usedTauntedMove = TRUE; CancelMultiTurnMoves(gBattlerAttacker); @@ -3464,7 +3475,10 @@ static void CancellerConfused(u32 *effect) static void CancellerParalysed(u32 *effect) { - if (!gBattleStruct->isAtkCancelerForCalledMove && (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && !RandomPercentage(RNG_PARALYSIS, 75)) + if (!gBattleStruct->isAtkCancelerForCalledMove + && (gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) + && (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD && B_MAGIC_GUARD >= GEN_4) + && !RandomPercentage(RNG_PARALYSIS, 75)) { gProtectStructs[gBattlerAttacker].prlzImmobility = TRUE; // This is removed in FRLG and Emerald for some reason @@ -3493,7 +3507,7 @@ static void CancellerBide(u32 *effect) gCurrentMove = MOVE_BIDE; gBattlerTarget = gBideTarget[gBattlerAttacker]; if (gAbsentBattlerFlags & (1u << gBattlerTarget)) - gBattlerTarget = GetMoveTarget(MOVE_BIDE, MOVE_TARGET_SELECTED + 1); + gBattlerTarget = GetBattleMoveTarget(MOVE_BIDE, MOVE_TARGET_SELECTED + 1); gBattlescriptCurrInstr = BattleScript_BideAttack; } else @@ -3518,7 +3532,7 @@ static void CancellerThaw(u32 *effect) } *effect = 2; } - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && gMovesInfo[gCurrentMove].thawsUser) + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FROSTBITE && MoveThawsUser(gCurrentMove)) { if (!(IsMoveEffectRemoveSpeciesType(gCurrentMove, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_FIRE))) { @@ -3539,9 +3553,9 @@ static void CancellerStanceChangeTwo(u32 *effect) static void CancellerWeatherPrimal(u32 *effect) { - if (WEATHER_HAS_EFFECT && gMovesInfo[gCurrentMove].power) + if (WEATHER_HAS_EFFECT && GetMovePower(gCurrentMove) > 0) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL)) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN; @@ -3574,7 +3588,7 @@ static void CancellerDynamaxBlocked(u32 *effect) static void CancellerPowderMove(u32 *effect) { - if ((gMovesInfo[gCurrentMove].powderMove) && (gBattlerAttacker != gBattlerTarget)) + if (IsPowderMove(gCurrentMove) && (gBattlerAttacker != gBattlerTarget)) { if (B_POWDER_GRASS >= GEN_6 && (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) || GetBattlerAbility(gBattlerTarget) == ABILITY_OVERCOAT)) @@ -3599,7 +3613,7 @@ static void CancellerPowderStatus(u32 *effect) if (gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER) { u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; - if ((GetMoveType(gCurrentMove) == TYPE_FIRE && !gBattleStruct->pledgeMove) + if ((GetBattleMoveType(gCurrentMove) == TYPE_FIRE && !gBattleStruct->pledgeMove) || (gCurrentMove == MOVE_FIRE_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE) || (gCurrentMove == MOVE_GRASS_PLEDGE && partnerMove == MOVE_FIRE_PLEDGE && gBattleStruct->pledgeMove)) { @@ -3619,7 +3633,7 @@ static void CancellerPowderStatus(u32 *effect) static void CancellerProtean(u32 *effect) { - u32 moveType = GetMoveType(gCurrentMove); + u32 moveType = GetBattleMoveType(gCurrentMove); if (ProteanTryChangeType(gBattlerAttacker, GetBattlerAbility(gBattlerAttacker), gCurrentMove, moveType)) { if (B_PROTEAN_LIBERO == GEN_9) @@ -3639,8 +3653,8 @@ static void CancellerPsychicTerrain(u32 *effect) if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN && IsBattlerGrounded(gBattlerTarget) && GetChosenMovePriority(gBattlerAttacker) > 0 - && gMovesInfo[gCurrentMove].target != MOVE_TARGET_ALL_BATTLERS - && gMovesInfo[gCurrentMove].target != MOVE_TARGET_OPPONENTS_FIELD + && GetMoveTarget(gCurrentMove) != MOVE_TARGET_ALL_BATTLERS + && GetMoveTarget(gCurrentMove) != MOVE_TARGET_OPPONENTS_FIELD && GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget)) { CancelMultiTurnMoves(gBattlerAttacker); @@ -3653,8 +3667,8 @@ static void CancellerPsychicTerrain(u32 *effect) static void CancellerExplodingDamp(u32 *effect) { u32 dampBattler = IsAbilityOnField(ABILITY_DAMP); - if (dampBattler && (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION - || gMovesInfo[gCurrentMove].effect == EFFECT_MIND_BLOWN)) + if (dampBattler && (GetMoveEffect(gCurrentMove) == EFFECT_EXPLOSION + || GetMoveEffect(gCurrentMove) == EFFECT_MIND_BLOWN)) { gBattleScripting.battler = dampBattler - 1; gBattlescriptCurrInstr = BattleScript_DampStopsExplosion; @@ -3665,7 +3679,7 @@ static void CancellerExplodingDamp(u32 *effect) static void CancellerMultihitMoves(u32 *effect) { - if (gMovesInfo[gCurrentMove].effect == EFFECT_MULTI_HIT) + if (GetMoveEffect(gCurrentMove) == EFFECT_MULTI_HIT) { u32 ability = GetBattlerAbility(gBattlerAttacker); @@ -3686,17 +3700,17 @@ static void CancellerMultihitMoves(u32 *effect) PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) } - else if (gMovesInfo[gCurrentMove].strikeCount > 1) + else if (GetMoveStrikeCount(gCurrentMove) > 1) { - if (gMovesInfo[gCurrentMove].effect == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) + if (GetMoveEffect(gCurrentMove) == EFFECT_POPULATION_BOMB && GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LOADED_DICE) { gMultiHitCounter = RandomUniform(RNG_LOADED_DICE, 4, 10); } else { - gMultiHitCounter = gMovesInfo[gCurrentMove].strikeCount; + gMultiHitCounter = GetMoveStrikeCount(gCurrentMove); - if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS + if (GetMoveEffect(gCurrentMove) == EFFECT_DRAGON_DARTS && CanTargetPartner(gBattlerAttacker, gBattlerTarget) && TargetFullyImmuneToCurrMove(gBattlerAttacker, gBattlerTarget)) gBattlerTarget = BATTLE_PARTNER(gBattlerTarget); @@ -3704,7 +3718,7 @@ static void CancellerMultihitMoves(u32 *effect) PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 3, 0) } - else if (B_BEAT_UP >= GEN_5 && gMovesInfo[gCurrentMove].effect == EFFECT_BEAT_UP) + else if (B_BEAT_UP >= GEN_5 && GetMoveEffect(gCurrentMove) == EFFECT_BEAT_UP) { struct Pokemon* party = GetBattlerParty(gBattlerAttacker); int i; @@ -3747,7 +3761,7 @@ static void CancellerZMoves(u32 *effect) gBattlescriptCurrInstr = BattleScript_ZMoveActivatePowder; } } - else if (gMovesInfo[gCurrentMove].category == DAMAGE_CATEGORY_STATUS) + else if (GetMoveCategory(gCurrentMove) == DAMAGE_CATEGORY_STATUS) { if (!alreadyUsed) { @@ -3786,7 +3800,7 @@ static void CancellerMultiTargetMoves(u32 *effect) gBattleStruct->noResultString[battlerDef] = TRUE; } else if (AbilityBattleEffects(ABILITYEFFECT_WOULD_BLOCK, battlerDef, 0, 0, 0) - || (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetMovePriority(gBattlerAttacker, gCurrentMove) > 0)) + || (IsBattlerTerrainAffected(gBattlerAttacker, STATUS_FIELD_PSYCHIC_TERRAIN) && GetBattleMovePriority(gBattlerAttacker, gCurrentMove) > 0)) { gBattleStruct->moveResultFlags[battlerDef] = 0; gBattleStruct->noResultString[battlerDef] = TRUE; @@ -3798,7 +3812,7 @@ static void CancellerMultiTargetMoves(u32 *effect) } else { - CalcTypeEffectivenessMultiplier(gCurrentMove, gMovesInfo[gCurrentMove].type, gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); + CalcTypeEffectivenessMultiplier(gCurrentMove, GetBattleMoveType(gCurrentMove), gBattlerAttacker, battlerDef, GetBattlerAbility(battlerDef), TRUE); } } if (moveTarget == MOVE_TARGET_BOTH) @@ -4005,43 +4019,39 @@ bool32 HasNoMonsToSwitch(u32 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2 } } -static const u16 sWeatherFlagsInfo[][3] = -{ - [ENUM_WEATHER_RAIN] = {B_WEATHER_RAIN_TEMPORARY, B_WEATHER_RAIN_PERMANENT, HOLD_EFFECT_DAMP_ROCK}, - [ENUM_WEATHER_RAIN_PRIMAL] = {B_WEATHER_RAIN_PRIMAL, B_WEATHER_RAIN_PRIMAL, HOLD_EFFECT_DAMP_ROCK}, - [ENUM_WEATHER_SUN] = {B_WEATHER_SUN_TEMPORARY, B_WEATHER_SUN_PERMANENT, HOLD_EFFECT_HEAT_ROCK}, - [ENUM_WEATHER_SUN_PRIMAL] = {B_WEATHER_SUN_PRIMAL, B_WEATHER_SUN_PRIMAL, HOLD_EFFECT_HEAT_ROCK}, - [ENUM_WEATHER_SANDSTORM] = {B_WEATHER_SANDSTORM_TEMPORARY, B_WEATHER_SANDSTORM_PERMANENT, HOLD_EFFECT_SMOOTH_ROCK}, - [ENUM_WEATHER_HAIL] = {B_WEATHER_HAIL_TEMPORARY, B_WEATHER_HAIL_PERMANENT, HOLD_EFFECT_ICY_ROCK}, - [ENUM_WEATHER_STRONG_WINDS] = {B_WEATHER_STRONG_WINDS, B_WEATHER_STRONG_WINDS, HOLD_EFFECT_NONE}, - [ENUM_WEATHER_SNOW] = {B_WEATHER_SNOW_TEMPORARY, B_WEATHER_SNOW_PERMANENT, HOLD_EFFECT_ICY_ROCK}, - [ENUM_WEATHER_FOG] = {B_WEATHER_FOG_TEMPORARY, B_WEATHER_FOG_PERMANENT, HOLD_EFFECT_NONE}, -}; - -bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility) +bool32 TryChangeBattleWeather(u32 battler, u32 battleWeatherId, bool32 viaAbility) { u16 battlerAbility = GetBattlerAbility(battler); - if (gBattleWeather & B_WEATHER_PRIMAL_ANY + + if (gBattleWeather & sBattleWeatherInfo[battleWeatherId].flag) + { + return FALSE; + } + else if (gBattleWeather & B_WEATHER_PRIMAL_ANY && battlerAbility != ABILITY_DESOLATE_LAND && battlerAbility != ABILITY_PRIMORDIAL_SEA && battlerAbility != ABILITY_DELTA_STREAM) { return FALSE; } - else if (B_ABILITY_WEATHER < GEN_6 && viaAbility && !(gBattleWeather & sWeatherFlagsInfo[weatherEnumId][1])) + else if (B_ABILITY_WEATHER < GEN_6 && viaAbility) { - gBattleWeather = (sWeatherFlagsInfo[weatherEnumId][0] | sWeatherFlagsInfo[weatherEnumId][1]); + gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag; return TRUE; } - else if (!(gBattleWeather & (sWeatherFlagsInfo[weatherEnumId][0] | sWeatherFlagsInfo[weatherEnumId][1]))) + else { - gBattleWeather = (sWeatherFlagsInfo[weatherEnumId][0]); - if (GetBattlerHoldEffect(battler, TRUE) == sWeatherFlagsInfo[weatherEnumId][2]) + u32 rock = sBattleWeatherInfo[battleWeatherId].rock; + gBattleWeather = sBattleWeatherInfo[battleWeatherId].flag; + if (gBattleWeather & B_WEATHER_PRIMAL_ANY) + gWishFutureKnock.weatherDuration = 0; + else if (rock != 0 && GetBattlerHoldEffect(battler, TRUE) == rock) gWishFutureKnock.weatherDuration = 8; else gWishFutureKnock.weatherDuration = 5; return TRUE; } + return FALSE; } @@ -4049,7 +4059,7 @@ static bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag, u8 *timer) { if ((!(gFieldStatuses & statusFlag) && (!gBattleStruct->isSkyBattle))) { - gFieldStatuses &= ~(STATUS_FIELD_TERRAIN_ANY | STATUS_FIELD_TERRAIN_PERMANENT); + gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; gFieldStatuses |= statusFlag; gDisableStructs[battler].terrainAbilityDone = FALSE; @@ -4086,7 +4096,7 @@ static void ForewarnChooseMove(u32 battler) continue; data[count].moveId = gBattleMons[i].moves[j]; data[count].battler = i; - switch (gMovesInfo[data[count].moveId].effect) + switch (GetMoveEffect(data[count].moveId)) { case EFFECT_OHKO: data[count].power = 150; @@ -4097,12 +4107,15 @@ static void ForewarnChooseMove(u32 battler) data[count].power = 120; break; default: - if (gMovesInfo[data[count].moveId].power == 1) + { + u32 movePower = GetMovePower(data[count].moveId); + if (movePower == 1) data[count].power = 80; else - data[count].power = gMovesInfo[data[count].moveId].power; + data[count].power = movePower; break; } + } count++; } } @@ -4222,11 +4235,11 @@ u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef switch (abilityDef) { case ABILITY_SOUNDPROOF: - if (gMovesInfo[move].soundMove && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER)) + if (IsSoundMove(move) && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER)) effect = MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF; break; case ABILITY_BULLETPROOF: - if (gMovesInfo[move].ballisticMove) + if (IsBallisticMove(move)) effect = MOVE_BLOCKED_BY_SOUNDPROOF_OR_BULLETPROOF; break; case ABILITY_DAZZLING: @@ -4234,13 +4247,13 @@ u32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abilityDef case ABILITY_ARMOR_TAIL: if (GetBattlerSide(battlerAtk) != GetBattlerSide(battlerDef)) { - u32 priority = AI_DATA->aiCalcInProgress ? GetMovePriority(battlerAtk, move) : GetChosenMovePriority(battlerAtk); + u32 priority = AI_DATA->aiCalcInProgress ? GetBattleMovePriority(battlerAtk, move) : GetChosenMovePriority(battlerAtk); if (priority > 0) effect = MOVE_BLOCKED_BY_DAZZLING; } break; case ABILITY_GOOD_AS_GOLD: - if (IS_MOVE_STATUS(move)) + if (IsBattleMoveStatus(move)) { u32 moveTarget = GetBattlerMoveTargetType(battlerAtk, move); if (!(moveTarget & MOVE_TARGET_OPPONENTS_FIELD) && !(moveTarget & MOVE_TARGET_ALL_BATTLERS)) @@ -4264,7 +4277,7 @@ u32 CanPartnerAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 move, u32 abi case ABILITY_ARMOR_TAIL: if (GetBattlerSide(battlerAtk) != GetBattlerSide(battlerDef)) { - s32 priority = AI_DATA->aiCalcInProgress ? GetMovePriority(battlerAtk, move) : GetChosenMovePriority(battlerAtk); + s32 priority = AI_DATA->aiCalcInProgress ? GetBattleMovePriority(battlerAtk, move) : GetChosenMovePriority(battlerAtk); if (priority > 0) return MOVE_BLOCKED_BY_PARTNER_DAZZLING; } @@ -4283,7 +4296,7 @@ u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 mov effect = MOVE_ABSORBED_BY_NO_ABILITY; break; case ABILITY_VOLT_ABSORB: - if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS) + if (moveType == TYPE_ELECTRIC && GetMoveTarget(move) != MOVE_TARGET_ALL_BATTLERS) effect = MOVE_ABSORBED_BY_DRAIN_HP_ABILITY; break; case ABILITY_WATER_ABSORB: @@ -4296,11 +4309,11 @@ u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 mov effect = MOVE_ABSORBED_BY_DRAIN_HP_ABILITY; break; case ABILITY_MOTOR_DRIVE: - if (moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS) // Potential bug in singles (might be solved with simu hp reudction) + if (moveType == TYPE_ELECTRIC && GetMoveTarget(move) != MOVE_TARGET_ALL_BATTLERS) // Potential bug in singles (might be solved with simu hp reudction) effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY; break; case ABILITY_LIGHTNING_ROD: - if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_ELECTRIC && gMovesInfo[move].target != MOVE_TARGET_ALL_BATTLERS) // Potential bug in singles (might be solved with simu hp reudction) + if (B_REDIRECT_ABILITY_IMMUNITY >= GEN_5 && moveType == TYPE_ELECTRIC && GetMoveTarget(move) != MOVE_TARGET_ALL_BATTLERS) // Potential bug in singles (might be solved with simu hp reudction) effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY; break; case ABILITY_STORM_DRAIN: @@ -4316,7 +4329,7 @@ u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 mov effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY; break; case ABILITY_WIND_RIDER: - if (gMovesInfo[move].windMove && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER)) + if (IsWindMove(move) && !(GetBattlerMoveTargetType(battlerAtk, move) & MOVE_TARGET_USER)) effect = MOVE_ABSORBED_BY_STAT_INCREASE_ABILITY; break; case ABILITY_FLASH_FIRE: @@ -4328,6 +4341,43 @@ u32 CanAbilityAbsorbMove(u32 battlerAtk, u32 battlerDef, u32 abilityDef, u32 mov return effect; } +static inline u32 SetStartingFieldStatus(u32 flag, u32 message, u32 anim, u8 *timer) +{ + if (!(gFieldStatuses & flag)) + { + gBattleCommunication[MULTISTRING_CHOOSER] = message; + gFieldStatuses |= flag; + gBattleScripting.animArg1 = anim; + if (gBattleStruct->startingStatusTimer) + *timer = gBattleStruct->startingStatusTimer; + else + *timer = 0; // Infinite + + return 1; + } + + return 0; +} + +static inline u32 SetStartingSideStatus(u32 flag, u32 side, u32 message, u32 anim, u8 *timer) +{ + if (!(gSideStatuses[side] & flag)) + { + gBattlerAttacker = gBattlerTarget = side; + gBattleCommunication[MULTISTRING_CHOOSER] = message; + gSideStatuses[side] |= flag; + gBattleScripting.animArg1 = anim; + if (gBattleStruct->startingStatusTimer) + *timer = gBattleStruct->startingStatusTimer; + else + *timer = 0; // Infinite + + return 1; + } + + return 0; +} + u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 moveArg) { u32 effect = 0; @@ -4353,131 +4403,116 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 else move = gCurrentMove; - moveType = GetMoveType(move); + moveType = GetBattleMoveType(move); switch (caseID) { case ABILITYEFFECT_SWITCH_IN_STATUSES: // starting field/side/etc statuses with a variable { - u8 timerVal = gBattleStruct->startingStatusTimer; - gBattleScripting.battler = battler; switch (gBattleStruct->startingStatus) { case STARTING_STATUS_ELECTRIC_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; - gFieldStatuses |= STATUS_FIELD_ELECTRIC_TERRAIN; - if (timerVal == 0) - gFieldStatuses |= STATUS_FIELD_TERRAIN_PERMANENT; - else - gFieldTimers.terrainTimer = timerVal; - effect = 2; - } + effect = SetStartingFieldStatus(STATUS_FIELD_ELECTRIC_TERRAIN, + B_MSG_TERRAIN_SET_ELECTRIC, + 0, + &gFieldTimers.terrainTimer); + effect = (effect == 1) ? 2 : 0; break; case STARTING_STATUS_MISTY_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; - gFieldStatuses |= STATUS_FIELD_MISTY_TERRAIN; - if (timerVal == 0) - gFieldStatuses |= STATUS_FIELD_TERRAIN_PERMANENT; - else - gFieldTimers.terrainTimer = timerVal; - effect = 2; - } + effect = SetStartingFieldStatus(STATUS_FIELD_MISTY_TERRAIN, + B_MSG_TERRAIN_SET_MISTY, + 0, + &gFieldTimers.terrainTimer); + effect = (effect == 1) ? 2 : 0; break; case STARTING_STATUS_GRASSY_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_GRASSY; - gFieldStatuses |= STATUS_FIELD_GRASSY_TERRAIN; - if (timerVal == 0) - gFieldStatuses |= STATUS_FIELD_TERRAIN_PERMANENT; - else - gFieldTimers.terrainTimer = timerVal; - effect = 2; - } + effect = SetStartingFieldStatus(STATUS_FIELD_GRASSY_TERRAIN, + B_MSG_TERRAIN_SET_GRASSY, + 0, + &gFieldTimers.terrainTimer); + effect = (effect == 1) ? 2 : 0; break; case STARTING_STATUS_PSYCHIC_TERRAIN: - if (!(gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; - gFieldStatuses |= STATUS_FIELD_PSYCHIC_TERRAIN; - if (timerVal == 0) - gFieldStatuses |= STATUS_FIELD_TERRAIN_PERMANENT; - else - gFieldTimers.terrainTimer = timerVal; - effect = 2; - } + effect = SetStartingFieldStatus(STATUS_FIELD_PSYCHIC_TERRAIN, + B_MSG_TERRAIN_SET_PSYCHIC, + 0, + &gFieldTimers.terrainTimer); + effect = (effect == 1) ? 2 : 0; break; case STARTING_STATUS_TRICK_ROOM: - if (!(gFieldStatuses & STATUS_FIELD_TRICK_ROOM)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_TRICK_ROOM; - gFieldStatuses |= STATUS_FIELD_TRICK_ROOM; - gBattleScripting.animArg1 = B_ANIM_TRICK_ROOM; - if (timerVal == 0) - gFieldTimers.trickRoomTimer = 0; // infinite - else - gFieldTimers.trickRoomTimer = 5; - effect = 1; - } + effect = SetStartingFieldStatus(STATUS_FIELD_TRICK_ROOM, + B_MSG_SET_TRICK_ROOM, + B_ANIM_TRICK_ROOM, + &gFieldTimers.trickRoomTimer); break; case STARTING_STATUS_MAGIC_ROOM: - if (!(gFieldStatuses & STATUS_FIELD_MAGIC_ROOM)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_MAGIC_ROOM; - gFieldStatuses |= STATUS_FIELD_MAGIC_ROOM; - gBattleScripting.animArg1 = B_ANIM_MAGIC_ROOM; - if (timerVal == 0) - gFieldTimers.magicRoomTimer = 0; // infinite - else - gFieldTimers.magicRoomTimer = 5; - effect = 1; - } + effect = SetStartingFieldStatus(STATUS_FIELD_MAGIC_ROOM, + B_MSG_SET_MAGIC_ROOM, + B_ANIM_MAGIC_ROOM, + &gFieldTimers.magicRoomTimer); break; case STARTING_STATUS_WONDER_ROOM: - if (!(gFieldStatuses & STATUS_FIELD_WONDER_ROOM)) - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_WONDER_ROOM; - gFieldStatuses |= STATUS_FIELD_WONDER_ROOM; - gBattleScripting.animArg1 = B_ANIM_WONDER_ROOM; - if (timerVal == 0) - gFieldTimers.wonderRoomTimer = 0; // infinite - else - gFieldTimers.wonderRoomTimer = 5; - effect = 1; - } + effect = SetStartingFieldStatus(STATUS_FIELD_WONDER_ROOM, + B_MSG_SET_WONDER_ROOM, + B_ANIM_WONDER_ROOM, + &gFieldTimers.wonderRoomTimer); break; case STARTING_STATUS_TAILWIND_PLAYER: - if (!(gSideStatuses[B_SIDE_PLAYER] & SIDE_STATUS_TAILWIND)) - { - gBattlerAttacker = B_POSITION_PLAYER_LEFT; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_TAILWIND_PLAYER; - gSideStatuses[B_SIDE_PLAYER] |= SIDE_STATUS_TAILWIND; - gBattleScripting.animArg1 = B_ANIM_TAILWIND; - if (timerVal == 0) - gSideTimers[B_SIDE_PLAYER].tailwindTimer = 0; // infinite - else - gSideTimers[B_SIDE_PLAYER].tailwindTimer = 5; - effect = 1; - } + effect = SetStartingSideStatus(SIDE_STATUS_TAILWIND, + B_SIDE_PLAYER, + B_MSG_SET_TAILWIND, + B_ANIM_TAILWIND, + &gSideTimers[B_SIDE_PLAYER].tailwindTimer); break; case STARTING_STATUS_TAILWIND_OPPONENT: - if (!(gSideStatuses[B_SIDE_OPPONENT] & SIDE_STATUS_TAILWIND)) - { - gBattlerAttacker = B_POSITION_OPPONENT_LEFT; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SET_TAILWIND_OPPONENT; - gSideStatuses[B_SIDE_OPPONENT] |= SIDE_STATUS_TAILWIND; - gBattleScripting.animArg1 = B_ANIM_TAILWIND; - if (timerVal == 0) - gSideTimers[B_SIDE_OPPONENT].tailwindTimer = 0; // infinite - else - gSideTimers[B_SIDE_OPPONENT].tailwindTimer = 5; - effect = 1; - } + effect = SetStartingSideStatus(SIDE_STATUS_TAILWIND, + B_SIDE_OPPONENT, + B_MSG_SET_TAILWIND, + B_ANIM_TAILWIND, + &gSideTimers[B_SIDE_OPPONENT].tailwindTimer); + break; + case STARTING_STATUS_RAINBOW_PLAYER: + effect = SetStartingSideStatus(SIDE_STATUS_RAINBOW, + B_SIDE_PLAYER, + B_MSG_SET_RAINBOW, + B_ANIM_RAINBOW, + &gSideTimers[B_SIDE_PLAYER].rainbowTimer); + break; + case STARTING_STATUS_RAINBOW_OPPONENT: + effect = SetStartingSideStatus(SIDE_STATUS_RAINBOW, + B_SIDE_OPPONENT, + B_MSG_SET_RAINBOW, + B_ANIM_RAINBOW, + &gSideTimers[B_SIDE_OPPONENT].rainbowTimer); + break; + case STARTING_STATUS_SEA_OF_FIRE_PLAYER: + effect = SetStartingSideStatus(SIDE_STATUS_SEA_OF_FIRE, + B_SIDE_PLAYER, + B_MSG_SET_SEA_OF_FIRE, + B_ANIM_SEA_OF_FIRE, + &gSideTimers[B_SIDE_PLAYER].seaOfFireTimer); + break; + case STARTING_STATUS_SEA_OF_FIRE_OPPONENT: + effect = SetStartingSideStatus(SIDE_STATUS_SEA_OF_FIRE, + B_SIDE_OPPONENT, + B_MSG_SET_SEA_OF_FIRE, + B_ANIM_SEA_OF_FIRE, + &gSideTimers[B_SIDE_OPPONENT].seaOfFireTimer); + break; + case STARTING_STATUS_SWAMP_PLAYER: + effect = SetStartingSideStatus(SIDE_STATUS_SWAMP, + B_SIDE_PLAYER, + B_MSG_SET_SWAMP, + B_ANIM_SWAMP, + &gSideTimers[B_SIDE_PLAYER].swampTimer); + break; + case STARTING_STATUS_SWAMP_OPPONENT: + effect = SetStartingSideStatus(SIDE_STATUS_SWAMP, + B_SIDE_OPPONENT, + B_MSG_SET_SWAMP, + B_ANIM_SWAMP, + &gSideTimers[B_SIDE_OPPONENT].swampTimer); break; } @@ -4493,7 +4528,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM) { // overworld weather started rain, so just do electric terrain anim - gFieldStatuses = (STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); + gFieldStatuses = STATUS_FIELD_ELECTRIC_TERRAIN; + gFieldTimers.terrainTimer = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); effect++; @@ -4502,7 +4538,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) { - gFieldStatuses = (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); + gFieldStatuses = STATUS_FIELD_MISTY_TERRAIN; + gFieldTimers.terrainTimer = 0; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); effect++; @@ -4519,7 +4556,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case WEATHER_DOWNPOUR: if (!(gBattleWeather & B_WEATHER_RAIN)) { - gBattleWeather = (B_WEATHER_RAIN_TEMPORARY | B_WEATHER_RAIN_PERMANENT); + gBattleWeather = B_WEATHER_RAIN_NORMAL; gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES; effect++; } @@ -4535,7 +4572,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case WEATHER_DROUGHT: if (!(gBattleWeather & B_WEATHER_SUN)) { - gBattleWeather = (B_WEATHER_SUN_PERMANENT | B_WEATHER_SUN_TEMPORARY); + gBattleWeather = B_WEATHER_SUN_NORMAL; gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES; effect++; } @@ -4722,7 +4759,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 for (j = 0; j < MAX_MON_MOVES; j++) { move = gBattleMons[i].moves[j]; - moveType = GetMoveType(move); + moveType = GetBattleMoveType(move); if (CalcTypeEffectivenessMultiplier(move, moveType, i, battler, ABILITY_ANTICIPATION, FALSE) >= UQ_4_12(2.0)) { effect++; @@ -4851,7 +4888,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_DRIZZLE: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_RAIN, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_RAIN, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates); effect++; @@ -4864,7 +4901,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_SAND_STREAM: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_SANDSTORM, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SANDSTORM, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_SandstreamActivates); effect++; @@ -4877,7 +4914,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_DROUGHT: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_SUN, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); effect++; @@ -4890,12 +4927,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_SNOW_WARNING: - if (B_SNOW_WARNING >= GEN_9 && TryChangeBattleWeather(battler, ENUM_WEATHER_SNOW, TRUE)) + if (B_SNOW_WARNING >= GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_SNOW, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesSnow); effect++; } - else if (B_SNOW_WARNING < GEN_9 && TryChangeBattleWeather(battler, ENUM_WEATHER_HAIL, TRUE)) + else if (B_SNOW_WARNING < GEN_9 && TryChangeBattleWeather(battler, BATTLE_WEATHER_HAIL, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivatesHail); effect++; @@ -5029,21 +5066,21 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_DESOLATE_LAND: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_SUN_PRIMAL, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN_PRIMAL, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_DesolateLandActivates); effect++; } break; case ABILITY_PRIMORDIAL_SEA: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_RAIN_PRIMAL, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_RAIN_PRIMAL, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_PrimordialSeaActivates); effect++; } break; case ABILITY_DELTA_STREAM: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_STRONG_WINDS, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_STRONG_WINDS, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_DeltaStreamActivates); effect++; @@ -5086,7 +5123,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_ORICHALCUM_PULSE: - if (TryChangeBattleWeather(battler, ENUM_WEATHER_SUN, TRUE)) + if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SUN, TRUE)) { BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates); effect++; @@ -5210,7 +5247,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 SaveBattlerAttacker(gBattlerAttacker); gSpecialStatuses[battler].switchInAbilityDone = TRUE; gBattlerAttacker = partner; - gBattleStruct->commandingDondozo |= 1u << battler; + gBattleStruct->battlerState[battler].commandingDondozo = TRUE; gBattleStruct->commanderActive[partner] = gBattleMons[battler].species; gStatuses3[battler] |= STATUS3_COMMANDER; if (gBattleMons[battler].status2 & STATUS2_CONFUSION @@ -5463,7 +5500,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 default: if (GetChosenMovePriority(gBattlerAttacker) > 0 && BlocksPrankster(move, gBattlerAttacker, gBattlerTarget, TRUE) - && !(IS_MOVE_STATUS(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove))) + && !(IsBattleMoveStatus(move) && (gLastUsedAbility == ABILITY_MAGIC_BOUNCE || gProtectStructs[gBattlerTarget].bounceMove))) { if (!IsDoubleBattle() || !(GetBattlerMoveTargetType(gBattlerAttacker, move) & (MOVE_TARGET_BOTH | MOVE_TARGET_FOES_AND_ALLY))) @@ -5556,14 +5593,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 break; case MOVE_ABSORBED_BY_BOOST_FLASH_FIRE: gBattleStruct->pledgeMove = FALSE; - if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE)) + if (!gDisableStructs[battler].flashFireBoosted) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FLASH_FIRE_BOOST; if (gProtectStructs[gBattlerAttacker].notFirstStrike) gBattlescriptCurrInstr = BattleScript_FlashFireBoost; else gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss; - gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_FLASH_FIRE; + gDisableStructs[battler].flashFireBoosted = TRUE; } else { @@ -5670,7 +5707,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 // Not currently held by Sky Drop && !(gStatuses3[battler] & STATUS3_SKY_DROPPED)) { - gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_EMERGENCY_EXIT; + gDisableStructs[battler].startEmergencyExit = TRUE; effect++; } break; @@ -5678,11 +5715,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (MoveResultHasEffect(battler) && IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(battler) - && IS_MOVE_PHYSICAL(gCurrentMove) + && IsBattleMovePhysical(gCurrentMove) && (CompareStat(battler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN) // Don't activate if both Speed and Defense cannot be raised. || CompareStat(battler, STAT_DEF, MIN_STAT_STAGE, CMP_GREATER_THAN))) { - if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker)) + if (GetMoveEffect(gCurrentMove) == EFFECT_HIT_ESCAPE && CanBattlerSwitch(gBattlerAttacker)) gProtectStructs[battler].disableEjectPack = TRUE; // Set flag for target BattleScriptPushCursor(); @@ -5715,7 +5752,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsBattlerTurnDamaged(gBattlerTarget) && GetBattlerHoldEffect(gBattlerAttacker, TRUE) != HOLD_EFFECT_PROTECTIVE_PADS && IsMoveMakingContact(move, gBattlerAttacker) - && gBattleStruct->overwrittenAbilities[gBattlerAttacker] != GetBattlerAbility(gBattlerTarget) + && gDisableStructs[gBattlerAttacker].overwrittenAbility != GetBattlerAbility(gBattlerTarget) && gBattleMons[gBattlerAttacker].ability != ABILITY_MUMMY && gBattleMons[gBattlerAttacker].ability != ABILITY_LINGERING_AROMA && !gAbilitiesInfo[gBattleMons[gBattlerAttacker].ability].cantBeSuppressed) @@ -5727,7 +5764,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } gLastUsedAbility = gBattleMons[gBattlerAttacker].ability; - gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gBattleMons[gBattlerTarget].ability; + gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_MummyActivates; effect++; @@ -5750,8 +5787,8 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } gLastUsedAbility = gBattleMons[gBattlerAttacker].ability; - gBattleMons[gBattlerAttacker].ability = gBattleStruct->overwrittenAbilities[gBattlerAttacker] = gBattleMons[gBattlerTarget].ability; - gBattleMons[gBattlerTarget].ability = gBattleStruct->overwrittenAbilities[gBattlerTarget] = gLastUsedAbility; + gBattleMons[gBattlerAttacker].ability = gDisableStructs[gBattlerAttacker].overwrittenAbility = gBattleMons[gBattlerTarget].ability; + gBattleMons[gBattlerTarget].ability = gDisableStructs[gBattlerTarget].overwrittenAbility = gLastUsedAbility; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_WanderingSpiritActivates; effect++; @@ -5774,7 +5811,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_COLOR_CHANGE: if (MoveResultHasEffect(battler) && move != MOVE_STRUGGLE - && !IS_MOVE_STATUS(move) + && !IsBattleMoveStatus(move) && IsBattlerTurnDamaged(gBattlerTarget) && !IS_BATTLER_OF_TYPE(battler, moveType) && moveType != TYPE_STELLAR @@ -5853,7 +5890,15 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !IsBattlerAlive(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker)) { - gBattleStruct->moveDamage[gBattlerAttacker] = gSpecialStatuses[gBattlerTarget].shellBellDmg; + // Prevent Innards Out effect if Future Sight user is currently not on field + if (GetMoveEffect(gCurrentMove) == EFFECT_FUTURE_SIGHT) + { + if (gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] != gBattlerPartyIndexes[gBattlerAttacker] + && gWishFutureKnock.futureSightPartyIndex[gBattlerTarget] != BATTLE_PARTNER(gBattlerPartyIndexes[gBattlerAttacker])) + break; + } + + gBattleStruct->moveDamage[gBattlerAttacker] = gBattleStruct->moveDamage[gBattlerTarget]; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_AftermathDmg; effect++; @@ -5896,7 +5941,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && IsMoveMakingContact(move, gBattlerAttacker)) { if (IsSleepClauseEnabled()) - gBattleStruct->sleepClauseEffectExempt |= (1u << gBattlerAttacker); + gBattleStruct->battlerState[gBattlerAttacker].sleepClauseEffectExempt = TRUE; gBattleScripting.moveEffect = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_SLEEP; PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); BattleScriptPushCursor(); @@ -6033,7 +6078,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 gBattlescriptCurrInstr = BattleScript_BlockedByPrimalWeatherRet; effect++; } - else if (TryChangeBattleWeather(battler, ENUM_WEATHER_SANDSTORM, TRUE)) + else if (TryChangeBattleWeather(battler, BATTLE_WEATHER_SANDSTORM, TRUE)) { gBattleScripting.battler = battler; BattleScriptPushCursor(); @@ -6135,7 +6180,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_WIND_POWER: - if (!(gMovesInfo[gCurrentMove].windMove)) + if (!IsWindMove(gCurrentMove)) break; // fall through case ABILITY_ELECTROMORPHOSIS: @@ -6153,7 +6198,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (MoveResultHasEffect(gBattlerTarget) && (!gBattleStruct->isSkyBattle) && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && IS_MOVE_PHYSICAL(gCurrentMove) + && IsBattleMovePhysical(gCurrentMove) && IsBattlerTurnDamaged(gBattlerTarget) && (gSideTimers[GetBattlerSide(gBattlerAttacker)].toxicSpikesAmount != 2)) { @@ -6247,7 +6292,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 { case ABILITY_DANCER: if (IsBattlerAlive(battler) - && (gMovesInfo[gCurrentMove].danceMove) + && IsDanceMove(gCurrentMove) && !gSpecialStatuses[battler].dancerUsedMove && gBattlerAttacker != battler) { @@ -6438,9 +6483,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 // Prints message only. separate from ABILITYEFFECT_ON_SWITCHIN bc activates before entry hazards for (i = 0; i < gBattlersCount; i++) { - if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !(gBattleResources->flags->flags[i] & RESOURCE_FLAG_NEUTRALIZING_GAS)) + if (gBattleMons[i].ability == ABILITY_NEUTRALIZING_GAS && !gDisableStructs[i].neutralizingGas) { - gBattleResources->flags->flags[i] |= RESOURCE_FLAG_NEUTRALIZING_GAS; + gDisableStructs[i].neutralizingGas = TRUE; gBattlerAbility = i; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SWITCHIN_NEUTRALIZING_GAS; BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg); @@ -6497,22 +6542,32 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 } break; case ABILITY_ICE_FACE: - if (IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW) + { + u32 battlerWeatherAffected = IsBattlerWeatherAffected(battler, B_WEATHER_HAIL | B_WEATHER_SNOW); + if (battlerWeatherAffected && gBattleMons[battler].species == SPECIES_EISCUE) + { + // If Hail/Snow activates when in Eiscue is in base, prevent reversion when Eiscue Noice gets broken + gDisableStructs[battler].weatherAbilityDone = TRUE; + } + if (!gDisableStructs[battler].weatherAbilityDone + && battlerWeatherAffected && gBattleMons[battler].species == SPECIES_EISCUE_NOICE && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED)) { // TODO: Convert this to a proper FORM_CHANGE type. gBattleScripting.battler = battler; + gDisableStructs[battler].weatherAbilityDone = TRUE; gBattleMons[battler].species = SPECIES_EISCUE_ICE; BattleScriptPushCursorAndCallback(BattleScript_BattlerFormChangeWithStringEnd3); effect++; } break; + } case ABILITY_PROTOSYNTHESIS: if (!gDisableStructs[battler].weatherAbilityDone && (gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) - && !(gBattleStruct->boosterEnergyActivates & (1u << battler))) + && !gDisableStructs[battler].boosterEnergyActivates) { gDisableStructs[battler].weatherAbilityDone = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); @@ -6541,7 +6596,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 if (!gDisableStructs[battler].terrainAbilityDone && gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED) - && !(gBattleStruct->boosterEnergyActivates & (1u << battler))) + && !gDisableStructs[battler].boosterEnergyActivates) { gDisableStructs[battler].terrainAbilityDone = TRUE; PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); @@ -6565,7 +6620,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 bool32 TryPrimalReversion(u32 battler) { if (GetBattlerHoldEffect(battler, FALSE) == HOLD_EFFECT_PRIMAL_ORB - && GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != SPECIES_NONE) + && GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_PRIMAL_REVERSION) != gBattleMons[battler].species) { gBattleScripting.battler = battler; BattleScriptPushCursorAndCallback(BattleScript_PrimalReversion); @@ -6593,12 +6648,12 @@ bool32 IsMoldBreakerTypeAbility(u32 battler, u32 ability) return FALSE; return (ability == ABILITY_MOLD_BREAKER || ability == ABILITY_TERAVOLT || ability == ABILITY_TURBOBLAZE - || (ability == ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gCurrentMove))); + || (ability == ABILITY_MYCELIUM_MIGHT && IsBattleMoveStatus(gCurrentMove))); } static inline bool32 CanBreakThroughAbility(u32 battlerAtk, u32 battlerDef, u32 ability) { - return ((IsMoldBreakerTypeAbility(battlerAtk, ability) || gMovesInfo[gCurrentMove].ignoresTargetAbility) + return ((IsMoldBreakerTypeAbility(battlerAtk, ability) || MoveIgnoresTargetAbility(gCurrentMove)) && battlerDef != battlerAtk && gAbilitiesInfo[gBattleMons[battlerDef].ability].breakable && gBattlerByTurnOrder[gCurrentTurnActionNumber] == battlerAtk @@ -7002,7 +7057,7 @@ static u32 TrySetMicleBerry(u32 battler, u32 itemId, enum ItemEffect caseID) { if (HasEnoughHpToEatBerry(battler, 4, itemId)) { - gBattleStruct->usedMicleBerry |= 1u << battler; + gBattleStruct->battlerState[battler].usedMicleBerry = TRUE; if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) { BattleScriptExecute(BattleScript_MicleBerryActivateEnd2); @@ -7162,9 +7217,8 @@ static u32 ItemHealHp(u32 battler, u32 itemId, enum ItemEffect caseID, bool32 pe BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ItemHealHP_RemoveItemRet; } - if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_EMERGENCY_EXIT - && GetNonDynamaxHP(battler) >= GetNonDynamaxMaxHP(battler) / 2) - gBattleResources->flags->flags[battler] &= ~RESOURCE_FLAG_EMERGENCY_EXIT; + if (gDisableStructs[battler].startEmergencyExit && GetNonDynamaxHP(battler) >= GetNonDynamaxMaxHP(battler) / 2) + gDisableStructs[battler].startEmergencyExit = FALSE; return ITEM_HP_CHANGE; } @@ -7261,7 +7315,7 @@ static u32 TryConsumeMirrorHerb(u32 battler, enum ItemEffect caseID) static inline u32 TryBoosterEnergy(u32 battler, enum ItemEffect caseID) { - if (gBattleStruct->boosterEnergyActivates & (1u << battler) || gBattleMons[battler].status2 & STATUS2_TRANSFORMED) + if (gDisableStructs[battler].boosterEnergyActivates || gBattleMons[battler].status2 & STATUS2_TRANSFORMED) return ITEM_NO_EFFECT; if (((GetBattlerAbility(battler) == ABILITY_PROTOSYNTHESIS) && !((gBattleWeather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT)) @@ -7269,7 +7323,7 @@ static inline u32 TryBoosterEnergy(u32 battler, enum ItemEffect caseID) { PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler)); gBattlerAbility = gBattleScripting.battler = battler; - gBattleStruct->boosterEnergyActivates |= 1u << battler; + gDisableStructs[battler].boosterEnergyActivates = TRUE; if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN || caseID == ITEMEFFECT_NORMAL) { BattleScriptExecute(BattleScript_BoosterEnergyEnd2); @@ -8103,7 +8157,7 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) if (gBattleStruct->moveDamage[battler] != 0 // Need to have done damage && MoveResultHasEffect(gBattlerTarget) && IsBattlerTurnDamaged(gBattlerTarget) - && !gMovesInfo[gCurrentMove].ignoresKingsRock + && !MoveIgnoresKingsRock(gCurrentMove) && gBattleMons[gBattlerTarget].hp && RandomPercentage(RNG_HOLD_EFFECT_FLINCH, atkHoldEffectParam) && ability != ABILITY_STENCH) @@ -8135,19 +8189,21 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) switch (atkHoldEffect) { case HOLD_EFFECT_SHELL_BELL: - if (gSpecialStatuses[gBattlerAttacker].damagedMons // Need to have done damage + if (gBattleScripting.savedDmg > 0 + && MoveResultHasEffect(battler) && gBattlerAttacker != gBattlerTarget - && gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP + && !IsBattlerAtMaxHp(gBattlerAttacker) && IsBattlerAlive(gBattlerAttacker) + && gMovesInfo[gCurrentMove].effect != EFFECT_FUTURE_SIGHT + && gMovesInfo[gCurrentMove].effect != EFFECT_PAIN_SPLIT && (B_HEAL_BLOCKING < GEN_5 || !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))) { gLastUsedItem = atkItem; gPotentialItemEffectBattler = gBattlerAttacker; gBattleScripting.battler = gBattlerAttacker; - gBattleStruct->moveDamage[gBattlerAttacker] = (gSpecialStatuses[gBattlerTarget].shellBellDmg / atkHoldEffectParam) * -1; + gBattleStruct->moveDamage[gBattlerAttacker] = (gBattleScripting.savedDmg / atkHoldEffectParam) * -1; if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) gBattleStruct->moveDamage[gBattlerAttacker] = -1; - gSpecialStatuses[gBattlerTarget].shellBellDmg = 0; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret; effect = ITEM_HP_CHANGE; @@ -8155,11 +8211,11 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) break; case HOLD_EFFECT_LIFE_ORB: if (IsBattlerAlive(gBattlerAttacker) + && (IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveDamage[gBattlerTarget]) // Needs the second check in case of Substitute && !(TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && !gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage - && gSpecialStatuses[gBattlerAttacker].damagedMons) + && !gSpecialStatuses[gBattlerAttacker].preventLifeOrbDamage) { gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 10; if (gBattleStruct->moveDamage[gBattlerAttacker] == 0) @@ -8167,13 +8223,13 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) effect = ITEM_HP_CHANGE; BattleScriptPushCursor(); gBattlescriptCurrInstr = BattleScript_ItemHurtRet; - gLastUsedItem = gBattleMons[gBattlerAttacker].item; + gLastUsedItem = atkItem; } break; case HOLD_EFFECT_THROAT_SPRAY: // Does NOT need to be a damaging move if (gProtectStructs[gBattlerAttacker].targetAffected && IsBattlerAlive(gBattlerAttacker) - && gMovesInfo[gCurrentMove].soundMove + && IsSoundMove(gCurrentMove) && CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN) && !NoAliveMonsForEitherParty()) // Don't activate if battle will end { @@ -8190,7 +8246,7 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) case ITEMEFFECT_TARGET: if (MoveResultHasEffect(gBattlerTarget)) { - moveType = GetMoveType(gCurrentMove); + moveType = GetBattleMoveType(gCurrentMove); switch (battlerHoldEffect) { case HOLD_EFFECT_AIR_BALLOON: @@ -8279,7 +8335,7 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) if (IsBattlerAlive(battler) && IsBattlerTurnDamaged(gBattlerTarget) && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IS_MOVE_PHYSICAL(gCurrentMove) + && IsBattleMovePhysical(gCurrentMove) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) { gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; @@ -8299,7 +8355,7 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) if (IsBattlerAlive(battler) && IsBattlerTurnDamaged(gBattlerTarget) && !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove) - && IS_MOVE_SPECIAL(gCurrentMove) + && IsBattleMoveSpecial(gCurrentMove) && GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) { gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 8; @@ -8323,7 +8379,7 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) break; case HOLD_EFFECT_CURE_STATUS: // only Toxic Chain's interaction with Knock Off case HOLD_EFFECT_CURE_PSN: - if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem) && GetBattlerAbility(gBattlerAttacker) == ABILITY_TOXIC_CHAIN && gMovesInfo[gCurrentMove].effect == EFFECT_KNOCK_OFF) + if (gBattleMons[battler].status1 & STATUS1_PSN_ANY && !UnnerveOn(battler, gLastUsedItem) && GetBattlerAbility(gBattlerAttacker) == ABILITY_TOXIC_CHAIN && GetMoveEffect(gCurrentMove) == EFFECT_KNOCK_OFF) { gBattleScripting.battler = battler; gBattleMons[battler].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); @@ -8409,6 +8465,18 @@ u32 ItemBattleEffects(enum ItemEffect caseID, u32 battler, bool32 moveTurn) gBattlescriptCurrInstr = BattleScript_WhiteHerbRet; } break; + case HOLD_EFFECT_EJECT_PACK: + if (gProtectStructs[battler].statFell + && gProtectStructs[battler].disableEjectPack == 0 + && CountUsablePartyMons(battler) > 0) + { + gBattleScripting.battler = battler; + gPotentialItemEffectBattler = battler; + effect = ITEM_STATS_CHANGE; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_EjectPackActivates; + } + break; } break; } @@ -8457,11 +8525,11 @@ u32 SetRandomTarget(u32 battlerAtk) return target; } -u32 GetMoveTarget(u16 move, u8 setTarget) +u32 GetBattleMoveTarget(u16 move, u8 setTarget) { u8 targetBattler = 0; u32 moveTarget, side; - u32 moveType = GetMoveType(move); + u32 moveType = GetBattleMoveType(move); if (setTarget != NO_TARGET_OVERRIDE) moveTarget = setTarget - 1; @@ -8478,22 +8546,36 @@ u32 GetMoveTarget(u16 move, u8 setTarget) } else { + u32 battlerAbilityOnField = 0; + targetBattler = SetRandomTarget(gBattlerAttacker); - if (moveType == TYPE_ELECTRIC - && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_LIGHTNING_ROD) - && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) + if (moveType == TYPE_ELECTRIC && GetBattlerAbility(targetBattler) != ABILITY_LIGHTNING_ROD) { - targetBattler ^= BIT_FLANK; - RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + if (B_REDIRECT_ABILITY_ALLIES >= GEN_4) + battlerAbilityOnField = IsAbilityOnField(ABILITY_LIGHTNING_ROD); + else + battlerAbilityOnField = IsAbilityOnOpposingSide(targetBattler, ABILITY_LIGHTNING_ROD); + + if (battlerAbilityOnField > 0) + { + targetBattler = battlerAbilityOnField - 1; + RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); + gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + } } - else if (moveType == TYPE_WATER - && IsAbilityOnOpposingSide(gBattlerAttacker, ABILITY_STORM_DRAIN) - && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) + else if (moveType == TYPE_WATER && GetBattlerAbility(targetBattler) != ABILITY_STORM_DRAIN) { - targetBattler ^= BIT_FLANK; - RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); - gSpecialStatuses[targetBattler].stormDrainRedirected = TRUE; + if (B_REDIRECT_ABILITY_ALLIES >= GEN_4) + battlerAbilityOnField = IsAbilityOnField(ABILITY_STORM_DRAIN); + else + battlerAbilityOnField = IsAbilityOnOpposingSide(targetBattler, ABILITY_STORM_DRAIN); + + if (battlerAbilityOnField > 0) + { + targetBattler = battlerAbilityOnField - 1; + RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); + gSpecialStatuses[targetBattler].lightningRodRedirected = TRUE; + } } } break; @@ -8598,7 +8680,8 @@ u8 GetAttackerObedienceForAction() // is not obedient if (gCurrentMove == MOVE_RAGE) gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RAGE; - if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (gMovesInfo[gCurrentMove].effect == EFFECT_SNORE || gMovesInfo[gCurrentMove].effect == EFFECT_SLEEP_TALK)) + u32 moveEffect = GetMoveEffect(gCurrentMove); + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (moveEffect == EFFECT_SNORE || moveEffect == EFFECT_SLEEP_TALK)) return DISOBEYS_WHILE_ASLEEP; calc = (levelReferenced + obedienceLevel) * ((rnd >> 8) & 255) >> 8; @@ -8686,14 +8769,14 @@ bool32 IsMoveMakingContact(u32 move, u32 battlerAtk) { u32 atkHoldEffect = GetBattlerHoldEffect(battlerAtk, TRUE); - if (!gMovesInfo[move].makesContact) + if (!MoveMakesContact(move)) { - if (gMovesInfo[move].effect == EFFECT_SHELL_SIDE_ARM && gBattleStruct->shellSideArmCategory[battlerAtk][gBattlerTarget] == DAMAGE_CATEGORY_PHYSICAL) + if (GetMoveEffect(move) == EFFECT_SHELL_SIDE_ARM && gBattleStruct->shellSideArmCategory[battlerAtk][gBattlerTarget] == DAMAGE_CATEGORY_PHYSICAL) return TRUE; else return FALSE; } - else if ((atkHoldEffect == HOLD_EFFECT_PUNCHING_GLOVE && gMovesInfo[move].punchingMove) + else if ((atkHoldEffect == HOLD_EFFECT_PUNCHING_GLOVE && IsPunchingMove(move)) || GetBattlerAbility(battlerAtk) == ABILITY_LONG_REACH) { return FALSE; @@ -8709,7 +8792,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) bool32 isProtected = FALSE; if ((IsZMove(move) || IsMaxMove(move)) - && (!gProtectStructs[battlerDef].maxGuarded || gMovesInfo[move].argument.maxEffect == MAX_EFFECT_BYPASS_PROTECT)) + && (!gProtectStructs[battlerDef].maxGuarded || GetMoveMaxEffect(move) == MAX_EFFECT_BYPASS_PROTECT)) isProtected = FALSE; // Z-Moves and Max Moves bypass protection (except Max Guard). else if (gProtectStructs[battlerDef].maxGuarded && IsMoveBlockedByMaxGuard(move)) isProtected = TRUE; @@ -8717,9 +8800,9 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) && IsMoveMakingContact(move, gBattlerAttacker) && GetBattlerAbility(gBattlerAttacker) == ABILITY_UNSEEN_FIST) isProtected = FALSE; - else if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_CRAFTY_SHIELD && IS_MOVE_STATUS(move) && gMovesInfo[move].effect != EFFECT_COACHING) + else if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_CRAFTY_SHIELD && IsBattleMoveStatus(move) && GetMoveEffect(move) != EFFECT_COACHING) isProtected = TRUE; - else if (gMovesInfo[move].ignoresProtect) + else if (MoveIgnoresProtect(move)) isProtected = FALSE; else if (gProtectStructs[battlerDef].protected) isProtected = TRUE; @@ -8730,11 +8813,11 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) isProtected = TRUE; else if (gProtectStructs[battlerDef].burningBulwarked) isProtected = TRUE; - else if ((gProtectStructs[battlerDef].obstructed || gProtectStructs[battlerDef].silkTrapped) && !IS_MOVE_STATUS(move)) + else if ((gProtectStructs[battlerDef].obstructed || gProtectStructs[battlerDef].silkTrapped) && !IsBattleMoveStatus(move)) isProtected = TRUE; else if (gProtectStructs[battlerDef].spikyShielded) isProtected = TRUE; - else if (gProtectStructs[battlerDef].kingsShielded && !IS_MOVE_STATUS(move)) + else if (gProtectStructs[battlerDef].kingsShielded && !IsBattleMoveStatus(move)) isProtected = TRUE; else if (gProtectStructs[battlerDef].maxGuarded) isProtected = TRUE; @@ -8742,7 +8825,7 @@ bool32 IsBattlerProtected(u32 battlerAtk, u32 battlerDef, u32 move) && GetChosenMovePriority(gBattlerAttacker) > 0) isProtected = TRUE; else if (gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_MAT_BLOCK - && !IS_MOVE_STATUS(move)) + && !IsBattleMoveStatus(move)) isProtected = TRUE; else isProtected = FALSE; @@ -9008,7 +9091,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData u32 move = damageCalcData->move; u32 i; - u32 basePower = gMovesInfo[move].power; + u32 basePower = GetMovePower(move); u32 weight, hpFraction, speed; if (GetActiveGimmick(battlerAtk) == GIMMICK_Z_MOVE) @@ -9017,7 +9100,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX) return GetMaxMovePower(move); - switch (gMovesInfo[move].effect) + switch (GetMoveEffect(move)) { case EFFECT_PLEDGE: if (gBattleStruct->pledgeMove) @@ -9057,7 +9140,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData basePower = gBattleStruct->presentBasePower; break; case EFFECT_TRIPLE_KICK: - basePower *= 1 + gMovesInfo[move].strikeCount - gMultiHitCounter; + basePower *= 1 + GetMoveStrikeCount(move) - gMultiHitCounter; break; case EFFECT_SPIT_UP: basePower = 100 * gDisableStructs[battlerAtk].stockpileCounter; @@ -9074,7 +9157,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData basePower *= 2; break; case EFFECT_PURSUIT: - if (gBattleStruct->pursuitTarget & (1u << battlerDef)) + if (gBattleStruct->battlerState[battlerDef].pursuitTarget) basePower *= 2; break; case EFFECT_NATURAL_GIFT: @@ -9082,8 +9165,8 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData break; case EFFECT_DOUBLE_POWER_ON_ARG_STATUS: // Comatose targets treated as if asleep - if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & gMovesInfo[move].argument.status - && !((gMovesInfo[move].additionalEffects->moveEffect == MOVE_EFFECT_REMOVE_STATUS) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) + if ((gBattleMons[battlerDef].status1 | (STATUS1_SLEEP * (abilityDef == ABILITY_COMATOSE))) & GetMoveEffectArg_Status(move) + && !((GetMoveAdditionalEffectById(move, 0)->moveEffect == MOVE_EFFECT_REMOVE_STATUS) && DoesSubstituteBlockMove(battlerAtk, battlerDef, move))) { basePower *= 2; } @@ -9171,7 +9254,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData case EFFECT_ROUND: for (i = 0; i < gBattlersCount; i++) { - if (i != battlerAtk && IsBattlerAlive(i) && gLastMoves[i] == MOVE_ROUND) + if (i != battlerAtk && IsBattlerAlive(i) && GetMoveEffect(gLastUsedMove) == EFFECT_ROUND) { basePower *= 2; break; @@ -9179,7 +9262,7 @@ static inline u32 CalcMoveBasePower(struct DamageCalculationData *damageCalcData } break; case EFFECT_FUSION_COMBO: - if (gMovesInfo[gLastUsedMove].effect == EFFECT_FUSION_COMBO && move != gLastUsedMove) + if (GetMoveEffect(gLastUsedMove) == EFFECT_FUSION_COMBO && move != gLastUsedMove) basePower *= 2; break; case EFFECT_LASH_OUT: @@ -9277,13 +9360,14 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * u32 battlerDef = damageCalcData->battlerDef; u32 move = damageCalcData->move; u32 moveType = damageCalcData->moveType; + u32 moveEffect = GetMoveEffect(move); uq4_12_t holdEffectModifier; uq4_12_t modifier = UQ_4_12(1.0); u32 atkSide = GetBattlerSide(battlerAtk); // move effect - switch (gMovesInfo[move].effect) + switch (moveEffect) { case EFFECT_FACADE: if (gBattleMons[battlerAtk].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_PARALYSIS | STATUS1_FROSTBITE)) @@ -9302,7 +9386,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(0.5)); break; case EFFECT_STOMPING_TANTRUM: - if (gBattleStruct->lastMoveFailed & (1u << battlerAtk)) + if (gBattleStruct->battlerState[battlerAtk].lastMoveFailed) modifier = uq4_12_multiply(modifier, UQ_4_12(2.0)); break; case EFFECT_MAGNITUDE: @@ -9351,19 +9435,19 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_FLARE_BOOST: - if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && IS_MOVE_SPECIAL(move)) + if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_TOXIC_BOOST: - if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && IS_MOVE_PHYSICAL(move)) + if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && IsBattleMovePhysical(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_RECKLESS: - if (IS_MOVE_RECOIL(move)) + if (IsBattleMoveRecoil(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.2)); break; case ABILITY_IRON_FIST: - if (gMovesInfo[move].punchingMove) + if (IsPunchingMove(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.2)); break; case ABILITY_SHEER_FORCE: @@ -9390,11 +9474,11 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); break; case ABILITY_STRONG_JAW: - if (gMovesInfo[move].bitingMove) + if (IsBitingMove(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_MEGA_LAUNCHER: - if (gMovesInfo[move].pulseMove) + if (IsPulseMove(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_WATER_BUBBLE: @@ -9426,7 +9510,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(1.2)); break; case ABILITY_PUNK_ROCK: - if (gMovesInfo[move].soundMove) + if (IsSoundMove(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); break; case ABILITY_STEELY_SPIRIT: @@ -9434,7 +9518,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_SHARPNESS: - if (gMovesInfo[move].slicingMove) + if (IsSlicingMove(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_SUPREME_OVERLORD: @@ -9458,7 +9542,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * switch (GetBattlerAbility(BATTLE_PARTNER(battlerAtk))) { case ABILITY_BATTERY: - if (IS_MOVE_SPECIAL(move)) + if (IsBattleMoveSpecial(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); break; case ABILITY_POWER_SPOT: @@ -9490,8 +9574,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * case ABILITY_PROTOSYNTHESIS: { u8 defHighestStat = GetHighestStatId(battlerDef); - if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerDef)) - && ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)) + if (((weather & B_WEATHER_SUN && WEATHER_HAS_EFFECT) || gDisableStructs[battlerDef].boosterEnergyActivates) + && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } @@ -9499,8 +9583,8 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * case ABILITY_QUARK_DRIVE: { u8 defHighestStat = GetHighestStatId(battlerDef); - if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerDef)) - && ((IS_MOVE_PHYSICAL(move) && defHighestStat == STAT_DEF) || (IS_MOVE_SPECIAL(move) && defHighestStat == STAT_SPDEF)) + if ((gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerDef].boosterEnergyActivates) + && ((IsBattleMovePhysical(move) && defHighestStat == STAT_DEF) || (IsBattleMoveSpecial(move) && defHighestStat == STAT_SPDEF)) && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED)) modifier = uq4_12_multiply(modifier, UQ_4_12(0.7)); } @@ -9517,11 +9601,11 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * switch (holdEffectAtk) { case HOLD_EFFECT_MUSCLE_BAND: - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12_Floored(holdEffectParamAtk))); break; case HOLD_EFFECT_WISE_GLASSES: - if (IS_MOVE_SPECIAL(move)) + if (IsBattleMoveSpecial(move)) modifier = uq4_12_multiply(modifier, uq4_12_add(UQ_4_12(1.0), PercentToUQ4_12_Floored(holdEffectParamAtk))); break; case HOLD_EFFECT_LUSTROUS_ORB: @@ -9539,7 +9623,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * case HOLD_EFFECT_SOUL_DEW: if ((gBattleMons[battlerAtk].species == SPECIES_LATIAS || gBattleMons[battlerAtk].species == SPECIES_LATIOS) && ((B_SOUL_DEW_BOOST >= GEN_7 && (moveType == TYPE_PSYCHIC || moveType == TYPE_DRAGON)) - || (B_SOUL_DEW_BOOST < GEN_7 && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && IS_MOVE_SPECIAL(move)))) + || (B_SOUL_DEW_BOOST < GEN_7 && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER) && IsBattleMoveSpecial(move)))) modifier = uq4_12_multiply(modifier, holdEffectModifier); break; case HOLD_EFFECT_BUG_POWER: @@ -9575,7 +9659,7 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * modifier = uq4_12_multiply(modifier, holdEffectModifier); break; case HOLD_EFFECT_PUNCHING_GLOVE: - if (gMovesInfo[move].punchingMove) + if (IsPunchingMove(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.1)); break; case HOLD_EFFECT_OGERPON_MASK: @@ -9589,9 +9673,12 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData * && (moveType == GetBattlerTeraType(battlerAtk) || (GetBattlerTeraType(battlerAtk) == TYPE_STELLAR && IsTypeStellarBoosted(battlerAtk, moveType))) && uq4_12_multiply_by_int_half_down(modifier, basePower) < 60 - && gMovesInfo[move].strikeCount < 2 - && gMovesInfo[move].effect != EFFECT_MULTI_HIT - && gMovesInfo[move].priority == 0) + && GetMovePower(move) > 1 + && GetMoveStrikeCount(move) < 2 + && moveEffect != EFFECT_POWER_BASED_ON_USER_HP + && moveEffect != EFFECT_POWER_BASED_ON_TARGET_HP + && moveEffect != EFFECT_MULTI_HIT + && GetMovePriority(move) == 0) { return 60; } @@ -9609,12 +9696,13 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u u32 battlerDef = damageCalcData->battlerDef; u32 move = damageCalcData->move; u32 moveType = damageCalcData->moveType; + u32 moveEffect = GetMoveEffect(move); atkBaseSpeciesId = GET_BASE_SPECIES_ID(gBattleMons[battlerAtk].species); - if (gMovesInfo[move].effect == EFFECT_FOUL_PLAY) + if (moveEffect == EFFECT_FOUL_PLAY) { - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) { atkStat = gBattleMons[battlerDef].attack; atkStage = gBattleMons[battlerDef].statStages[STAT_ATK]; @@ -9625,9 +9713,9 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u atkStage = gBattleMons[battlerDef].statStages[STAT_SPATK]; } } - else if (gMovesInfo[move].effect == EFFECT_BODY_PRESS) + else if (moveEffect == EFFECT_BODY_PRESS) { - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) { atkStat = gBattleMons[battlerAtk].defense; // Edge case: Body Press used during Wonder Room. For some reason, it still uses Defense over Sp.Def, but uses Sp.Def stat changes @@ -9644,7 +9732,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u } else { - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) { atkStat = gBattleMons[battlerAtk].attack; atkStage = gBattleMons[battlerAtk].statStages[STAT_ATK]; @@ -9674,7 +9762,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u { case ABILITY_HUGE_POWER: case ABILITY_PURE_POWER: - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case ABILITY_SLOW_START: @@ -9682,7 +9770,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5)); break; case ABILITY_SOLAR_POWER: - if (IS_MOVE_SPECIAL(move) && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN)) + if (IsBattleMoveSpecial(move) && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case ABILITY_DEFEATIST: @@ -9690,7 +9778,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.5)); break; case ABILITY_FLASH_FIRE: - if (moveType == TYPE_FIRE && gBattleResources->flags->flags[battlerAtk] & RESOURCE_FLAG_FLASH_FIRE) + if (moveType == TYPE_FIRE && gDisableStructs[battlerAtk].flashFireBoosted) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case ABILITY_SWARM: @@ -9710,7 +9798,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case ABILITY_PLUS: - if (IS_MOVE_SPECIAL(move) && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) + if (IsBattleMoveSpecial(move) && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) { u32 partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk)); if (partnerAbility == ABILITY_MINUS @@ -9719,7 +9807,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u } break; case ABILITY_MINUS: - if (IS_MOVE_SPECIAL(move) && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) + if (IsBattleMoveSpecial(move) && IsBattlerAlive(BATTLE_PARTNER(battlerAtk))) { u32 partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk)); if (partnerAbility == ABILITY_PLUS @@ -9728,11 +9816,11 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u } break; case ABILITY_FLOWER_GIFT: - if (gBattleMons[battlerAtk].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN) && IS_MOVE_PHYSICAL(move)) + if (gBattleMons[battlerAtk].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(battlerAtk, B_WEATHER_SUN) && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case ABILITY_HUSTLE: - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case ABILITY_STAKEOUT: @@ -9740,7 +9828,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case ABILITY_GUTS: - if (gBattleMons[battlerAtk].status1 & STATUS1_ANY && IS_MOVE_PHYSICAL(move)) + if (gBattleMons[battlerAtk].status1 & STATUS1_ANY && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case ABILITY_TRANSISTOR: @@ -9757,7 +9845,7 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_GORILLA_TACTICS: - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.5)); break; case ABILITY_ROCKY_PAYLOAD: @@ -9768,9 +9856,9 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED)) { u32 atkHighestStat = GetHighestStatId(battlerAtk); - if (((weather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT) || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk)) + if (((weather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT) || gDisableStructs[battlerAtk].boosterEnergyActivates) { - if ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)) + if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); } } @@ -9779,19 +9867,19 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u if (!(gBattleMons[battlerAtk].status2 & STATUS2_TRANSFORMED)) { u32 atkHighestStat = GetHighestStatId(battlerAtk); - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gBattleStruct->boosterEnergyActivates & (1u << battlerAtk)) + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN || gDisableStructs[battlerAtk].boosterEnergyActivates) { - if ((IS_MOVE_PHYSICAL(move) && atkHighestStat == STAT_ATK) || (IS_MOVE_SPECIAL(move) && atkHighestStat == STAT_SPATK)) + if ((IsBattleMovePhysical(move) && atkHighestStat == STAT_ATK) || (IsBattleMoveSpecial(move) && atkHighestStat == STAT_SPATK)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3)); } } break; case ABILITY_ORICHALCUM_PULSE: - if ((weather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT && IS_MOVE_PHYSICAL(move)) + if ((weather & B_WEATHER_SUN) && WEATHER_HAS_EFFECT && IsBattleMovePhysical(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3333)); break; case ABILITY_HADRON_ENGINE: - if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && IS_MOVE_SPECIAL(move)) + if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply(modifier, UQ_4_12(1.3333)); break; } @@ -9815,49 +9903,49 @@ static inline u32 CalcAttackStat(struct DamageCalculationData *damageCalcData, u switch (GetBattlerAbility(BATTLE_PARTNER(battlerAtk))) { case ABILITY_FLOWER_GIFT: - if (gBattleMons[BATTLE_PARTNER(battlerAtk)].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerAtk), B_WEATHER_SUN) && IS_MOVE_PHYSICAL(move)) + if (gBattleMons[BATTLE_PARTNER(battlerAtk)].species == SPECIES_CHERRIM_SUNSHINE && IsBattlerWeatherAffected(BATTLE_PARTNER(battlerAtk), B_WEATHER_SUN) && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; } } // field abilities - if (IsAbilityOnField(ABILITY_VESSEL_OF_RUIN) && atkAbility != ABILITY_VESSEL_OF_RUIN && IS_MOVE_SPECIAL(move)) + if (IsAbilityOnField(ABILITY_VESSEL_OF_RUIN) && atkAbility != ABILITY_VESSEL_OF_RUIN && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75)); - if (IsAbilityOnField(ABILITY_TABLETS_OF_RUIN) && atkAbility != ABILITY_TABLETS_OF_RUIN && IS_MOVE_PHYSICAL(move)) + if (IsAbilityOnField(ABILITY_TABLETS_OF_RUIN) && atkAbility != ABILITY_TABLETS_OF_RUIN && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(0.75)); // attacker's hold effect switch (holdEffectAtk) { case HOLD_EFFECT_THICK_CLUB: - if ((atkBaseSpeciesId == SPECIES_CUBONE || atkBaseSpeciesId == SPECIES_MAROWAK) && IS_MOVE_PHYSICAL(move)) + if ((atkBaseSpeciesId == SPECIES_CUBONE || atkBaseSpeciesId == SPECIES_MAROWAK) && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case HOLD_EFFECT_DEEP_SEA_TOOTH: - if (gBattleMons[battlerAtk].species == SPECIES_CLAMPERL && IS_MOVE_SPECIAL(move)) + if (gBattleMons[battlerAtk].species == SPECIES_CLAMPERL && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case HOLD_EFFECT_LIGHT_BALL: - if (atkBaseSpeciesId == SPECIES_PIKACHU && (B_LIGHT_BALL_ATTACK_BOOST >= GEN_4 || IS_MOVE_SPECIAL(move))) + if (atkBaseSpeciesId == SPECIES_PIKACHU && (B_LIGHT_BALL_ATTACK_BOOST >= GEN_4 || IsBattleMoveSpecial(move))) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(2.0)); break; case HOLD_EFFECT_CHOICE_BAND: - if (IS_MOVE_PHYSICAL(move) && GetActiveGimmick(battlerAtk) != GIMMICK_DYNAMAX) + if (IsBattleMovePhysical(move) && GetActiveGimmick(battlerAtk) != GIMMICK_DYNAMAX) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; case HOLD_EFFECT_CHOICE_SPECS: - if (IS_MOVE_SPECIAL(move) && GetActiveGimmick(battlerAtk) != GIMMICK_DYNAMAX) + if (IsBattleMoveSpecial(move) && GetActiveGimmick(battlerAtk) != GIMMICK_DYNAMAX) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.5)); break; } // The offensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the 1st badge and 7th badges. // Having the 1st badge boosts physical attack while having the 7th badge boosts special attack. - if (ShouldGetStatBadgeBoost(FLAG_BADGE01_GET, battlerAtk) && IS_MOVE_PHYSICAL(move)) + if (ShouldGetStatBadgeBoost(FLAG_BADGE01_GET, battlerAtk) && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); - if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerAtk) && IS_MOVE_SPECIAL(move)) + if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerAtk) && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); return uq4_12_multiply_by_int_half_down(modifier, atkStat); @@ -9889,6 +9977,7 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData, u32 battlerDef = damageCalcData->battlerDef; u32 move = damageCalcData->move; u32 moveType = damageCalcData->moveType; + u32 moveEffect = GetMoveEffect(move); if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM) // the defense stats are swapped { @@ -9901,7 +9990,7 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData, spDef = gBattleMons[battlerDef].spDefense; } - if (gMovesInfo[move].effect == EFFECT_PSYSHOCK || IS_MOVE_PHYSICAL(move)) // uses defense stat instead of sp.def + if (moveEffect == EFFECT_PSYSHOCK || IsBattleMovePhysical(move)) // uses defense stat instead of sp.def { defStat = def; defStage = gBattleMons[battlerDef].statStages[STAT_DEF]; @@ -9915,7 +10004,7 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData, } // Self-destruct / Explosion cut defense in half - if (B_EXPLOSION_DEFENSE < GEN_5 && gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION) + if (B_EXPLOSION_DEFENSE < GEN_5 && moveEffect == EFFECT_EXPLOSION) defStat /= 2; // critical hits ignore positive stat changes @@ -9925,7 +10014,7 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData, if (atkAbility == ABILITY_UNAWARE) defStage = DEFAULT_STAT_STAGE; // certain moves also ignore stat changes - if (gMovesInfo[move].ignoresTargetDefenseEvasionStages) + if (MoveIgnoresDefenseEvasionStages(move)) defStage = DEFAULT_STAT_STAGE; defStat *= gStatStageRatios[defStage][0]; @@ -10027,9 +10116,9 @@ static inline u32 CalcDefenseStat(struct DamageCalculationData *damageCalcData, // The defensive stats of a Player's Pokémon are boosted by x1.1 (+10%) if they have the 5th badge and 7th badges. // Having the 5th badge boosts physical defense while having the 7th badge boosts special defense. - if (ShouldGetStatBadgeBoost(FLAG_BADGE05_GET, battlerDef) && IS_MOVE_PHYSICAL(move)) + if (ShouldGetStatBadgeBoost(FLAG_BADGE05_GET, battlerDef) && IsBattleMovePhysical(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); - if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerDef) && IS_MOVE_SPECIAL(move)) + if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerDef) && IsBattleMoveSpecial(move)) modifier = uq4_12_multiply_half_down(modifier, UQ_4_12(1.1)); return uq4_12_multiply_by_int_half_down(modifier, defStat); @@ -10078,7 +10167,7 @@ static uq4_12_t GetWeatherDamageModifier(struct DamageCalculationData *damageCal if (weather == B_WEATHER_NONE) return UQ_4_12(1.0); - if (gMovesInfo[move].effect == EFFECT_HYDRO_STEAM && (weather & B_WEATHER_SUN) && holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA) + if (GetMoveEffect(move) == EFFECT_HYDRO_STEAM && (weather & B_WEATHER_SUN) && holdEffectAtk != HOLD_EFFECT_UTILITY_UMBRELLA) return UQ_4_12(1.5); if (holdEffectDef == HOLD_EFFECT_UTILITY_UMBRELLA) return UQ_4_12(1.0); @@ -10102,15 +10191,16 @@ static inline uq4_12_t GetBurnOrFrostBiteModifier(struct DamageCalculationData * { u32 battlerAtk = damageCalcData->battlerAtk; u32 move = damageCalcData->move; + u32 moveEffect = GetMoveEffect(move); if (gBattleMons[battlerAtk].status1 & STATUS1_BURN - && IS_MOVE_PHYSICAL(move) - && (B_BURN_FACADE_DMG < GEN_6 || gMovesInfo[move].effect != EFFECT_FACADE) + && IsBattleMovePhysical(move) + && (B_BURN_FACADE_DMG < GEN_6 || moveEffect != EFFECT_FACADE) && abilityAtk != ABILITY_GUTS) return UQ_4_12(0.5); if (gBattleMons[battlerAtk].status1 & STATUS1_FROSTBITE - && IS_MOVE_SPECIAL(move) - && (B_BURN_FACADE_DMG < GEN_6 || gMovesInfo[move].effect != EFFECT_FACADE)) + && IsBattleMoveSpecial(move) + && (B_BURN_FACADE_DMG < GEN_6 || moveEffect != EFFECT_FACADE)) return UQ_4_12(0.5); return UQ_4_12(1.0); } @@ -10138,28 +10228,28 @@ static inline uq4_12_t GetZMaxMoveAgainstProtectionModifier(struct DamageCalcula static inline uq4_12_t GetMinimizeModifier(u32 move, u32 battlerDef) { - if (gMovesInfo[move].minimizeDoubleDamage && gStatuses3[battlerDef] & STATUS3_MINIMIZED) + if (MoveIncreasesPowerToMinimizedTargets(move) && gStatuses3[battlerDef] & STATUS3_MINIMIZED) return UQ_4_12(2.0); return UQ_4_12(1.0); } static inline uq4_12_t GetUndergroundModifier(u32 move, u32 battlerDef) { - if (gMovesInfo[move].damagesUnderground && gStatuses3[battlerDef] & STATUS3_UNDERGROUND) + if (MoveDamagesUnderground(move) && gStatuses3[battlerDef] & STATUS3_UNDERGROUND) return UQ_4_12(2.0); return UQ_4_12(1.0); } static inline uq4_12_t GetDiveModifier(u32 move, u32 battlerDef) { - if (gMovesInfo[move].damagesUnderwater && gStatuses3[battlerDef] & STATUS3_UNDERWATER) + if (MoveDamagesUnderWater(move) && gStatuses3[battlerDef] & STATUS3_UNDERWATER) return UQ_4_12(2.0); return UQ_4_12(1.0); } static inline uq4_12_t GetAirborneModifier(u32 move, u32 battlerDef) { - if (gMovesInfo[move].damagesAirborneDoubleDamage && gStatuses3[battlerDef] & STATUS3_ON_AIR) + if (MoveDamagesAirborneDoubleDamage(move) && gStatuses3[battlerDef] & STATUS3_ON_AIR) return UQ_4_12(2.0); return UQ_4_12(1.0); } @@ -10167,8 +10257,8 @@ static inline uq4_12_t GetAirborneModifier(u32 move, u32 battlerDef) static inline uq4_12_t GetScreensModifier(u32 move, u32 battlerAtk, u32 battlerDef, bool32 isCrit, u32 abilityAtk) { u32 sideStatus = gSideStatuses[GetBattlerSide(battlerDef)]; - bool32 lightScreen = (sideStatus & SIDE_STATUS_LIGHTSCREEN) && IS_MOVE_SPECIAL(move); - bool32 reflect = (sideStatus & SIDE_STATUS_REFLECT) && IS_MOVE_PHYSICAL(move); + bool32 lightScreen = (sideStatus & SIDE_STATUS_LIGHTSCREEN) && IsBattleMoveSpecial(move); + bool32 reflect = (sideStatus & SIDE_STATUS_REFLECT) && IsBattleMovePhysical(move); bool32 auroraVeil = sideStatus & SIDE_STATUS_AURORA_VEIL; if (isCrit || abilityAtk == ABILITY_INFILTRATOR || gProtectStructs[battlerAtk].confusionSelfDmg) @@ -10180,7 +10270,7 @@ static inline uq4_12_t GetScreensModifier(u32 move, u32 battlerAtk, u32 battlerD static inline uq4_12_t GetCollisionCourseElectroDriftModifier(u32 move, uq4_12_t typeEffectivenessModifier) { - if (gMovesInfo[move].effect == EFFECT_COLLISION_COURSE && typeEffectivenessModifier >= UQ_4_12(2.0)) + if (GetMoveEffect(move) == EFFECT_COLLISION_COURSE && typeEffectivenessModifier >= UQ_4_12(2.0)) return UQ_4_12(1.3333); return UQ_4_12(1.0); } @@ -10227,11 +10317,11 @@ static inline uq4_12_t GetDefenderAbilitiesModifier(u32 move, u32 moveType, u32 return UQ_4_12(0.5); break; case ABILITY_PUNK_ROCK: - if (gMovesInfo[move].soundMove) + if (IsSoundMove(move)) return UQ_4_12(0.5); break; case ABILITY_ICE_SCALES: - if (IS_MOVE_SPECIAL(move)) + if (IsBattleMoveSpecial(move)) return UQ_4_12(0.5); break; } @@ -10430,9 +10520,9 @@ static inline s32 DoFutureSightAttackDamageCalcVars(struct DamageCalculationData struct Pokemon *partyMon = &party[gWishFutureKnock.futureSightPartyIndex[battlerDef]]; u32 partyMonLevel = GetMonData(partyMon, MON_DATA_LEVEL, NULL); u32 partyMonSpecies = GetMonData(partyMon, MON_DATA_SPECIES, NULL); - gBattleMovePower = gMovesInfo[move].power; + gBattleMovePower = GetMovePower(move); - if (IS_MOVE_PHYSICAL(move)) + if (IsBattleMovePhysical(move)) userFinalAttack = GetMonData(partyMon, MON_DATA_ATK, NULL); else userFinalAttack = GetMonData(partyMon, MON_DATA_SPATK, NULL); @@ -10488,7 +10578,7 @@ static u32 GetWeather(void) static inline bool32 IsFutureSightAttackerInParty(struct DamageCalculationData *damageCalcData) { - if (gMovesInfo[damageCalcData->move].effect != EFFECT_FUTURE_SIGHT) + if (GetMoveEffect(damageCalcData->move) != EFFECT_FUTURE_SIGHT) return FALSE; struct Pokemon *party = GetSideParty(GetBattlerSide(gBattlerAttacker)); @@ -10545,7 +10635,7 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move if (moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); - if (gMovesInfo[move].effect == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == gMovesInfo[move].argument.type) + if (GetMoveEffect(move) == EFFECT_SUPER_EFFECTIVE_ON_ARG && defType == GetMoveArgType(move)) mod = UQ_4_12(2.0); if (moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(battlerDef) && mod == UQ_4_12(0.0)) mod = UQ_4_12(1.0); @@ -10581,27 +10671,27 @@ static inline void TryNoticeIllusionInTypeEffectiveness(u32 move, u32 moveType, RecordAbilityBattle(battlerDef, ABILITY_ILLUSION); } -static void UpdateMoveResultFlags(uq4_12_t modifier, u32 battler) +void UpdateMoveResultFlags(uq4_12_t modifier, u16 *resultFlags) { if (modifier == UQ_4_12(0.0)) { - gBattleStruct->moveResultFlags[battler] |= MOVE_RESULT_DOESNT_AFFECT_FOE; - gBattleStruct->moveResultFlags[battler] &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE); + *resultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE; + *resultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE); gBattleStruct->blunderPolicy = FALSE; // Don't activate if missed } else if (modifier == UQ_4_12(1.0)) { - gBattleStruct->moveResultFlags[battler] &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); + *resultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); } else if (modifier > UQ_4_12(1.0)) { - gBattleStruct->moveResultFlags[battler] |= MOVE_RESULT_SUPER_EFFECTIVE; - gBattleStruct->moveResultFlags[battler] &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); + *resultFlags |= MOVE_RESULT_SUPER_EFFECTIVE; + *resultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); } else //if (modifier < UQ_4_12(1.0)) { - gBattleStruct->moveResultFlags[battler] |= MOVE_RESULT_NOT_VERY_EFFECTIVE; - gBattleStruct->moveResultFlags[battler] &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); + *resultFlags |= MOVE_RESULT_NOT_VERY_EFFECTIVE; + *resultFlags &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE); } } @@ -10622,13 +10712,13 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov if (recordAbilities && (illusionSpecies = GetIllusionMonSpecies(battlerDef))) TryNoticeIllusionInTypeEffectiveness(move, moveType, battlerAtk, battlerDef, modifier, illusionSpecies); - if (gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS && move != MOVE_THUNDER_WAVE) + if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS && move != MOVE_THUNDER_WAVE) { modifier = UQ_4_12(1.0); if (B_GLARE_GHOST < GEN_4 && move == MOVE_GLARE && IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST)) modifier = UQ_4_12(0.0); } - else if (moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(battlerDef, TRUE) && !(gMovesInfo[move].ignoreTypeIfFlyingAndUngrounded)) + else if (moveType == TYPE_GROUND && !IsBattlerGroundedInverseCheck(battlerDef, TRUE) && !(MoveIgnoresTypeIfFlyingAndUngrounded(move))) { modifier = UQ_4_12(0.0); if (recordAbilities && defAbility == ABILITY_LEVITATE) @@ -10647,7 +10737,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov // Thousand Arrows ignores type modifiers for flying mons if (!IsBattlerGrounded(battlerDef) - && (gMovesInfo[move].ignoreTypeIfFlyingAndUngrounded) + && MoveIgnoresTypeIfFlyingAndUngrounded(move) && IS_BATTLER_OF_TYPE(battlerDef, TYPE_FLYING)) { modifier = UQ_4_12(1.0); @@ -10655,7 +10745,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov if (((defAbility == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0)) || (defAbility == ABILITY_TELEPATHY && battlerDef == BATTLE_PARTNER(battlerAtk))) - && gMovesInfo[move].power) + && GetMovePower(move) != 0) { modifier = UQ_4_12(0.0); if (recordAbilities) @@ -10682,19 +10772,19 @@ uq4_12_t CalcTypeEffectivenessMultiplier(u32 move, u32 moveType, u32 battlerAtk, if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); - if (gMovesInfo[move].effect == EFFECT_TWO_TYPED_MOVE) - modifier = CalcTypeEffectivenessMultiplierInternal(move, gMovesInfo[move].argument.type, battlerAtk, battlerDef, recordAbilities, modifier, defAbility); + if (GetMoveEffect(move) == EFFECT_TWO_TYPED_MOVE) + modifier = CalcTypeEffectivenessMultiplierInternal(move, GetMoveArgType(move), battlerAtk, battlerDef, recordAbilities, modifier, defAbility); } if (recordAbilities) - UpdateMoveResultFlags(modifier, battlerDef); + UpdateMoveResultFlags(modifier, &gBattleStruct->moveResultFlags[battlerDef]); return modifier; } uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef) { uq4_12_t modifier = UQ_4_12(1.0); - u32 moveType = GetMoveType(move); + u32 moveType = GetBattleMoveType(move); if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY) { @@ -10704,11 +10794,10 @@ uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 a if (moveType == TYPE_GROUND && abilityDef == ABILITY_LEVITATE && !(gFieldStatuses & STATUS_FIELD_GRAVITY)) modifier = UQ_4_12(0.0); - if (abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && gMovesInfo[move].power) + if (abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && GetMovePower(move) != 0) modifier = UQ_4_12(0.0); } - UpdateMoveResultFlags(modifier, speciesDef); return modifier; } @@ -10727,7 +10816,7 @@ static uq4_12_t GetInverseTypeMultiplier(uq4_12_t multiplier) } } -uq4_12_t GetTypeEffectiveness(struct Pokemon *mon, u8 moveType) +uq4_12_t GetOverworldTypeEffectiveness(struct Pokemon *mon, u8 moveType) { uq4_12_t modifier = UQ_4_12(1.0); u16 abilityDef = GetMonAbility(mon); @@ -10766,14 +10855,14 @@ uq4_12_t GetTypeModifier(u32 atkType, u32 defType) return gTypeEffectivenessTable[atkType][defType]; } -s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp) +s32 GetStealthHazardDamageByTypesAndHP(enum TypeSideHazard hazardType, u8 type1, u8 type2, u32 maxHp) { s32 dmg = 0; uq4_12_t modifier = UQ_4_12(1.0); - modifier = uq4_12_multiply(modifier, GetTypeModifier(hazardType, type1)); + modifier = uq4_12_multiply(modifier, GetTypeModifier((u8)hazardType, type1)); if (type2 != type1) - modifier = uq4_12_multiply(modifier, GetTypeModifier(hazardType, type2)); + modifier = uq4_12_multiply(modifier, GetTypeModifier((u8)hazardType, type2)); switch (modifier) { @@ -10810,7 +10899,7 @@ s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 ma return dmg; } -s32 GetStealthHazardDamage(u8 hazardType, u32 battler) +s32 GetStealthHazardDamage(enum TypeSideHazard hazardType, u32 battler) { u8 type1 = gBattleMons[battler].types[0]; u8 type2 = gBattleMons[battler].types[1]; @@ -10883,11 +10972,11 @@ bool32 CanMegaEvolve(u32 battler) return FALSE; // Check if there is an entry in the form change table for regular Mega Evolution and battler is holding Mega Stone. - if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM) != SPECIES_NONE && holdEffect == HOLD_EFFECT_MEGA_STONE) + if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM) != gBattleMons[battler].species && holdEffect == HOLD_EFFECT_MEGA_STONE) return TRUE; // Check if there is an entry in the form change table for Wish Mega Evolution. - if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE) != SPECIES_NONE) + if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE) != gBattleMons[battler].species) return TRUE; // No checks passed, the mon CAN'T mega evolve. @@ -10917,7 +11006,7 @@ bool32 CanUltraBurst(u32 battler) return FALSE; // Check if there is an entry in the form change table for Ultra Burst and battler is holding a Z-Crystal. - if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_ULTRA_BURST) != SPECIES_NONE && holdEffect == HOLD_EFFECT_Z_CRYSTAL) + if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_ULTRA_BURST) != gBattleMons[battler].species && holdEffect == HOLD_EFFECT_Z_CRYSTAL) return TRUE; // No checks passed, the mon CAN'T ultra burst. @@ -10928,7 +11017,7 @@ void ActivateMegaEvolution(u32 battler) { gLastUsedItem = gBattleMons[battler].item; SetActiveGimmick(battler, GIMMICK_MEGA); - if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE) != SPECIES_NONE) + if (GetBattleFormChangeTargetSpecies(battler, FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE) != gBattleMons[battler].species) BattleScriptExecute(BattleScript_WishMegaEvolution); else BattleScriptExecute(BattleScript_MegaEvolution); @@ -10977,8 +11066,8 @@ bool32 IsBattlerInTeraForm(u32 battler) u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method) { u32 i; - u16 targetSpecies = SPECIES_NONE; - u16 species = gBattleMons[battler].species; + u32 species = gBattleMons[battler].species; + u32 targetSpecies = species; const struct FormChange *formChanges = GetSpeciesFormChanges(species); struct Pokemon *mon = &GetBattlerParty(battler)[gBattlerPartyIndexes[battler]]; u16 heldItem; @@ -11107,15 +11196,16 @@ bool32 TryBattleFormChange(u32 battler, u32 method) u32 monId = gBattlerPartyIndexes[battler]; u32 side = GetBattlerSide(battler); struct Pokemon *party = GetBattlerParty(battler); + u32 currentSpecies = GetMonData(&party[monId], MON_DATA_SPECIES); u32 targetSpecies; if (!CanBattlerFormChange(battler, method)) return FALSE; targetSpecies = GetBattleFormChangeTargetSpecies(battler, method); - if (targetSpecies == SPECIES_NONE) + if (targetSpecies == currentSpecies) targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != currentSpecies) { // Saves the original species on the first form change. if (gBattleStruct->changedSpecies[side][monId] == SPECIES_NONE) @@ -11124,7 +11214,7 @@ bool32 TryBattleFormChange(u32 battler, u32 method) TryToSetBattleFormChangeMoves(&party[monId], method); SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies); gBattleMons[battler].species = targetSpecies; - RecalcBattlerStats(battler, &party[monId]); + RecalcBattlerStats(battler, &party[monId], method == FORM_CHANGE_BATTLE_GIGANTAMAX); return TRUE; } else if (gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE) @@ -11149,7 +11239,7 @@ bool32 TryBattleFormChange(u32 battler, u32 method) // Reverts the original species TryToSetBattleFormChangeMoves(&party[monId], method); SetMonData(&party[monId], MON_DATA_SPECIES, &gBattleStruct->changedSpecies[side][monId]); - RecalcBattlerStats(battler, &party[monId]); + RecalcBattlerStats(battler, &party[monId], method == FORM_CHANGE_BATTLE_GIGANTAMAX); // Battler data is not updated with regular form's ability, not doing so could cause wrong ability activation. if (method == FORM_CHANGE_FAINT) gBattleMons[battler].ability = abilityForm; @@ -11292,7 +11382,7 @@ bool32 ShouldGetStatBadgeBoost(u16 badgeFlag, u32 battler) static u32 SwapMoveDamageCategory(u32 move) { - if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL) + if (GetMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL) return DAMAGE_CATEGORY_SPECIAL; return DAMAGE_CATEGORY_PHYSICAL; } @@ -11304,11 +11394,11 @@ u8 GetBattleMoveCategory(u32 moveId) if (gBattleStruct != NULL && (IsZMove(moveId) || IsMaxMove(moveId))) // TODO: Might be buggy depending on when this is called. return gBattleStruct->categoryOverride; if (B_PHYSICAL_SPECIAL_SPLIT >= GEN_4) - return gMovesInfo[moveId].category; + return GetMoveCategory(moveId); - if (IS_MOVE_STATUS(moveId)) + if (IsBattleMoveStatus(moveId)) return DAMAGE_CATEGORY_STATUS; - return gTypesInfo[GetMoveType(moveId)].damageCategory; + return gTypesInfo[GetBattleMoveType(moveId)].damageCategory; } static bool32 TryRemoveScreens(u32 battler) @@ -11371,7 +11461,7 @@ static u32 GetFlingPowerFromItemId(u32 itemId) { if (itemId >= ITEM_TM01 && itemId <= ITEM_HM08) { - u32 power = gMovesInfo[ItemIdToBattleMoveId(itemId)].power; + u32 power = GetMovePower(ItemIdToBattleMoveId(itemId)); if (power > 1) return power; return 10; // Status moves and moves with variable power always return 10 power. @@ -11688,17 +11778,18 @@ u32 GetBattlerMoveTargetType(u32 battler, u32 move) { if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) return MOVE_TARGET_USER; - if (gMovesInfo[move].effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(battler, STATUS_FIELD_PSYCHIC_TERRAIN)) + u32 effect = GetMoveEffect(move); + if (effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(battler, STATUS_FIELD_PSYCHIC_TERRAIN)) return MOVE_TARGET_BOTH; - if (gMovesInfo[move].effect == EFFECT_TERA_STARSTORM && gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR) + if (effect == EFFECT_TERA_STARSTORM && gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR) return MOVE_TARGET_BOTH; - return gMovesInfo[move].target; + return GetMoveTarget(move); } bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move) { - if (gMovesInfo[move].effect == EFFECT_HIT_ENEMY_HEAL_ALLY + if (GetMoveEffect(move) == EFFECT_HIT_ENEMY_HEAL_ALLY && GetBattlerSide(battlerAtk) == GetBattlerSide(battlerDef) && gStatuses3[battlerAtk] & STATUS3_HEAL_BLOCK) return FALSE; // Pokémon affected by Heal Block cannot target allies with Pollen Puff @@ -11738,11 +11829,28 @@ void CopyMonAbilityAndTypesToBattleMon(u32 battler, struct Pokemon *mon) gBattleMons[battler].types[2] = TYPE_MYSTERY; } -void RecalcBattlerStats(u32 battler, struct Pokemon *mon) +void RecalcBattlerStats(u32 battler, struct Pokemon *mon, bool32 isDynamaxing) { + u32 hp = GetMonData(mon, MON_DATA_HP); + u32 oldMaxHp = GetMonData(mon, MON_DATA_MAX_HP); CalculateMonStats(mon); if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && gChosenActionByBattler[battler] != B_ACTION_SWITCH) - ApplyDynamaxHPMultiplier(battler, mon); + { + ApplyDynamaxHPMultiplier(mon); + u32 newMaxHp = GetMonData(mon, MON_DATA_MAX_HP); + if (!isDynamaxing) + { + if (newMaxHp > oldMaxHp) // restore hp gained from changing form, without this, dynamaxed form changes are calculated incorrectly + { + hp += (newMaxHp - oldMaxHp); + SetMonData(mon, MON_DATA_HP, &hp); + } + else + { + SetMonData(mon, MON_DATA_HP, &hp); + } + } + } CopyMonLevelAndBaseStatsToBattleMon(battler, mon); CopyMonAbilityAndTypesToBattleMon(battler, mon); } @@ -11825,10 +11933,11 @@ bool32 IsGen6ExpShareEnabled(void) bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect) { u32 i; - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); + for (i = 0; i < numAdditionalEffects; i++) { - if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect - && gMovesInfo[move].additionalEffects[i].self == FALSE) + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); + if (additionalEffect->moveEffect == moveEffect && additionalEffect->self == FALSE) return TRUE; } return FALSE; @@ -11837,10 +11946,11 @@ bool32 MoveHasAdditionalEffect(u32 move, u32 moveEffect) bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance) { u32 i; - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); + for (i = 0; i < numAdditionalEffects; i++) { - if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect - && gMovesInfo[move].additionalEffects[i].chance == chance) + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); + if (additionalEffect->moveEffect == moveEffect && additionalEffect->chance == chance) return TRUE; } return FALSE; @@ -11849,10 +11959,11 @@ bool32 MoveHasAdditionalEffectWithChance(u32 move, u32 moveEffect, u32 chance) bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect) { u32 i; - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); + for (i = 0; i < numAdditionalEffects; i++) { - if (gMovesInfo[move].additionalEffects[i].moveEffect == moveEffect - && gMovesInfo[move].additionalEffects[i].self == TRUE) + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); + if (additionalEffect->moveEffect == moveEffect && additionalEffect->self == TRUE) return TRUE; } return FALSE; @@ -11860,15 +11971,16 @@ bool32 MoveHasAdditionalEffectSelf(u32 move, u32 moveEffect) bool32 IsMoveEffectRemoveSpeciesType(u32 move, u32 moveEffect, u32 argument) { - return (gMovesInfo[move].argument.type == argument) && MoveHasAdditionalEffectSelf(move, moveEffect); + return (GetMoveArgType(move) == argument) && MoveHasAdditionalEffectSelf(move, moveEffect); } bool32 MoveHasChargeTurnAdditionalEffect(u32 move) { u32 i; - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); + for (i = 0; i < numAdditionalEffects; i++) { - if (gMovesInfo[move].additionalEffects[i].onChargeTurnOnly) + if (GetMoveAdditionalEffectById(move, i)->onChargeTurnOnly) return TRUE; } return FALSE; @@ -11877,14 +11989,16 @@ bool32 MoveHasChargeTurnAdditionalEffect(u32 move) bool32 MoveIsAffectedBySheerForce(u32 move) { u32 i; - for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + u32 numAdditionalEffects = GetMoveAdditionalEffectCount(move); + for (i = 0; i < numAdditionalEffects; i++) { - if (gMovesInfo[move].additionalEffects[i].sheerForceBoost == SHEER_FORCE_NO_BOOST) + const struct AdditionalEffect *additionalEffect = GetMoveAdditionalEffectById(move, i); + if (additionalEffect->sheerForceBoost == SHEER_FORCE_NO_BOOST) continue; - if (gMovesInfo[move].additionalEffects[i].chance > 0) + if (additionalEffect->chance > 0) return TRUE; - if (gMovesInfo[move].additionalEffects[i].sheerForceBoost == SHEER_FORCE_BOOST) + if (additionalEffect->sheerForceBoost == SHEER_FORCE_BOOST) return TRUE; } return FALSE; @@ -11960,7 +12074,7 @@ void GetBattlerTypes(u32 battler, bool32 ignoreTera, u32 types[static 3]) types[2] = gBattleMons[battler].types[2]; // Roost. - if (!isTera && (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST)) + if (!isTera && gDisableStructs[battler].roostActive) { if (types[0] == TYPE_FLYING && types[1] == TYPE_FLYING) types[0] = types[1] = B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY; @@ -12000,6 +12114,7 @@ void SetShellSideArmCategory(void) u8 statStage; u32 physical; u32 special; + u32 power = GetMovePower(MOVE_SHELL_SIDE_ARM); for (battlerAtk = 0; battlerAtk < gBattlersCount; battlerAtk++) { @@ -12023,14 +12138,14 @@ void SetShellSideArmCategory(void) targetDefStat *= gStatStageRatios[statStage][0]; targetDefStat /= gStatStageRatios[statStage][1]; - physical = ((((2 * gBattleMons[battlerAtk].level / 5 + 2) * gMovesInfo[MOVE_SHELL_SIDE_ARM].power * attackerAtkStat) / targetDefStat) / 50); + physical = ((((2 * gBattleMons[battlerAtk].level / 5 + 2) * power * attackerAtkStat) / targetDefStat) / 50); targetSpDefStat = gBattleMons[battlerDef].spDefense; statStage = gBattleMons[battlerDef].statStages[STAT_SPDEF]; targetSpDefStat *= gStatStageRatios[statStage][0]; targetSpDefStat /= gStatStageRatios[statStage][1]; - special = ((((2 * gBattleMons[battlerAtk].level / 5 + 2) * gMovesInfo[MOVE_SHELL_SIDE_ARM].power * attackerSpAtkStat) / targetSpDefStat) / 50); + special = ((((2 * gBattleMons[battlerAtk].level / 5 + 2) * power * attackerSpAtkStat) / targetSpDefStat) / 50); if ((physical > special) || (physical == special && RandomPercentage(RNG_SHELL_SIDE_ARM, 50))) gBattleStruct->shellSideArmCategory[battlerAtk][battlerDef] = DAMAGE_CATEGORY_PHYSICAL; @@ -12055,13 +12170,13 @@ static inline bool32 DoesBattlerHaveAbilityImmunity(u32 battlerDef) bool32 TargetFullyImmuneToCurrMove(u32 battlerAtk, u32 battlerDef) { - return ((CalcTypeEffectivenessMultiplier(gCurrentMove, GetMoveType(gCurrentMove), battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) + return ((CalcTypeEffectivenessMultiplier(gCurrentMove, GetBattleMoveType(gCurrentMove), battlerAtk, battlerDef, GetBattlerAbility(battlerDef), FALSE) == UQ_4_12(0.0)) || IsBattlerProtected(battlerAtk, battlerDef, gCurrentMove) || IsSemiInvulnerable(battlerDef, gCurrentMove) || DoesBattlerHaveAbilityImmunity(battlerDef)); } -u32 GetMoveType(u32 move) +u32 GetBattleMoveType(u32 move) { if (gMain.inBattle && gBattleStruct->dynamicMoveType) return gBattleStruct->dynamicMoveType & DYNAMIC_TYPE_MASK; @@ -12070,14 +12185,14 @@ u32 GetMoveType(u32 move) || move == MOVE_FUTURE_SIGHT || move == MOVE_DOOM_DESIRE)) return TYPE_MYSTERY; - return gMovesInfo[move].type; + return GetMoveType(move); } void TryActivateSleepClause(u32 battler, u32 indexInParty) { - if (gBattleStruct->sleepClauseEffectExempt & (1u << battler)) + if (gBattleStruct->battlerState[battler].sleepClauseEffectExempt) { - gBattleStruct->sleepClauseEffectExempt &= ~(1u << battler); + gBattleStruct->battlerState[battler].sleepClauseEffectExempt = FALSE; return; } @@ -12132,8 +12247,66 @@ void ClearDamageCalcResults(void) bool32 DoesDestinyBondFail(u32 battler) { if (B_DESTINY_BOND_FAIL >= GEN_7 - && gMovesInfo[gLastResultingMoves[battler]].effect == EFFECT_DESTINY_BOND - && !(gBattleStruct->lastMoveFailed & (1u << battler))) + && GetMoveEffect(gLastResultingMoves[battler]) == EFFECT_DESTINY_BOND + && !gBattleStruct->battlerState[battler].lastMoveFailed) + return TRUE; + return FALSE; +} + +// This check has always to be the last in a condtion statement because of the recording of AI data. +bool32 IsMoveEffectBlockedByTarget(u32 ability) +{ + if (ability == ABILITY_SHIELD_DUST) + { + RecordAbilityBattle(gBattlerTarget, ability); + return TRUE; + } + else if (GetBattlerHoldEffect(gBattlerTarget, TRUE) == HOLD_EFFECT_COVERT_CLOAK) + { + RecordItemEffectBattle(gBattlerTarget, HOLD_EFFECT_COVERT_CLOAK); return TRUE; + } + return FALSE; } + +u32 NumAffectedSpreadMoveTargets(void) +{ + u32 targetCount = 1; + + if (!IsDoubleSpreadMove()) + return targetCount; + + targetCount = 0; + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (MoveResultHasEffect(battler)) + targetCount++; + } + + return targetCount; +} + +bool32 IsPursuitTargetSet(void) +{ + for (u32 battler = 0; battler < gBattlersCount; battler++) + { + if (gBattleStruct->battlerState[battler].pursuitTarget) + return TRUE; + } + return FALSE; +} + +void ClearPursuitValues(void) +{ + for (u32 i = 0; i < gBattlersCount; i++) + gBattleStruct->battlerState[i].pursuitTarget = FALSE; + gBattleStruct->pursuitSwitchByMove = FALSE; + gBattleStruct->pursuitStoredSwitch = 0; +} + +void ClearPursuitValuesIfSet(u32 battler) +{ + if (gBattleStruct->battlerState[battler].pursuitTarget) + ClearPursuitValues(); +} diff --git a/src/battle_util2.c b/src/battle_util2.c index 326acf0e40a8..6c2d0ff0a9cc 100644 --- a/src/battle_util2.c +++ b/src/battle_util2.c @@ -25,7 +25,6 @@ void AllocateBattleResources(void) gBattleResources = AllocZeroed(sizeof(*gBattleResources)); gBattleResources->secretBase = AllocZeroed(sizeof(*gBattleResources->secretBase)); - gBattleResources->flags = AllocZeroed(sizeof(*gBattleResources->flags)); gBattleResources->battleScriptsStack = AllocZeroed(sizeof(*gBattleResources->battleScriptsStack)); gBattleResources->battleCallbackStack = AllocZeroed(sizeof(*gBattleResources->battleCallbackStack)); gBattleResources->beforeLvlUp = AllocZeroed(sizeof(*gBattleResources->beforeLvlUp)); @@ -58,7 +57,6 @@ void FreeBattleResources(void) FREE_AND_SET_NULL(gBattleStruct); FREE_AND_SET_NULL(gBattleResources->secretBase); - FREE_AND_SET_NULL(gBattleResources->flags); FREE_AND_SET_NULL(gBattleResources->battleScriptsStack); FREE_AND_SET_NULL(gBattleResources->battleCallbackStack); FREE_AND_SET_NULL(gBattleResources->beforeLvlUp); diff --git a/src/battle_z_move.c b/src/battle_z_move.c index 53a39b6a792e..c878a2c12b8d 100644 --- a/src/battle_z_move.c +++ b/src/battle_z_move.c @@ -151,7 +151,7 @@ u32 GetUsableZMove(u32 battler, u32 move) if (zMove != MOVE_NONE) return zMove; // Signature z move exists - if (move != MOVE_NONE && zMove != MOVE_Z_STATUS && gMovesInfo[move].type == ItemId_GetSecondaryId(item)) + if (move != MOVE_NONE && zMove != MOVE_Z_STATUS && GetMoveType(move) == ItemId_GetSecondaryId(item)) return GetTypeBasedZMove(move); } @@ -195,7 +195,7 @@ bool32 IsViableZMove(u32 battler, u32 move) if (zMove != MOVE_NONE) return TRUE; - if (move != MOVE_NONE && gMovesInfo[move].type == ItemId_GetSecondaryId(item)) + if (move != MOVE_NONE && GetMoveType(move) == ItemId_GetSecondaryId(item)) return TRUE; } @@ -243,13 +243,13 @@ u32 GetSignatureZMove(u32 move, u32 species, u32 item) u32 GetTypeBasedZMove(u32 move) { - u32 moveType = gMovesInfo[move].type; + u32 moveType = GetMoveType(move); if (moveType >= NUMBER_OF_MON_TYPES) moveType = TYPE_MYSTERY; // Z-Weather Ball changes types, however Revelation Dance, -ate ability affected moves, and Hidden Power do not - if (gBattleStruct->dynamicMoveType && gMovesInfo[move].effect == EFFECT_WEATHER_BALL) + if (gBattleStruct->dynamicMoveType && GetMoveEffect(move) == EFFECT_WEATHER_BALL) moveType = gBattleStruct->dynamicMoveType & DYNAMIC_TYPE_MASK; // Get Z-Move from type @@ -276,9 +276,9 @@ bool32 MoveSelectionDisplayZMove(u16 zmove, u32 battler) BattlePutTextOnWindow(gDisplayedStringBattle, i + 3); } - if (IS_MOVE_STATUS(move)) + if (IsBattleMoveStatus(move)) { - u8 zEffect = gMovesInfo[move].zMove.effect; + u8 zEffect = GetMoveZEffect(move); gDisplayedStringBattle[0] = EOS; @@ -388,9 +388,9 @@ static void ZMoveSelectionDisplayPower(u16 move, u16 zMove) u16 power = GetZMovePower(move); if (zMove >= MOVE_CATASTROPIKA) - power = gMovesInfo[zMove].power; + power = GetMovePower(zMove); - if (gMovesInfo[move].category != DAMAGE_CATEGORY_STATUS) + if (GetMoveCategory(move) != DAMAGE_CATEGORY_STATUS) { txtPtr = StringCopy(gDisplayedStringBattle, sText_PowerColon); ConvertIntToDecimalStringN(txtPtr, power, STR_CONV_MODE_LEFT_ALIGN, 3); @@ -415,7 +415,7 @@ static void ZMoveSelectionDisplayPpNumber(u32 battler) static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler) { u8 *txtPtr, *end; - u32 zMoveType = GetMoveType(zMove); + u32 zMoveType = GetBattleMoveType(zMove); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); *(txtPtr)++ = EXT_CTRL_CODE_BEGIN; @@ -433,7 +433,7 @@ static void ZMoveSelectionDisplayMoveType(u16 zMove, u32 battler) void SetZEffect(void) { u32 i; - u32 effect = gMovesInfo[gBattleStruct->zmove.baseMoves[gBattlerAttacker]].zMove.effect; + u32 effect = GetMoveZEffect(gBattleStruct->zmove.baseMoves[gBattlerAttacker]); if (effect == Z_EFFECT_CURSE) { @@ -542,35 +542,25 @@ void SetZEffect(void) u32 GetZMovePower(u32 move) { - if (gMovesInfo[move].category == DAMAGE_CATEGORY_STATUS) + if (GetMoveCategory(move) == DAMAGE_CATEGORY_STATUS) return 0; - if (gMovesInfo[move].effect == EFFECT_OHKO) + if (GetMoveEffect(move) == EFFECT_OHKO) return 180; - if (gMovesInfo[move].zMove.powerOverride > 0) - return gMovesInfo[move].zMove.powerOverride; - else - { - if (gMovesInfo[move].power >= 140) - return 200; - else if (gMovesInfo[move].power >= 130) - return 195; - else if (gMovesInfo[move].power >= 120) - return 190; - else if (gMovesInfo[move].power >= 110) - return 185; - else if (gMovesInfo[move].power >= 100) - return 180; - else if (gMovesInfo[move].power >= 90) - return 175; - else if (gMovesInfo[move].power >= 80) - return 160; - else if (gMovesInfo[move].power >= 70) - return 140; - else if (gMovesInfo[move].power >= 60) - return 120; - else - return 100; - } + u32 power = GetMoveZPowerOverride(move); + if (power > 0) + return power; + + power = GetMovePower(move); + if (power >= 140) return 200; + else if (power >= 130) return 195; + else if (power >= 120) return 190; + else if (power >= 110) return 185; + else if (power >= 100) return 180; + else if (power >= 90) return 175; + else if (power >= 80) return 160; + else if (power >= 70) return 140; + else if (power >= 60) return 120; + else return 100; } diff --git a/src/berry.c b/src/berry.c index a287073df166..4730799e0c25 100644 --- a/src/berry.c +++ b/src/berry.c @@ -1654,6 +1654,24 @@ const struct BerryCrushBerryData gBerryCrush_BerryData[] = { [ITEM_WATMEL_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250}, [ITEM_DURIN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250}, [ITEM_BELUE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 250}, + [ITEM_CHILAN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 80, .powder = 70}, + [ITEM_OCCA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 100, .powder = 100}, + [ITEM_PASSHO_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 60, .powder = 30}, + [ITEM_WACAN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_RINDO_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_YACHE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_CHOPLE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_KEBIA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_SHUCA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 20}, + [ITEM_COBA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_PAYAPA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_TANGA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_CHARTI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_KASIB_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_HABAN_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 50, .powder = 30}, + [ITEM_COLBUR_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 60, .powder = 50}, + [ITEM_BABIRI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 80, .powder = 50}, + [ITEM_ROSELI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 60, .powder = 50}, [ITEM_LIECHI_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_GANLON_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_SALAC_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, @@ -1661,6 +1679,13 @@ const struct BerryCrushBerryData gBerryCrush_BerryData[] = { [ITEM_APICOT_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 180, .powder = 500}, [ITEM_LANSAT_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750}, [ITEM_STARF_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750}, + [ITEM_ENIGMA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 150, .powder = 200}, + [ITEM_MICLE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 130, .powder = 250}, + [ITEM_CUSTAP_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 200, .powder = 750}, + [ITEM_JABOCA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 130, .powder = 250}, + [ITEM_ROWAP_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 130, .powder = 250}, + [ITEM_KEE_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 500}, + [ITEM_MARANGA_BERRY - FIRST_BERRY_INDEX] = {.difficulty = 160, .powder = 500}, [ITEM_ENIGMA_BERRY_E_READER - FIRST_BERRY_INDEX] = {.difficulty = 150, .powder = 200} }; diff --git a/src/bike.c b/src/bike.c index 5bbf647ce9dc..afc3099ab7e8 100644 --- a/src/bike.c +++ b/src/bike.c @@ -996,8 +996,6 @@ bool8 IsPlayerNotUsingAcroBikeOnBumpySlope(void) void GetOnOffBike(u8 transitionFlags) { - gUnusedBikeCameraAheadPanback = FALSE; - if (gPlayerAvatar.flags & (PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE)) { SetPlayerAvatarTransitionFlags(PLAYER_AVATAR_FLAG_ON_FOOT); diff --git a/src/clock.c b/src/clock.c index 54c9422bbe47..d122fc782c2b 100644 --- a/src/clock.c +++ b/src/clock.c @@ -83,9 +83,10 @@ static void FormChangeTimeUpdate() for (i = 0; i < PARTY_SIZE; i++) { struct Pokemon *mon = &gPlayerParty[i]; - u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_TIME_OF_DAY, 0); + u32 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_TIME_OF_DAY, 0); + u32 currentSpecies = GetMonData(mon, MON_DATA_SPECIES); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != currentSpecies) { SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); CalculateMonStats(mon); diff --git a/src/contest.c b/src/contest.c index f740b46b6227..a1cd62777f93 100644 --- a/src/contest.c +++ b/src/contest.c @@ -1639,7 +1639,7 @@ static void Task_ShowMoveSelectScreen(u8 taskId) } else if (move != MOVE_NONE && eContestantStatus[gContestPlayerMonIndex].prevMove == move - && gMovesInfo[move].contestEffect != CONTEST_EFFECT_REPETITION_NOT_BORING) + && GetMoveContestEffect(move) != CONTEST_EFFECT_REPETITION_NOT_BORING) { // Gray the text because it's a repeated move moveNameBuffer = StringCopy(moveName, gText_ColorBlue); @@ -2310,7 +2310,7 @@ static void Task_DoAppeals(u8 taskId) } else { - StringCopy(gStringVar3, sContestConditions[gMovesInfo[eContestantStatus[contestant].currMove].contestCategory]); + StringCopy(gStringVar3, sContestConditions[GetMoveContestCategory(eContestantStatus[contestant].currMove)]); } if (r3 > 0 && eContestantStatus[contestant].repeatedMove) @@ -3267,7 +3267,7 @@ static u16 GetMoveEffectSymbolTileOffset(u16 move, u8 contestant) { u16 offset; - switch (gContestEffects[gMovesInfo[move].contestEffect].effectType) + switch (gContestEffects[GetMoveContestEffect(move)].effectType) { case 0: case 1: @@ -3293,7 +3293,7 @@ static void PrintContestMoveDescription(u16 move) u8 numHearts; // The contest category icon is implemented as a 5x2 group of tiles. - category = gMovesInfo[move].contestCategory; + category = GetMoveContestCategory(move); if (category == CONTEST_CATEGORY_COOL) categoryTile = 0x4040; else if (category == CONTEST_CATEGORY_BEAUTY) @@ -3309,27 +3309,27 @@ static void PrintContestMoveDescription(u16 move) ContestBG_FillBoxWithIncrementingTile(0, categoryTile + 0x10, 0x0b, 0x20, 0x05, 0x01, 0x11, 0x01); // Appeal hearts - if (gContestEffects[gMovesInfo[move].contestEffect].appeal == 0xFF) + if (gContestEffects[GetMoveContestEffect(move)].appeal == 0xFF) numHearts = 0; else - numHearts = gContestEffects[gMovesInfo[move].contestEffect].appeal / 10; + numHearts = gContestEffects[GetMoveContestEffect(move)].appeal / 10; if (numHearts > MAX_CONTEST_MOVE_HEARTS) numHearts = MAX_CONTEST_MOVE_HEARTS; ContestBG_FillBoxWithTile(0, TILE_EMPTY_APPEAL_HEART, 0x15, 0x1f, MAX_CONTEST_MOVE_HEARTS, 0x01, 0x11); ContestBG_FillBoxWithTile(0, TILE_FILLED_APPEAL_HEART, 0x15, 0x1f, numHearts, 0x01, 0x11); // Jam hearts - if (gContestEffects[gMovesInfo[move].contestEffect].jam == 0xFF) + if (gContestEffects[GetMoveContestEffect(move)].jam == 0xFF) numHearts = 0; else - numHearts = gContestEffects[gMovesInfo[move].contestEffect].jam / 10; + numHearts = gContestEffects[GetMoveContestEffect(move)].jam / 10; if (numHearts > MAX_CONTEST_MOVE_HEARTS) numHearts = MAX_CONTEST_MOVE_HEARTS; ContestBG_FillBoxWithTile(0, TILE_EMPTY_JAM_HEART, 0x15, 0x20, MAX_CONTEST_MOVE_HEARTS, 0x01, 0x11); ContestBG_FillBoxWithTile(0, TILE_FILLED_JAM_HEART, 0x15, 0x20, numHearts, 0x01, 0x11); FillWindowPixelBuffer(WIN_MOVE_DESCRIPTION, PIXEL_FILL(0)); - Contest_PrintTextToBg0WindowStd(WIN_MOVE_DESCRIPTION, gContestEffectDescriptionPointers[gMovesInfo[move].contestEffect]); + Contest_PrintTextToBg0WindowStd(WIN_MOVE_DESCRIPTION, gContestEffectDescriptionPointers[GetMoveContestEffect(move)]); Contest_PrintTextToBg0WindowStd(WIN_SLASH, gText_Slash); } @@ -4530,9 +4530,9 @@ static void CalculateAppealMoveImpact(u8 contestant) return; move = eContestantStatus[contestant].currMove; - effect = gMovesInfo[move].contestEffect; + effect = GetMoveContestEffect(move); - eContestantStatus[contestant].moveCategory = gMovesInfo[eContestantStatus[contestant].currMove].contestCategory; + eContestantStatus[contestant].moveCategory = GetMoveContestCategory(eContestantStatus[contestant].currMove); if (eContestantStatus[contestant].currMove == eContestantStatus[contestant].prevMove && eContestantStatus[contestant].currMove != MOVE_NONE) { eContestantStatus[contestant].repeatedMove = TRUE; @@ -4583,7 +4583,7 @@ static void CalculateAppealMoveImpact(u8 contestant) } else { - if (gMovesInfo[eContestantStatus[contestant].currMove].contestComboStarterId != 0) + if (GetMoveContestComboStarter(eContestantStatus[contestant].currMove) != 0) { eContestantStatus[contestant].hasJudgesAttention = TRUE; eContestantStatus[contestant].usedComboMove = TRUE; @@ -4663,13 +4663,13 @@ static void PrintAppealMoveResultText(u8 contestant, u8 stringId) { StringCopy(gStringVar1, gContestMons[contestant].nickname); StringCopy(gStringVar2, GetMoveName(eContestantStatus[contestant].currMove)); - if (gMovesInfo[eContestantStatus[eContestAppealResults.contestant].currMove].contestCategory == CONTEST_CATEGORY_COOL) + if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_COOL) StringCopy(gStringVar3, gText_Contest_Shyness); - else if (gMovesInfo[eContestantStatus[eContestAppealResults.contestant].currMove].contestCategory == CONTEST_CATEGORY_BEAUTY) + else if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_BEAUTY) StringCopy(gStringVar3, gText_Contest_Anxiety); - else if (gMovesInfo[eContestantStatus[eContestAppealResults.contestant].currMove].contestCategory == CONTEST_CATEGORY_CUTE) + else if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_CUTE) StringCopy(gStringVar3, gText_Contest_Laziness); - else if (gMovesInfo[eContestantStatus[eContestAppealResults.contestant].currMove].contestCategory == CONTEST_CATEGORY_SMART) + else if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) == CONTEST_CATEGORY_SMART) StringCopy(gStringVar3, gText_Contest_Hesitancy); else StringCopy(gStringVar3, gText_Contest_Fear); @@ -4842,7 +4842,7 @@ static void UpdateApplauseMeter(void) s8 Contest_GetMoveExcitement(u16 move) { - return sContestExcitementTable[gSpecialVar_ContestCategory][gMovesInfo[move].contestCategory]; + return sContestExcitementTable[gSpecialVar_ContestCategory][GetMoveContestCategory(move)]; } static u8 StartApplauseOverflowAnimation(void) diff --git a/src/contest_ai.c b/src/contest_ai.c index f131c709ac31..4386aeee64b5 100644 --- a/src/contest_ai.c +++ b/src/contest_ai.c @@ -758,7 +758,7 @@ static void ContestAICmd_get_move_effect(void) { u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]; - eContestAI.scriptResult = gMovesInfo[move].contestEffect; + eContestAI.scriptResult = GetMoveContestEffect(move); gAIScriptPtr += 1; } @@ -786,7 +786,7 @@ static void ContestAICmd_get_move_effect_type(void) { u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]; - eContestAI.scriptResult = gContestEffects[gMovesInfo[move].contestEffect].effectType; + eContestAI.scriptResult = gContestEffects[GetMoveContestEffect(move)].effectType; gAIScriptPtr += 1; } @@ -814,12 +814,12 @@ static void ContestAICmd_check_most_appealing_move(void) { int i; u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]; - u8 appeal = gContestEffects[gMovesInfo[move].contestEffect].appeal; + u8 appeal = gContestEffects[GetMoveContestEffect(move)].appeal; for (i = 0; i < MAX_MON_MOVES; i++) { u16 newMove = gContestMons[eContestAI.contestantId].moves[i]; - if (newMove != 0 && appeal < gContestEffects[gMovesInfo[newMove].contestEffect].appeal) + if (newMove != 0 && appeal < gContestEffects[GetMoveContestEffect(newMove)].appeal) break; } @@ -845,12 +845,12 @@ static void ContestAICmd_check_most_jamming_move(void) { int i; u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]; - u8 jam = gContestEffects[gMovesInfo[move].contestEffect].jam; + u8 jam = gContestEffects[GetMoveContestEffect(move)].jam; for (i = 0; i < MAX_MON_MOVES; i++) { u16 newMove = gContestMons[eContestAI.contestantId].moves[i]; - if (newMove != MOVE_NONE && jam < gContestEffects[gMovesInfo[newMove].contestEffect].jam) + if (newMove != MOVE_NONE && jam < gContestEffects[GetMoveContestEffect(newMove)].jam) break; } @@ -876,7 +876,7 @@ static void ContestAICmd_get_num_move_hearts(void) { u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]; - eContestAI.scriptResult = gContestEffects[gMovesInfo[move].contestEffect].appeal / 10; + eContestAI.scriptResult = gContestEffects[GetMoveContestEffect(move)].appeal / 10; gAIScriptPtr += 1; } @@ -924,7 +924,7 @@ static void ContestAICmd_get_num_move_jam_hearts(void) { u16 move = gContestMons[eContestAI.contestantId].moves[eContestAI.nextMoveIndex]; - eContestAI.scriptResult = gContestEffects[gMovesInfo[move].contestEffect].jam / 10; + eContestAI.scriptResult = gContestEffects[GetMoveContestEffect(move)].jam / 10; gAIScriptPtr += 1; } @@ -1203,7 +1203,7 @@ static void ContestAICmd_get_used_combo_starter(void) u8 contestant = GetContestantIdByTurn(gAIScriptPtr[1]); if (IsContestantAllowedToCombo(contestant)) - result = gMovesInfo[eContestantStatus[contestant].prevMove].contestComboStarterId ? TRUE : FALSE; + result = GetMoveContestComboStarter(eContestantStatus[contestant].prevMove) ? TRUE : FALSE; eContestAI.scriptResult = result; gAIScriptPtr += 2; @@ -1409,7 +1409,7 @@ static void ContestAICmd_get_used_moves_effect(void) u8 round = gAIScriptPtr[2]; u16 move = eContest.moveHistory[round][contestant]; - eContestAI.scriptResult = gMovesInfo[move].contestEffect; + eContestAI.scriptResult = GetMoveContestEffect(move); gAIScriptPtr += 3; } @@ -1509,7 +1509,7 @@ static void ContestAICmd_get_used_moves_effect_type(void) u8 round = gAIScriptPtr[2]; u16 move = eContest.moveHistory[round][contestant]; - eContestAI.scriptResult = gContestEffects[gMovesInfo[move].contestEffect].effectType; + eContestAI.scriptResult = gContestEffects[GetMoveContestEffect(move)].effectType; gAIScriptPtr += 3; } @@ -1748,7 +1748,7 @@ static void ContestAICmd_check_user_has_move(void) for (i = 0; i < MAX_MON_MOVES; i++) { #ifdef BUGFIX - u16 move = gMovesInfo[gContestMons[eContestAI.contestantId].moves[i]].contestEffect; + u16 move = GetMoveContestEffect(gContestMons[eContestAI.contestantId].moves[i]); #else u16 move = gContestMons[eContestAI.contestantId].moves[i]; #endif diff --git a/src/contest_effect.c b/src/contest_effect.c index 0de31339f4b8..51416ba14a76 100644 --- a/src/contest_effect.c +++ b/src/contest_effect.c @@ -1,4 +1,5 @@ #include "global.h" +#include "move.h" #include "random.h" #include "constants/moves.h" #include "contest.h" @@ -60,7 +61,7 @@ static s16 RoundUp(s16); bool8 AreMovesContestCombo(u16 lastMove, u16 nextMove) { int i; - u8 lastMoveComboStarterId = gMovesInfo[lastMove].contestComboStarterId; + u8 lastMoveComboStarterId = GetMoveContestComboStarter(lastMove); if (lastMoveComboStarterId == 0) { @@ -70,7 +71,7 @@ bool8 AreMovesContestCombo(u16 lastMove, u16 nextMove) { for (i = 0; i < MAX_COMBO_MOVES; i++) { - if (lastMoveComboStarterId == gMovesInfo[nextMove].contestComboMoves[i]) + if (lastMoveComboStarterId == GetMoveContestComboMoves(nextMove, i)) return TRUE; } return FALSE; @@ -132,7 +133,7 @@ static void ContestEffect_UserLessEasilyStartled(void) SetContestantEffectStringID(eContestAppealResults.contestant,CONTEST_STRING_STOPPED_CARING); } -// Slightly startles the POKMON in front. +// Slightly startles the POK�MON in front. static void ContestEffect_StartleFrontMon(void) { u8 idx = 0; @@ -180,7 +181,7 @@ static void ContestEffect_StartlePrevMons(void) SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Startles the POKMON that appealed before the user. +// Startles the POK�MON that appealed before the user. static void ContestEffect_StartlePrevMon2(void) { u8 rval = Random() % 10; @@ -197,7 +198,7 @@ static void ContestEffect_StartlePrevMon2(void) ContestEffect_StartleFrontMon(); } -// Startles all POKMON that appealed before the user. +// Startles all POK�MON that appealed before the user. static void ContestEffect_StartlePrevMons2(void) { u8 numStartled = 0; @@ -273,7 +274,7 @@ static void ContestEffect_ShiftJudgeAttention(void) } } -// Startles the POKMON that has the JUDGE's attention. +// Startles the POK�MON that has the JUDGE's attention. static void ContestEffect_StartleMonWithJudgesAttention(void) { u8 numStartled = 0; @@ -311,50 +312,50 @@ static void ContestEffect_JamsOthersButMissOneTurn(void) SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Startles POKMON that made a same-type appeal. +// Startles POK�MON that made a same-type appeal. static void ContestEffect_StartleMonsSameTypeAppeal(void) { u16 move = eContestantStatus[eContestAppealResults.contestant].currMove; - JamByMoveCategory(gMovesInfo[move].contestCategory); + JamByMoveCategory(GetMoveContestCategory(move)); SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Badly startles POKMON that made COOL appeals. +// Badly startles POK�MON that made COOL appeals. static void ContestEffect_StartleMonsCoolAppeal(void) { JamByMoveCategory(CONTEST_CATEGORY_COOL); SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Badly startles POKMON that made BEAUTY appeals. +// Badly startles POK�MON that made BEAUTY appeals. static void ContestEffect_StartleMonsBeautyAppeal(void) { JamByMoveCategory(CONTEST_CATEGORY_BEAUTY); SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Badly startles POKMON that made CUTE appeals. +// Badly startles POK�MON that made CUTE appeals. static void ContestEffect_StartleMonsCuteAppeal(void) { JamByMoveCategory(CONTEST_CATEGORY_CUTE); SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Badly startles POKMON that made SMART appeals. +// Badly startles POK�MON that made SMART appeals. static void ContestEffect_StartleMonsSmartAppeal(void) { JamByMoveCategory(CONTEST_CATEGORY_SMART); SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Badly startles POKMON that made TOUGH appeals. +// Badly startles POK�MON that made TOUGH appeals. static void ContestEffect_StartleMonsToughAppeal(void) { JamByMoveCategory(CONTEST_CATEGORY_TOUGH); SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_ATTEMPT_STARTLE); } -// Makes one POKMON after the user nervous. +// Makes one POK�MON after the user nervous. static void ContestEffect_MakeFollowingMonNervous(void) { bool32 hitAny = FALSE; @@ -386,7 +387,7 @@ static void ContestEffect_MakeFollowingMonNervous(void) SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_MESSED_UP2); } -// Makes all POKMON after the user nervous. +// Makes all POK�MON after the user nervous. static void ContestEffect_MakeFollowingMonsNervous(void) { u8 numUnnerved = 0; @@ -428,7 +429,7 @@ static void ContestEffect_MakeFollowingMonsNervous(void) for (i = 0; i < CONTESTANT_COUNT; i++) { if (eContestantStatus[i].hasJudgesAttention && IsContestantAllowedToCombo(i)) - oddsMod[i] = gMovesInfo[eContestantStatus[i].prevMove].contestComboStarterId == 0 ? 0 : 10; + oddsMod[i] = GetMoveContestComboStarter(eContestantStatus[i].prevMove) == 0 ? 0 : 10; else oddsMod[i] = 0; oddsMod[i] -= (eContestantStatus[i].condition / 10) * 10; @@ -493,7 +494,7 @@ static void ContestEffect_WorsenConditionOfPrevMons(void) SetContestantEffectStringID2(eContestAppealResults.contestant, CONTEST_STRING_IGNORED); } -// Badly startles POKMON in good condition. +// Badly startles POK�MON in good condition. static void ContestEffect_BadlyStartlesMonsInGoodCondition(void) { u8 numHit = 0; @@ -524,7 +525,7 @@ static void ContestEffect_BetterIfFirst(void) if (gContestantTurnOrder[eContestAppealResults.contestant] == 0) { u16 move = eContestantStatus[eContestAppealResults.contestant].currMove; - eContestantStatus[eContestAppealResults.contestant].appeal += 2 * gContestEffects[gMovesInfo[move].contestEffect].appeal; + eContestantStatus[eContestAppealResults.contestant].appeal += 2 * gContestEffects[GetMoveContestEffect(move)].appeal; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_HUSTLE_STANDOUT); } } @@ -535,7 +536,7 @@ static void ContestEffect_BetterIfLast(void) if (gContestantTurnOrder[eContestAppealResults.contestant] == 3) { u16 move = eContestantStatus[eContestAppealResults.contestant].currMove; - eContestantStatus[eContestAppealResults.contestant].appeal += 2 * gContestEffects[gMovesInfo[move].contestEffect].appeal; + eContestantStatus[eContestAppealResults.contestant].appeal += 2 * gContestEffects[GetMoveContestEffect(move)].appeal; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_WORK_HARD_UNNOTICED); } } @@ -671,9 +672,9 @@ static void ContestEffect_BetterIfSameType(void) } move = eContestantStatus[eContestAppealResults.contestant].currMove; - if (gMovesInfo[move].contestCategory == gMovesInfo[eContestantStatus[j].currMove].contestCategory) + if (GetMoveContestCategory(move) == GetMoveContestCategory(eContestantStatus[j].currMove)) { - eContestantStatus[eContestAppealResults.contestant].appeal += gContestEffects[gMovesInfo[move].contestEffect].appeal * 2; + eContestantStatus[eContestAppealResults.contestant].appeal += gContestEffects[GetMoveContestEffect(move)].appeal * 2; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_SAME_TYPE_GOOD); } } @@ -689,9 +690,9 @@ static void ContestEffect_BetterIfDiffType(void) for (i = 0; i < CONTESTANT_COUNT; i++) { if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] - 1 == eContestAppealResults.turnOrder[i] && - gMovesInfo[move].contestCategory != gMovesInfo[eContestantStatus[i].currMove].contestCategory) + GetMoveContestCategory(move) != GetMoveContestCategory(eContestantStatus[i].currMove)) { - eContestantStatus[eContestAppealResults.contestant].appeal += gContestEffects[gMovesInfo[move].contestEffect].appeal * 2; + eContestantStatus[eContestAppealResults.contestant].appeal += gContestEffects[GetMoveContestEffect(move)].appeal * 2; SetContestantEffectStringID(eContestAppealResults.contestant, CONTEST_STRING_DIFF_TYPE_GOOD); break; } @@ -891,13 +892,13 @@ static void ContestEffect_ScrambleNextTurnOrder(void) // An appeal that excites the audience in any CONTEST. static void ContestEffect_ExciteAudienceInAnyContest(void) { - if (gMovesInfo[eContestantStatus[eContestAppealResults.contestant].currMove].contestCategory != gSpecialVar_ContestCategory) + if (GetMoveContestCategory(eContestantStatus[eContestAppealResults.contestant].currMove) != gSpecialVar_ContestCategory) { eContestantStatus[eContestAppealResults.contestant].overrideCategoryExcitementMod = TRUE; } } -// Badly startles all POKMON that made good appeals. +// Badly startles all POK�MON that made good appeals. static void ContestEffect_BadlyStartleMonsWithGoodAppeals(void) { int i; @@ -980,7 +981,7 @@ static void JamByMoveCategory(u8 category) { if (eContestAppealResults.turnOrder[eContestAppealResults.contestant] > eContestAppealResults.turnOrder[i]) { - if (category == gMovesInfo[eContestantStatus[i].currMove].contestCategory) + if (category == GetMoveContestCategory(eContestantStatus[i].currMove)) eContestAppealResults.jam = 40; else eContestAppealResults.jam = 10; diff --git a/src/credits.c b/src/credits.c index 5d5a80cf78ed..9269460e928c 100644 --- a/src/credits.c +++ b/src/credits.c @@ -81,10 +81,8 @@ struct CreditsEntry const u8 *text; }; -static EWRAM_DATA s16 UNUSED sUnkVar = 0; // Never read, only set to 0 static EWRAM_DATA u16 sSavedTaskId = 0; EWRAM_DATA bool8 gHasHallOfFameRecords = 0; -static EWRAM_DATA bool8 sUsedSpeedUp = 0; // Never read static EWRAM_DATA struct CreditsData *sCreditsData = {0}; static const u16 sCredits_Pal[] = INCBIN_U16("graphics/credits/credits.gbapal"); @@ -355,7 +353,6 @@ static void CB2_Credits(void) VBlankCB_Credits(); RunTasks(); AnimateSprites(); - sUsedSpeedUp = TRUE; } BuildOamBuffer(); UpdatePaletteFade(); @@ -448,7 +445,6 @@ void CB2_StartCreditsSequence(void) SetVBlankCallback(VBlankCB_Credits); m4aSongNumStart(MUS_CREDITS); SetMainCallback2(CB2_Credits); - sUsedSpeedUp = FALSE; sCreditsData = AllocZeroed(sizeof(struct CreditsData)); DeterminePokemonToShow(); @@ -480,7 +476,6 @@ static void Task_CreditsMain(u8 taskId) return; } - sUnkVar = 0; mode = gTasks[taskId].tNextMode; if (gTasks[taskId].tNextMode == MODE_BIKE_SCENE) @@ -740,7 +735,6 @@ static void Task_UpdatePage(u8 taskId) gTasks[taskId].tState = 1; gTasks[taskId].tDelay = 72; gTasks[gTasks[taskId].tMainTaskId].tPrintedPage = FALSE; - sUnkVar = 0; } return; case 1: diff --git a/src/crt0.s b/src/crt0.s index af6ea0bc9549..bd0eb9426c0b 100644 --- a/src/crt0.s +++ b/src/crt0.s @@ -14,15 +14,15 @@ Init:: mov r0, #PSR_SYS_MODE msr cpsr_cf, r0 ldr sp, sp_sys -@ Prepare for interrupt handling - ldr r1, =INTR_VECTOR - adr r0, IntrMain - str r0, [r1] @ Dispatch memory reset request to hardware mov r0, #255 @ RESET_ALL svc #1 << 16 @ Fill RAM areas with appropriate data bl InitializeWorkingMemory +@ Prepare for interrupt handling + ldr r1, =INTR_VECTOR + ldr r0, =IntrMain + str r0, [r1] @ Jump to AgbMain ldr r1, =AgbMain + 1 mov lr, pc @@ -37,6 +37,7 @@ sp_irq: .word IWRAM_END - 0x60 .pool .arm + .section .iwram.code .align 2, 0 IntrMain:: mov r3, #REG_BASE @@ -129,6 +130,7 @@ IntrMain_RetAddr: .pool + .text .align 2, 0 @ Don't pad with nop. @ Fills initialized IWRAM and EWRAM sections in RAM from LMA areas in ROM diff --git a/src/data.c b/src/data.c index ccb6b4c62324..e50fa0c549a6 100644 --- a/src/data.c +++ b/src/data.c @@ -227,7 +227,7 @@ const union AnimCmd *const sAnims_Trainer[] ={ #include "data/trainer_parties.h" -const struct Trainer gTrainers[] = +const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT] = { #include "data/trainers.h" }; diff --git a/src/data/battle_partners.h b/src/data/battle_partners.h index 95866d24faeb..ce451e0a4e09 100644 --- a/src/data/battle_partners.h +++ b/src/data/battle_partners.h @@ -9,7 +9,7 @@ #line 1 "src/data/battle_partners.party" #line 1 - [PARTNER_NONE] = + [DIFFICULTY_NORMAL][PARTNER_NONE] = { #line 3 .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, @@ -24,7 +24,7 @@ }, }, #line 8 - [PARTNER_STEVEN] = + [DIFFICULTY_NORMAL][PARTNER_STEVEN] = { #line 9 .trainerName = _("STEVEN"), diff --git a/src/data/field_effects/field_effect_object_template_pointers.h b/src/data/field_effects/field_effect_object_template_pointers.h index 14113d3a43bb..ee00023a51f7 100755 --- a/src/data/field_effects/field_effect_object_template_pointers.h +++ b/src/data/field_effects/field_effect_object_template_pointers.h @@ -38,6 +38,7 @@ extern const struct SpriteTemplate gFieldEffectObjectTemplate_Rayquaza; extern const struct SpriteTemplate gFieldEffectObjectTemplate_SlitherTracks; extern const struct SpriteTemplate gFieldEffectObjectTemplate_BugTracks; extern const struct SpriteTemplate gFieldEffectObjectTemplate_SpotTracks; +extern const struct SpriteTemplate gFieldEffectObjectTemplate_CaveDust; const struct SpriteTemplate *const gFieldEffectObjectTemplatePointers[] = { [FLDEFFOBJ_SHADOW_S] = &gFieldEffectObjectTemplate_ShadowSmall, @@ -80,4 +81,5 @@ const struct SpriteTemplate *const gFieldEffectObjectTemplatePointers[] = { [FLDEFFOBJ_TRACKS_SLITHER] = &gFieldEffectObjectTemplate_SlitherTracks, [FLDEFFOBJ_TRACKS_SPOT] = &gFieldEffectObjectTemplate_SpotTracks, [FLDEFFOBJ_TRACKS_BUG] = &gFieldEffectObjectTemplate_BugTracks, + [FLDEFFOBJ_CAVE_DUST] = &gFieldEffectObjectTemplate_CaveDust, }; diff --git a/src/data/field_effects/field_effect_objects.h b/src/data/field_effects/field_effect_objects.h index 1a169007c53a..ecea0350c572 100755 --- a/src/data/field_effects/field_effect_objects.h +++ b/src/data/field_effects/field_effect_objects.h @@ -1336,3 +1336,23 @@ const struct SpriteTemplate gFieldEffectObjectTemplate_Rayquaza = { }; static const struct SpritePalette sSpritePalette_Unused = {gObjectEventPal_Npc3, FLDEFF_PAL_TAG_UNKNOWN}; + +// cave dust +static const struct SpriteFrameImage sPicTable_CaveDust[] = +{ + overworld_frame(gFieldEffectObjectPic_CaveDust, 2, 2, 0), + overworld_frame(gFieldEffectObjectPic_CaveDust, 2, 2, 1), + overworld_frame(gFieldEffectObjectPic_CaveDust, 2, 2, 2), + overworld_frame(gFieldEffectObjectPic_CaveDust, 2, 2, 3), +}; +const struct SpriteTemplate gFieldEffectObjectTemplate_CaveDust = { + .tileTag = 0xFFFF, + .paletteTag = FLDEFF_PAL_TAG_CAVE_DUST, + .oam = &gObjectEventBaseOam_16x16, + .anims = sAnimTable_WaterSurfacing, + .images = sPicTable_CaveDust, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = WaitFieldEffectSpriteAnim, +}; + +const struct SpritePalette gSpritePalette_CaveDust = {gFieldEffectObjectPalette_CaveDust, FLDEFF_PAL_TAG_CAVE_DUST}; diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 726a0414f45b..141e2f16f89c 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -19787,92 +19787,92 @@ const u32 gObjectEventPic_Substitute[] = INCBIN_COMP("graphics/pokemon/question_ const u8 gMonFootprint_Furfrou[] = INCBIN_U8("graphics/pokemon/furfrou/footprint.1bpp"); #endif //P_FOOTPRINTS - const u32 gMonFrontPic_FurfrouHeartTrim[] = INCBIN_U32("graphics/pokemon/furfrou/heart_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouHeartTrim[] = INCBIN_U32("graphics/pokemon/furfrou/heart_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouHeartTrim[] = INCBIN_U32("graphics/pokemon/furfrou/heart_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouHeartTrim[] = INCBIN_U32("graphics/pokemon/furfrou/heart_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouHeartTrim[] = INCBIN_U8("graphics/pokemon/furfrou/heart_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouStarTrim[] = INCBIN_U32("graphics/pokemon/furfrou/star_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouStarTrim[] = INCBIN_U32("graphics/pokemon/furfrou/star_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouStarTrim[] = INCBIN_U32("graphics/pokemon/furfrou/star_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouStarTrim[] = INCBIN_U32("graphics/pokemon/furfrou/star_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouStarTrim[] = INCBIN_U8("graphics/pokemon/furfrou/star_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouDiamondTrim[] = INCBIN_U32("graphics/pokemon/furfrou/diamond_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouDiamondTrim[] = INCBIN_U32("graphics/pokemon/furfrou/diamond_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouDiamondTrim[] = INCBIN_U32("graphics/pokemon/furfrou/diamond_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouDiamondTrim[] = INCBIN_U32("graphics/pokemon/furfrou/diamond_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouDiamondTrim[] = INCBIN_U8("graphics/pokemon/furfrou/diamond_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouDebutanteTrim[] = INCBIN_U32("graphics/pokemon/furfrou/debutante_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouDebutanteTrim[] = INCBIN_U32("graphics/pokemon/furfrou/debutante_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouDebutanteTrim[] = INCBIN_U32("graphics/pokemon/furfrou/debutante_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouDebutanteTrim[] = INCBIN_U32("graphics/pokemon/furfrou/debutante_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouDebutanteTrim[] = INCBIN_U8("graphics/pokemon/furfrou/debutante_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouMatronTrim[] = INCBIN_U32("graphics/pokemon/furfrou/matron_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouMatronTrim[] = INCBIN_U32("graphics/pokemon/furfrou/matron_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouMatronTrim[] = INCBIN_U32("graphics/pokemon/furfrou/matron_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouMatronTrim[] = INCBIN_U32("graphics/pokemon/furfrou/matron_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouMatronTrim[] = INCBIN_U8("graphics/pokemon/furfrou/matron_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouDandyTrim[] = INCBIN_U32("graphics/pokemon/furfrou/dandy_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouDandyTrim[] = INCBIN_U32("graphics/pokemon/furfrou/dandy_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouDandyTrim[] = INCBIN_U32("graphics/pokemon/furfrou/dandy_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouDandyTrim[] = INCBIN_U32("graphics/pokemon/furfrou/dandy_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouDandyTrim[] = INCBIN_U8("graphics/pokemon/furfrou/dandy_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouLaReineTrim[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouLaReineTrim[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouLaReineTrim[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouLaReineTrim[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouLaReineTrim[] = INCBIN_U8("graphics/pokemon/furfrou/la_reine_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouKabukiTrim[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouKabukiTrim[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouKabukiTrim[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouKabukiTrim[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouKabukiTrim[] = INCBIN_U8("graphics/pokemon/furfrou/kabuki_trim/icon.4bpp"); - - const u32 gMonFrontPic_FurfrouPharaohTrim[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh_trim/anim_front.4bpp.lz"); - const u32 gMonPalette_FurfrouPharaohTrim[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh_trim/normal.gbapal.lz"); - const u32 gMonBackPic_FurfrouPharaohTrim[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh_trim/back.4bpp.lz"); - const u32 gMonShinyPalette_FurfrouPharaohTrim[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh_trim/shiny.gbapal.lz"); - const u8 gMonIcon_FurfrouPharaohTrim[] = INCBIN_U8("graphics/pokemon/furfrou/pharaoh_trim/icon.4bpp"); + const u32 gMonFrontPic_FurfrouHeart[] = INCBIN_U32("graphics/pokemon/furfrou/heart/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouHeart[] = INCBIN_U32("graphics/pokemon/furfrou/heart/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouHeart[] = INCBIN_U32("graphics/pokemon/furfrou/heart/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouHeart[] = INCBIN_U32("graphics/pokemon/furfrou/heart/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouHeart[] = INCBIN_U8("graphics/pokemon/furfrou/heart/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouStar[] = INCBIN_U32("graphics/pokemon/furfrou/star/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouStar[] = INCBIN_U32("graphics/pokemon/furfrou/star/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouStar[] = INCBIN_U32("graphics/pokemon/furfrou/star/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouStar[] = INCBIN_U32("graphics/pokemon/furfrou/star/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouStar[] = INCBIN_U8("graphics/pokemon/furfrou/star/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouDiamond[] = INCBIN_U32("graphics/pokemon/furfrou/diamond/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouDiamond[] = INCBIN_U32("graphics/pokemon/furfrou/diamond/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouDiamond[] = INCBIN_U32("graphics/pokemon/furfrou/diamond/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouDiamond[] = INCBIN_U32("graphics/pokemon/furfrou/diamond/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouDiamond[] = INCBIN_U8("graphics/pokemon/furfrou/diamond/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouDebutante[] = INCBIN_U32("graphics/pokemon/furfrou/debutante/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouDebutante[] = INCBIN_U32("graphics/pokemon/furfrou/debutante/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouDebutante[] = INCBIN_U32("graphics/pokemon/furfrou/debutante/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouDebutante[] = INCBIN_U32("graphics/pokemon/furfrou/debutante/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouDebutante[] = INCBIN_U8("graphics/pokemon/furfrou/debutante/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouMatron[] = INCBIN_U32("graphics/pokemon/furfrou/matron/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouMatron[] = INCBIN_U32("graphics/pokemon/furfrou/matron/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouMatron[] = INCBIN_U32("graphics/pokemon/furfrou/matron/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouMatron[] = INCBIN_U32("graphics/pokemon/furfrou/matron/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouMatron[] = INCBIN_U8("graphics/pokemon/furfrou/matron/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouDandy[] = INCBIN_U32("graphics/pokemon/furfrou/dandy/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouDandy[] = INCBIN_U32("graphics/pokemon/furfrou/dandy/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouDandy[] = INCBIN_U32("graphics/pokemon/furfrou/dandy/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouDandy[] = INCBIN_U32("graphics/pokemon/furfrou/dandy/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouDandy[] = INCBIN_U8("graphics/pokemon/furfrou/dandy/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouLaReine[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouLaReine[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouLaReine[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouLaReine[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouLaReine[] = INCBIN_U8("graphics/pokemon/furfrou/la_reine/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouKabuki[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouKabuki[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouKabuki[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouKabuki[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouKabuki[] = INCBIN_U8("graphics/pokemon/furfrou/kabuki/icon.4bpp"); + + const u32 gMonFrontPic_FurfrouPharaoh[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh/anim_front.4bpp.lz"); + const u32 gMonPalette_FurfrouPharaoh[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh/normal.gbapal.lz"); + const u32 gMonBackPic_FurfrouPharaoh[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh/back.4bpp.lz"); + const u32 gMonShinyPalette_FurfrouPharaoh[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh/shiny.gbapal.lz"); + const u8 gMonIcon_FurfrouPharaoh[] = INCBIN_U8("graphics/pokemon/furfrou/pharaoh/icon.4bpp"); #if OW_POKEMON_OBJECT_EVENTS const u32 gObjectEventPic_FurfrouNatural[] = INCBIN_COMP("graphics/pokemon/furfrou/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouHeartTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/heart_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouStarTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/star_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouDiamondTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/diamond_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouDebutanteTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/debutante_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouMatronTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/matron_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouDandyTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/dandy_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouLaReineTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/la_reine_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouKabukiTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/kabuki_trim/overworld.4bpp"); - const u32 gObjectEventPic_FurfrouPharaohTrim[] = INCBIN_COMP("graphics/pokemon/furfrou/pharaoh_trim/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouHeart[] = INCBIN_COMP("graphics/pokemon/furfrou/heart/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouStar[] = INCBIN_COMP("graphics/pokemon/furfrou/star/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouDiamond[] = INCBIN_COMP("graphics/pokemon/furfrou/diamond/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouDebutante[] = INCBIN_COMP("graphics/pokemon/furfrou/debutante/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouMatron[] = INCBIN_COMP("graphics/pokemon/furfrou/matron/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouDandy[] = INCBIN_COMP("graphics/pokemon/furfrou/dandy/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouLaReine[] = INCBIN_COMP("graphics/pokemon/furfrou/la_reine/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouKabuki[] = INCBIN_COMP("graphics/pokemon/furfrou/kabuki/overworld.4bpp"); + const u32 gObjectEventPic_FurfrouPharaoh[] = INCBIN_COMP("graphics/pokemon/furfrou/pharaoh/overworld.4bpp"); #if OW_PKMN_OBJECTS_SHARE_PALETTES == FALSE const u32 gOverworldPalette_FurfrouNatural[] = INCBIN_U32("graphics/pokemon/furfrou/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouHeartTrim[] = INCBIN_U32("graphics/pokemon/furfrou/heart_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouStarTrim[] = INCBIN_U32("graphics/pokemon/furfrou/star_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouDiamondTrim[] = INCBIN_U32("graphics/pokemon/furfrou/diamond_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouDebutanteTrim[] = INCBIN_U32("graphics/pokemon/furfrou/debutante_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouMatronTrim[] = INCBIN_U32("graphics/pokemon/furfrou/matron_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouDandyTrim[] = INCBIN_U32("graphics/pokemon/furfrou/dandy_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouLaReineTrim[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouKabukiTrim[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki_trim/overworld_normal.gbapal.lz"); - const u32 gOverworldPalette_FurfrouPharaohTrim[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh_trim/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouHeart[] = INCBIN_U32("graphics/pokemon/furfrou/heart/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouStar[] = INCBIN_U32("graphics/pokemon/furfrou/star/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouDiamond[] = INCBIN_U32("graphics/pokemon/furfrou/diamond/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouDebutante[] = INCBIN_U32("graphics/pokemon/furfrou/debutante/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouMatron[] = INCBIN_U32("graphics/pokemon/furfrou/matron/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouDandy[] = INCBIN_U32("graphics/pokemon/furfrou/dandy/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouLaReine[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouKabuki[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki/overworld_normal.gbapal.lz"); + const u32 gOverworldPalette_FurfrouPharaoh[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh/overworld_normal.gbapal.lz"); const u32 gShinyOverworldPalette_FurfrouNatural[] = INCBIN_U32("graphics/pokemon/furfrou/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouHeartTrim[] = INCBIN_U32("graphics/pokemon/furfrou/heart_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouStarTrim[] = INCBIN_U32("graphics/pokemon/furfrou/star_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouDiamondTrim[] = INCBIN_U32("graphics/pokemon/furfrou/diamond_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouDebutanteTrim[] = INCBIN_U32("graphics/pokemon/furfrou/debutante_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouMatronTrim[] = INCBIN_U32("graphics/pokemon/furfrou/matron_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouDandyTrim[] = INCBIN_U32("graphics/pokemon/furfrou/dandy_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouLaReineTrim[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouKabukiTrim[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki_trim/overworld_shiny.gbapal.lz"); - const u32 gShinyOverworldPalette_FurfrouPharaohTrim[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh_trim/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouHeart[] = INCBIN_U32("graphics/pokemon/furfrou/heart/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouStar[] = INCBIN_U32("graphics/pokemon/furfrou/star/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouDiamond[] = INCBIN_U32("graphics/pokemon/furfrou/diamond/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouDebutante[] = INCBIN_U32("graphics/pokemon/furfrou/debutante/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouMatron[] = INCBIN_U32("graphics/pokemon/furfrou/matron/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouDandy[] = INCBIN_U32("graphics/pokemon/furfrou/dandy/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouLaReine[] = INCBIN_U32("graphics/pokemon/furfrou/la_reine/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouKabuki[] = INCBIN_U32("graphics/pokemon/furfrou/kabuki/overworld_shiny.gbapal.lz"); + const u32 gShinyOverworldPalette_FurfrouPharaoh[] = INCBIN_U32("graphics/pokemon/furfrou/pharaoh/overworld_shiny.gbapal.lz"); #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS #endif //P_FAMILY_FURFROU diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 2c28621286df..ec9e209dda47 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -21567,7 +21567,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = [MOVE_G_MAX_CANNONADE] = { - .name = COMPOUND_STRING("G-Max Canonade"), + .name = COMPOUND_STRING("G-Max Cannonade"), .description = sNullDescription, //ANIM TODO .effect = EFFECT_MAX_MOVE, .power = 10, diff --git a/src/data/object_events/object_event_graphics.h b/src/data/object_events/object_event_graphics.h index 1f08b77599f9..577263e77b91 100755 --- a/src/data/object_events/object_event_graphics.h +++ b/src/data/object_events/object_event_graphics.h @@ -454,3 +454,6 @@ const u16 gObjectEventPal_BeastBall[] = INCBIN_U16("graphics/object_events/pics/ const u16 gObjectEventPal_StrangeBall[] = INCBIN_U16("graphics/object_events/pics/misc/ball_strange.gbapal"); #endif //ITEM_STRANGE_BALL #endif //OW_FOLLOWERS_POKEBALLS + +const u32 gFieldEffectObjectPic_CaveDust[] = INCBIN_U32("graphics/field_effects/pics/cave_dust.4bpp"); +const u16 gFieldEffectObjectPalette_CaveDust[] = INCBIN_U16("graphics/field_effects/palettes/cave_dust.gbapal"); diff --git a/src/data/party_menu.h b/src/data/party_menu.h index 3bc86593fa01..168387dbf4a5 100644 --- a/src/data/party_menu.h +++ b/src/data/party_menu.h @@ -659,6 +659,7 @@ static const u8 *const sActionStringTable[] = [PARTY_MSG_ALREADY_HOLDING_ONE] = gText_AlreadyHoldingOne, [PARTY_MSG_WHICH_APPLIANCE] = gText_WhichAppliance, [PARTY_MSG_CHOOSE_SECOND_FUSION] = gText_NextFusionMon, + [PARTY_MSG_NO_POKEMON] = COMPOUND_STRING("You have no POKéMON."), }; static const u8 *const sDescriptionStringTable[] = @@ -838,7 +839,7 @@ static const u8 *const sUnionRoomTradeMessages[] = }; static const u32 sHeldItemGfx[] = INCBIN_U32("graphics/party_menu/hold_icons.4bpp"); -static const u16 sHeldItemPalette[] = INCBIN_U16("graphics/party_menu/hold_icons.gbapal"); +const u16 gHeldItemPalette[] = INCBIN_U16("graphics/party_menu/hold_icons.gbapal"); static const struct OamData sOamData_HeldItem = { @@ -875,14 +876,14 @@ static const union AnimCmd *const sSpriteAnimTable_HeldItem[] = sSpriteAnim_HeldMail, }; -static const struct SpriteSheet sSpriteSheet_HeldItem = +const struct SpriteSheet gSpriteSheet_HeldItem = { .data = sHeldItemGfx, .size = sizeof(sHeldItemGfx), .tag = TAG_HELD_ITEM }; static const struct SpritePalette sSpritePalette_HeldItem = { - .data = sHeldItemPalette, .tag = TAG_HELD_ITEM + .data = gHeldItemPalette, .tag = TAG_HELD_ITEM }; static const struct SpriteTemplate sSpriteTemplate_HeldItem = diff --git a/src/data/pokemon/form_species_tables.h b/src/data/pokemon/form_species_tables.h index f2c456021651..f30c1cca77b1 100644 --- a/src/data/pokemon/form_species_tables.h +++ b/src/data/pokemon/form_species_tables.h @@ -1459,15 +1459,15 @@ static const u16 sFlorgesFormSpeciesIdTable[] = { #if P_FAMILY_FURFROU static const u16 sFurfrouFormSpeciesIdTable[] = { SPECIES_FURFROU_NATURAL, - SPECIES_FURFROU_HEART_TRIM, - SPECIES_FURFROU_STAR_TRIM, - SPECIES_FURFROU_DIAMOND_TRIM, - SPECIES_FURFROU_DEBUTANTE_TRIM, - SPECIES_FURFROU_MATRON_TRIM, - SPECIES_FURFROU_DANDY_TRIM, - SPECIES_FURFROU_LA_REINE_TRIM, - SPECIES_FURFROU_KABUKI_TRIM, - SPECIES_FURFROU_PHARAOH_TRIM, + SPECIES_FURFROU_HEART, + SPECIES_FURFROU_STAR, + SPECIES_FURFROU_DIAMOND, + SPECIES_FURFROU_DEBUTANTE, + SPECIES_FURFROU_MATRON, + SPECIES_FURFROU_DANDY, + SPECIES_FURFROU_LA_REINE, + SPECIES_FURFROU_KABUKI, + SPECIES_FURFROU_PHARAOH, FORM_SPECIES_END, }; #endif //P_FAMILY_FURFROU diff --git a/src/data/pokemon/pokedex_orders.h b/src/data/pokemon/pokedex_orders.h index 1b0b32c63c54..b2f5f3cc02d1 100644 --- a/src/data/pokemon/pokedex_orders.h +++ b/src/data/pokemon/pokedex_orders.h @@ -1894,15 +1894,15 @@ const u16 gPokedexOrder_Weight[] = NATIONAL_DEX_SIMISEAR, NATIONAL_DEX_MARACTUS, NATIONAL_DEX_FURFROU,//_NATURAL, - //NATIONAL_DEX_FURFROU_HEART_TRIM, - //NATIONAL_DEX_FURFROU_STAR_TRIM, - //NATIONAL_DEX_FURFROU_DIAMOND_TRIM, - //NATIONAL_DEX_FURFROU_DEBUTANTE_TRIM, - //NATIONAL_DEX_FURFROU_MATRON_TRIM, - //NATIONAL_DEX_FURFROU_DANDY_TRIM, - //NATIONAL_DEX_FURFROU_LA_REINE_TRIM, - //NATIONAL_DEX_FURFROU_KABUKI_TRIM, - //NATIONAL_DEX_FURFROU_PHARAOH_TRIM, + //NATIONAL_DEX_FURFROU_HEART, + //NATIONAL_DEX_FURFROU_STAR, + //NATIONAL_DEX_FURFROU_DIAMOND, + //NATIONAL_DEX_FURFROU_DEBUTANTE, + //NATIONAL_DEX_FURFROU_MATRON, + //NATIONAL_DEX_FURFROU_DANDY, + //NATIONAL_DEX_FURFROU_LA_REINE, + //NATIONAL_DEX_FURFROU_KABUKI, + //NATIONAL_DEX_FURFROU_PHARAOH, NATIONAL_DEX_PERRSERKER, NATIONAL_DEX_INDEEDEE,//_MALE, //NATIONAL_DEX_INDEEDEE_FEMALE, @@ -3711,15 +3711,15 @@ const u16 gPokedexOrder_Height[] = NATIONAL_DEX_TALONFLAME, NATIONAL_DEX_VIVILLON, NATIONAL_DEX_FURFROU,//_NATURAL, - //NATIONAL_DEX_FURFROU_HEART_TRIM, - //NATIONAL_DEX_FURFROU_STAR_TRIM, - //NATIONAL_DEX_FURFROU_DIAMOND_TRIM, - //NATIONAL_DEX_FURFROU_DEBUTANTE_TRIM, - //NATIONAL_DEX_FURFROU_MATRON_TRIM, - //NATIONAL_DEX_FURFROU_DANDY_TRIM, - //NATIONAL_DEX_FURFROU_LA_REINE_TRIM, - //NATIONAL_DEX_FURFROU_KABUKI_TRIM, - //NATIONAL_DEX_FURFROU_PHARAOH_TRIM, + //NATIONAL_DEX_FURFROU_HEART, + //NATIONAL_DEX_FURFROU_STAR, + //NATIONAL_DEX_FURFROU_DIAMOND, + //NATIONAL_DEX_FURFROU_DEBUTANTE, + //NATIONAL_DEX_FURFROU_MATRON, + //NATIONAL_DEX_FURFROU_DANDY, + //NATIONAL_DEX_FURFROU_LA_REINE, + //NATIONAL_DEX_FURFROU_KABUKI, + //NATIONAL_DEX_FURFROU_PHARAOH, //NATIONAL_DEX_ZYGARDE_10, //NATIONAL_DEX_ZYGARDE_10_POWER_CONSTRUCT, NATIONAL_DEX_SALAZZLE, diff --git a/src/data/pokemon/species_info/gen_6_families.h b/src/data/pokemon/species_info/gen_6_families.h index 35af532e6026..2c6c142eae96 100644 --- a/src/data/pokemon/species_info/gen_6_families.h +++ b/src/data/pokemon/species_info/gen_6_families.h @@ -2221,16 +2221,16 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .formChangeTable = sFurfrouFormChangeTable, \ } - [SPECIES_FURFROU_NATURAL] = FURFROU_MISC_INFO(Natural, FALSE, 48, 3, 56, 0, 0), - [SPECIES_FURFROU_HEART_TRIM] = FURFROU_MISC_INFO(HeartTrim, FALSE, 56, 2, 56, 1, 0), - [SPECIES_FURFROU_STAR_TRIM] = FURFROU_MISC_INFO(StarTrim, FALSE, 56, 2, 64, 1, 0), - [SPECIES_FURFROU_DIAMOND_TRIM] = FURFROU_MISC_INFO(DiamondTrim, FALSE, 48, 2, 56, 1, 0), - [SPECIES_FURFROU_DEBUTANTE_TRIM] = FURFROU_MISC_INFO(DebutanteTrim, TRUE, 48, 2, 56, 1, 2), - [SPECIES_FURFROU_MATRON_TRIM] = FURFROU_MISC_INFO(MatronTrim, FALSE, 48, 2, 56, 1, 2), - [SPECIES_FURFROU_DANDY_TRIM] = FURFROU_MISC_INFO(DandyTrim, FALSE, 48, 2, 56, 1, 1), - [SPECIES_FURFROU_LA_REINE_TRIM] = FURFROU_MISC_INFO(LaReineTrim, FALSE, 48, 2, 56, 1, 0), - [SPECIES_FURFROU_KABUKI_TRIM] = FURFROU_MISC_INFO(KabukiTrim, FALSE, 56, 2, 56, 1, 0), - [SPECIES_FURFROU_PHARAOH_TRIM] = FURFROU_MISC_INFO(PharaohTrim, FALSE, 48, 2, 56, 1, 0), + [SPECIES_FURFROU_NATURAL] = FURFROU_MISC_INFO(Natural, FALSE, 48, 3, 56, 0, 0), + [SPECIES_FURFROU_HEART] = FURFROU_MISC_INFO(Heart, FALSE, 56, 2, 56, 1, 0), + [SPECIES_FURFROU_STAR] = FURFROU_MISC_INFO(Star, FALSE, 56, 2, 64, 1, 0), + [SPECIES_FURFROU_DIAMOND] = FURFROU_MISC_INFO(Diamond, FALSE, 48, 2, 56, 1, 0), + [SPECIES_FURFROU_DEBUTANTE] = FURFROU_MISC_INFO(Debutante, TRUE, 48, 2, 56, 1, 2), + [SPECIES_FURFROU_MATRON] = FURFROU_MISC_INFO(Matron, FALSE, 48, 2, 56, 1, 2), + [SPECIES_FURFROU_DANDY] = FURFROU_MISC_INFO(Dandy, FALSE, 48, 2, 56, 1, 1), + [SPECIES_FURFROU_LA_REINE] = FURFROU_MISC_INFO(LaReine, FALSE, 48, 2, 56, 1, 0), + [SPECIES_FURFROU_KABUKI] = FURFROU_MISC_INFO(Kabuki, FALSE, 56, 2, 56, 1, 0), + [SPECIES_FURFROU_PHARAOH] = FURFROU_MISC_INFO(Pharaoh, FALSE, 48, 2, 56, 1, 0), #endif //P_FAMILY_FURFROU #if P_FAMILY_ESPURR diff --git a/src/data/trainers.h b/src/data/trainers.h index ebc85e9cab2d..ffe1d90f0266 100644 --- a/src/data/trainers.h +++ b/src/data/trainers.h @@ -9,7 +9,7 @@ #line 1 "src/data/trainers.party" #line 76 - [TRAINER_NONE] = + [DIFFICULTY_NORMAL][TRAINER_NONE] = { #line 78 .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, @@ -26,7 +26,7 @@ }, }, #line 84 - [TRAINER_SAWYER_1] = + [DIFFICULTY_NORMAL][TRAINER_SAWYER_1] = { #line 85 .trainerName = _("SAWYER"), @@ -58,7 +58,7 @@ }, }, #line 97 - [TRAINER_GRUNT_AQUA_HIDEOUT_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_1] = { #line 98 .trainerName = _("GRUNT"), @@ -90,7 +90,7 @@ }, }, #line 110 - [TRAINER_GRUNT_AQUA_HIDEOUT_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_2] = { #line 111 .trainerName = _("GRUNT"), @@ -133,7 +133,7 @@ }, }, #line 127 - [TRAINER_GRUNT_AQUA_HIDEOUT_3] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_3] = { #line 128 .trainerName = _("GRUNT"), @@ -165,7 +165,7 @@ }, }, #line 140 - [TRAINER_GRUNT_AQUA_HIDEOUT_4] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_4] = { #line 141 .trainerName = _("GRUNT"), @@ -197,7 +197,7 @@ }, }, #line 153 - [TRAINER_GRUNT_SEAFLOOR_CAVERN_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SEAFLOOR_CAVERN_1] = { #line 154 .trainerName = _("GRUNT"), @@ -229,7 +229,7 @@ }, }, #line 166 - [TRAINER_GRUNT_SEAFLOOR_CAVERN_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SEAFLOOR_CAVERN_2] = { #line 167 .trainerName = _("GRUNT"), @@ -261,7 +261,7 @@ }, }, #line 179 - [TRAINER_GRUNT_SEAFLOOR_CAVERN_3] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SEAFLOOR_CAVERN_3] = { #line 180 .trainerName = _("GRUNT"), @@ -293,7 +293,7 @@ }, }, #line 192 - [TRAINER_GABRIELLE_1] = + [DIFFICULTY_NORMAL][TRAINER_GABRIELLE_1] = { #line 193 .trainerName = _("GABRIELLE"), @@ -382,7 +382,7 @@ F_TRAINER_FEMALE | }, }, #line 225 - [TRAINER_GRUNT_PETALBURG_WOODS] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_PETALBURG_WOODS] = { #line 226 .trainerName = _("GRUNT"), @@ -414,7 +414,7 @@ F_TRAINER_FEMALE | }, }, #line 238 - [TRAINER_MARCEL] = + [DIFFICULTY_NORMAL][TRAINER_MARCEL] = { #line 239 .trainerName = _("MARCEL"), @@ -459,7 +459,7 @@ F_TRAINER_FEMALE | }, }, #line 256 - [TRAINER_ALBERTO] = + [DIFFICULTY_NORMAL][TRAINER_ALBERTO] = { #line 257 .trainerName = _("ALBERTO"), @@ -502,7 +502,7 @@ F_TRAINER_FEMALE | }, }, #line 273 - [TRAINER_ED] = + [DIFFICULTY_NORMAL][TRAINER_ED] = { #line 274 .trainerName = _("ED"), @@ -545,7 +545,7 @@ F_TRAINER_FEMALE | }, }, #line 290 - [TRAINER_GRUNT_SEAFLOOR_CAVERN_4] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SEAFLOOR_CAVERN_4] = { #line 291 .trainerName = _("GRUNT"), @@ -579,7 +579,7 @@ F_TRAINER_FEMALE | }, }, #line 303 - [TRAINER_DECLAN] = + [DIFFICULTY_NORMAL][TRAINER_DECLAN] = { #line 304 .trainerName = _("DECLAN"), @@ -611,7 +611,7 @@ F_TRAINER_FEMALE | }, }, #line 316 - [TRAINER_GRUNT_RUSTURF_TUNNEL] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_RUSTURF_TUNNEL] = { #line 317 .trainerName = _("GRUNT"), @@ -643,7 +643,7 @@ F_TRAINER_FEMALE | }, }, #line 329 - [TRAINER_GRUNT_WEATHER_INST_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_WEATHER_INST_1] = { #line 330 .trainerName = _("GRUNT"), @@ -686,7 +686,7 @@ F_TRAINER_FEMALE | }, }, #line 346 - [TRAINER_GRUNT_WEATHER_INST_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_WEATHER_INST_2] = { #line 347 .trainerName = _("GRUNT"), @@ -729,7 +729,7 @@ F_TRAINER_FEMALE | }, }, #line 363 - [TRAINER_GRUNT_WEATHER_INST_3] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_WEATHER_INST_3] = { #line 364 .trainerName = _("GRUNT"), @@ -783,7 +783,7 @@ F_TRAINER_FEMALE | }, }, #line 384 - [TRAINER_GRUNT_MUSEUM_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MUSEUM_1] = { #line 385 .trainerName = _("GRUNT"), @@ -815,7 +815,7 @@ F_TRAINER_FEMALE | }, }, #line 397 - [TRAINER_GRUNT_MUSEUM_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MUSEUM_2] = { #line 398 .trainerName = _("GRUNT"), @@ -858,7 +858,7 @@ F_TRAINER_FEMALE | }, }, #line 414 - [TRAINER_GRUNT_SPACE_CENTER_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_1] = { #line 415 .trainerName = _("GRUNT"), @@ -890,7 +890,7 @@ F_TRAINER_FEMALE | }, }, #line 427 - [TRAINER_GRUNT_MT_PYRE_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MT_PYRE_1] = { #line 428 .trainerName = _("GRUNT"), @@ -922,7 +922,7 @@ F_TRAINER_FEMALE | }, }, #line 440 - [TRAINER_GRUNT_MT_PYRE_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MT_PYRE_2] = { #line 441 .trainerName = _("GRUNT"), @@ -954,7 +954,7 @@ F_TRAINER_FEMALE | }, }, #line 453 - [TRAINER_GRUNT_MT_PYRE_3] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MT_PYRE_3] = { #line 454 .trainerName = _("GRUNT"), @@ -997,7 +997,7 @@ F_TRAINER_FEMALE | }, }, #line 470 - [TRAINER_GRUNT_WEATHER_INST_4] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_WEATHER_INST_4] = { #line 471 .trainerName = _("GRUNT"), @@ -1031,7 +1031,7 @@ F_TRAINER_FEMALE | }, }, #line 483 - [TRAINER_GRUNT_AQUA_HIDEOUT_5] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_5] = { #line 484 .trainerName = _("GRUNT"), @@ -1065,7 +1065,7 @@ F_TRAINER_FEMALE | }, }, #line 496 - [TRAINER_GRUNT_AQUA_HIDEOUT_6] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_6] = { #line 497 .trainerName = _("GRUNT"), @@ -1099,7 +1099,7 @@ F_TRAINER_FEMALE | }, }, #line 509 - [TRAINER_FREDRICK] = + [DIFFICULTY_NORMAL][TRAINER_FREDRICK] = { #line 510 .trainerName = _("FREDRICK"), @@ -1142,7 +1142,7 @@ F_TRAINER_FEMALE | }, }, #line 526 - [TRAINER_MATT] = + [DIFFICULTY_NORMAL][TRAINER_MATT] = { #line 527 .trainerName = _("MATT"), @@ -1187,7 +1187,7 @@ F_TRAINER_FEMALE | }, }, #line 544 - [TRAINER_ZANDER] = + [DIFFICULTY_NORMAL][TRAINER_ZANDER] = { #line 545 .trainerName = _("ZANDER"), @@ -1219,7 +1219,7 @@ F_TRAINER_FEMALE | }, }, #line 557 - [TRAINER_SHELLY_WEATHER_INSTITUTE] = + [DIFFICULTY_NORMAL][TRAINER_SHELLY_WEATHER_INSTITUTE] = { #line 558 .trainerName = _("SHELLY"), @@ -1264,7 +1264,7 @@ F_TRAINER_FEMALE | }, }, #line 574 - [TRAINER_SHELLY_SEAFLOOR_CAVERN] = + [DIFFICULTY_NORMAL][TRAINER_SHELLY_SEAFLOOR_CAVERN] = { #line 575 .trainerName = _("SHELLY"), @@ -1309,7 +1309,7 @@ F_TRAINER_FEMALE | }, }, #line 591 - [TRAINER_ARCHIE] = + [DIFFICULTY_NORMAL][TRAINER_ARCHIE] = { #line 592 .trainerName = _("ARCHIE"), @@ -1365,7 +1365,7 @@ F_TRAINER_FEMALE | }, }, #line 613 - [TRAINER_LEAH] = + [DIFFICULTY_NORMAL][TRAINER_LEAH] = { #line 614 .trainerName = _("LEAH"), @@ -1399,7 +1399,7 @@ F_TRAINER_FEMALE | }, }, #line 626 - [TRAINER_DAISY] = + [DIFFICULTY_NORMAL][TRAINER_DAISY] = { #line 627 .trainerName = _("DAISY"), @@ -1444,7 +1444,7 @@ F_TRAINER_FEMALE | }, }, #line 643 - [TRAINER_ROSE_1] = + [DIFFICULTY_NORMAL][TRAINER_ROSE_1] = { #line 644 .trainerName = _("ROSE"), @@ -1500,7 +1500,7 @@ F_TRAINER_FEMALE | }, }, #line 664 - [TRAINER_FELIX] = + [DIFFICULTY_NORMAL][TRAINER_FELIX] = { #line 665 .trainerName = _("FELIX"), @@ -1554,7 +1554,7 @@ F_TRAINER_FEMALE | }, }, #line 685 - [TRAINER_VIOLET] = + [DIFFICULTY_NORMAL][TRAINER_VIOLET] = { #line 686 .trainerName = _("VIOLET"), @@ -1599,7 +1599,7 @@ F_TRAINER_FEMALE | }, }, #line 702 - [TRAINER_ROSE_2] = + [DIFFICULTY_NORMAL][TRAINER_ROSE_2] = { #line 703 .trainerName = _("ROSE"), @@ -1644,7 +1644,7 @@ F_TRAINER_FEMALE | }, }, #line 719 - [TRAINER_ROSE_3] = + [DIFFICULTY_NORMAL][TRAINER_ROSE_3] = { #line 720 .trainerName = _("ROSE"), @@ -1700,7 +1700,7 @@ F_TRAINER_FEMALE | }, }, #line 740 - [TRAINER_ROSE_4] = + [DIFFICULTY_NORMAL][TRAINER_ROSE_4] = { #line 741 .trainerName = _("ROSE"), @@ -1756,7 +1756,7 @@ F_TRAINER_FEMALE | }, }, #line 761 - [TRAINER_ROSE_5] = + [DIFFICULTY_NORMAL][TRAINER_ROSE_5] = { #line 762 .trainerName = _("ROSE"), @@ -1812,7 +1812,7 @@ F_TRAINER_FEMALE | }, }, #line 782 - [TRAINER_DUSTY_1] = + [DIFFICULTY_NORMAL][TRAINER_DUSTY_1] = { #line 783 .trainerName = _("DUSTY"), @@ -1851,7 +1851,7 @@ F_TRAINER_FEMALE | }, }, #line 799 - [TRAINER_CHIP] = + [DIFFICULTY_NORMAL][TRAINER_CHIP] = { #line 800 .trainerName = _("CHIP"), @@ -1926,7 +1926,7 @@ F_TRAINER_FEMALE | }, }, #line 832 - [TRAINER_FOSTER] = + [DIFFICULTY_NORMAL][TRAINER_FOSTER] = { #line 833 .trainerName = _("FOSTER"), @@ -1983,7 +1983,7 @@ F_TRAINER_FEMALE | }, }, #line 857 - [TRAINER_DUSTY_2] = + [DIFFICULTY_NORMAL][TRAINER_DUSTY_2] = { #line 858 .trainerName = _("DUSTY"), @@ -2022,7 +2022,7 @@ F_TRAINER_FEMALE | }, }, #line 874 - [TRAINER_DUSTY_3] = + [DIFFICULTY_NORMAL][TRAINER_DUSTY_3] = { #line 875 .trainerName = _("DUSTY"), @@ -2061,7 +2061,7 @@ F_TRAINER_FEMALE | }, }, #line 891 - [TRAINER_DUSTY_4] = + [DIFFICULTY_NORMAL][TRAINER_DUSTY_4] = { #line 892 .trainerName = _("DUSTY"), @@ -2100,7 +2100,7 @@ F_TRAINER_FEMALE | }, }, #line 908 - [TRAINER_DUSTY_5] = + [DIFFICULTY_NORMAL][TRAINER_DUSTY_5] = { #line 909 .trainerName = _("DUSTY"), @@ -2139,7 +2139,7 @@ F_TRAINER_FEMALE | }, }, #line 925 - [TRAINER_GABBY_AND_TY_1] = + [DIFFICULTY_NORMAL][TRAINER_GABBY_AND_TY_1] = { #line 926 .trainerName = _("GABBY & TY"), @@ -2182,7 +2182,7 @@ F_TRAINER_FEMALE | }, }, #line 942 - [TRAINER_GABBY_AND_TY_2] = + [DIFFICULTY_NORMAL][TRAINER_GABBY_AND_TY_2] = { #line 943 .trainerName = _("GABBY & TY"), @@ -2225,7 +2225,7 @@ F_TRAINER_FEMALE | }, }, #line 959 - [TRAINER_GABBY_AND_TY_3] = + [DIFFICULTY_NORMAL][TRAINER_GABBY_AND_TY_3] = { #line 960 .trainerName = _("GABBY & TY"), @@ -2268,7 +2268,7 @@ F_TRAINER_FEMALE | }, }, #line 976 - [TRAINER_GABBY_AND_TY_4] = + [DIFFICULTY_NORMAL][TRAINER_GABBY_AND_TY_4] = { #line 977 .trainerName = _("GABBY & TY"), @@ -2311,7 +2311,7 @@ F_TRAINER_FEMALE | }, }, #line 993 - [TRAINER_GABBY_AND_TY_5] = + [DIFFICULTY_NORMAL][TRAINER_GABBY_AND_TY_5] = { #line 994 .trainerName = _("GABBY & TY"), @@ -2354,7 +2354,7 @@ F_TRAINER_FEMALE | }, }, #line 1010 - [TRAINER_GABBY_AND_TY_6] = + [DIFFICULTY_NORMAL][TRAINER_GABBY_AND_TY_6] = { #line 1011 .trainerName = _("GABBY & TY"), @@ -2411,7 +2411,7 @@ F_TRAINER_FEMALE | }, }, #line 1035 - [TRAINER_LOLA_1] = + [DIFFICULTY_NORMAL][TRAINER_LOLA_1] = { #line 1036 .trainerName = _("LOLA"), @@ -2456,7 +2456,7 @@ F_TRAINER_FEMALE | }, }, #line 1052 - [TRAINER_AUSTINA] = + [DIFFICULTY_NORMAL][TRAINER_AUSTINA] = { #line 1053 .trainerName = _("AUSTINA"), @@ -2490,7 +2490,7 @@ F_TRAINER_FEMALE | }, }, #line 1065 - [TRAINER_GWEN] = + [DIFFICULTY_NORMAL][TRAINER_GWEN] = { #line 1066 .trainerName = _("GWEN"), @@ -2524,7 +2524,7 @@ F_TRAINER_FEMALE | }, }, #line 1078 - [TRAINER_LOLA_2] = + [DIFFICULTY_NORMAL][TRAINER_LOLA_2] = { #line 1079 .trainerName = _("LOLA"), @@ -2569,7 +2569,7 @@ F_TRAINER_FEMALE | }, }, #line 1095 - [TRAINER_LOLA_3] = + [DIFFICULTY_NORMAL][TRAINER_LOLA_3] = { #line 1096 .trainerName = _("LOLA"), @@ -2614,7 +2614,7 @@ F_TRAINER_FEMALE | }, }, #line 1112 - [TRAINER_LOLA_4] = + [DIFFICULTY_NORMAL][TRAINER_LOLA_4] = { #line 1113 .trainerName = _("LOLA"), @@ -2659,7 +2659,7 @@ F_TRAINER_FEMALE | }, }, #line 1129 - [TRAINER_LOLA_5] = + [DIFFICULTY_NORMAL][TRAINER_LOLA_5] = { #line 1130 .trainerName = _("LOLA"), @@ -2704,7 +2704,7 @@ F_TRAINER_FEMALE | }, }, #line 1146 - [TRAINER_RICKY_1] = + [DIFFICULTY_NORMAL][TRAINER_RICKY_1] = { #line 1147 .trainerName = _("RICKY"), @@ -2743,7 +2743,7 @@ F_TRAINER_FEMALE | }, }, #line 1163 - [TRAINER_SIMON] = + [DIFFICULTY_NORMAL][TRAINER_SIMON] = { #line 1164 .trainerName = _("SIMON"), @@ -2786,7 +2786,7 @@ F_TRAINER_FEMALE | }, }, #line 1180 - [TRAINER_CHARLIE] = + [DIFFICULTY_NORMAL][TRAINER_CHARLIE] = { #line 1181 .trainerName = _("CHARLIE"), @@ -2818,7 +2818,7 @@ F_TRAINER_FEMALE | }, }, #line 1193 - [TRAINER_RICKY_2] = + [DIFFICULTY_NORMAL][TRAINER_RICKY_2] = { #line 1194 .trainerName = _("RICKY"), @@ -2857,7 +2857,7 @@ F_TRAINER_FEMALE | }, }, #line 1210 - [TRAINER_RICKY_3] = + [DIFFICULTY_NORMAL][TRAINER_RICKY_3] = { #line 1211 .trainerName = _("RICKY"), @@ -2896,7 +2896,7 @@ F_TRAINER_FEMALE | }, }, #line 1227 - [TRAINER_RICKY_4] = + [DIFFICULTY_NORMAL][TRAINER_RICKY_4] = { #line 1228 .trainerName = _("RICKY"), @@ -2935,7 +2935,7 @@ F_TRAINER_FEMALE | }, }, #line 1244 - [TRAINER_RICKY_5] = + [DIFFICULTY_NORMAL][TRAINER_RICKY_5] = { #line 1245 .trainerName = _("RICKY"), @@ -2974,7 +2974,7 @@ F_TRAINER_FEMALE | }, }, #line 1261 - [TRAINER_RANDALL] = + [DIFFICULTY_NORMAL][TRAINER_RANDALL] = { #line 1262 .trainerName = _("RANDALL"), @@ -3014,7 +3014,7 @@ F_TRAINER_FEMALE | }, }, #line 1278 - [TRAINER_PARKER] = + [DIFFICULTY_NORMAL][TRAINER_PARKER] = { #line 1279 .trainerName = _("PARKER"), @@ -3054,7 +3054,7 @@ F_TRAINER_FEMALE | }, }, #line 1295 - [TRAINER_GEORGE] = + [DIFFICULTY_NORMAL][TRAINER_GEORGE] = { #line 1296 .trainerName = _("GEORGE"), @@ -3096,7 +3096,7 @@ F_TRAINER_FEMALE | }, }, #line 1312 - [TRAINER_BERKE] = + [DIFFICULTY_NORMAL][TRAINER_BERKE] = { #line 1313 .trainerName = _("BERKE"), @@ -3135,7 +3135,7 @@ F_TRAINER_FEMALE | }, }, #line 1328 - [TRAINER_BRAXTON] = + [DIFFICULTY_NORMAL][TRAINER_BRAXTON] = { #line 1329 .trainerName = _("BRAXTON"), @@ -3248,7 +3248,7 @@ F_TRAINER_FEMALE | }, }, #line 1378 - [TRAINER_VINCENT] = + [DIFFICULTY_NORMAL][TRAINER_VINCENT] = { #line 1379 .trainerName = _("VINCENT"), @@ -3304,7 +3304,7 @@ F_TRAINER_FEMALE | }, }, #line 1400 - [TRAINER_LEROY] = + [DIFFICULTY_NORMAL][TRAINER_LEROY] = { #line 1401 .trainerName = _("LEROY"), @@ -3349,7 +3349,7 @@ F_TRAINER_FEMALE | }, }, #line 1418 - [TRAINER_WILTON_1] = + [DIFFICULTY_NORMAL][TRAINER_WILTON_1] = { #line 1419 .trainerName = _("WILTON"), @@ -3405,7 +3405,7 @@ F_TRAINER_FEMALE | }, }, #line 1440 - [TRAINER_EDGAR] = + [DIFFICULTY_NORMAL][TRAINER_EDGAR] = { #line 1441 .trainerName = _("EDGAR"), @@ -3450,7 +3450,7 @@ F_TRAINER_FEMALE | }, }, #line 1458 - [TRAINER_ALBERT] = + [DIFFICULTY_NORMAL][TRAINER_ALBERT] = { #line 1459 .trainerName = _("ALBERT"), @@ -3495,7 +3495,7 @@ F_TRAINER_FEMALE | }, }, #line 1476 - [TRAINER_SAMUEL] = + [DIFFICULTY_NORMAL][TRAINER_SAMUEL] = { #line 1477 .trainerName = _("SAMUEL"), @@ -3551,7 +3551,7 @@ F_TRAINER_FEMALE | }, }, #line 1498 - [TRAINER_VITO] = + [DIFFICULTY_NORMAL][TRAINER_VITO] = { #line 1499 .trainerName = _("VITO"), @@ -3618,7 +3618,7 @@ F_TRAINER_FEMALE | }, }, #line 1524 - [TRAINER_OWEN] = + [DIFFICULTY_NORMAL][TRAINER_OWEN] = { #line 1525 .trainerName = _("OWEN"), @@ -3674,7 +3674,7 @@ F_TRAINER_FEMALE | }, }, #line 1546 - [TRAINER_WILTON_2] = + [DIFFICULTY_NORMAL][TRAINER_WILTON_2] = { #line 1547 .trainerName = _("WILTON"), @@ -3730,7 +3730,7 @@ F_TRAINER_FEMALE | }, }, #line 1568 - [TRAINER_WILTON_3] = + [DIFFICULTY_NORMAL][TRAINER_WILTON_3] = { #line 1569 .trainerName = _("WILTON"), @@ -3786,7 +3786,7 @@ F_TRAINER_FEMALE | }, }, #line 1590 - [TRAINER_WILTON_4] = + [DIFFICULTY_NORMAL][TRAINER_WILTON_4] = { #line 1591 .trainerName = _("WILTON"), @@ -3842,7 +3842,7 @@ F_TRAINER_FEMALE | }, }, #line 1612 - [TRAINER_WILTON_5] = + [DIFFICULTY_NORMAL][TRAINER_WILTON_5] = { #line 1613 .trainerName = _("WILTON"), @@ -3898,7 +3898,7 @@ F_TRAINER_FEMALE | }, }, #line 1634 - [TRAINER_WARREN] = + [DIFFICULTY_NORMAL][TRAINER_WARREN] = { #line 1635 .trainerName = _("WARREN"), @@ -3943,7 +3943,7 @@ F_TRAINER_FEMALE | }, }, #line 1652 - [TRAINER_MARY] = + [DIFFICULTY_NORMAL][TRAINER_MARY] = { #line 1653 .trainerName = _("MARY"), @@ -3984,7 +3984,7 @@ F_TRAINER_FEMALE | }, }, #line 1668 - [TRAINER_ALEXIA] = + [DIFFICULTY_NORMAL][TRAINER_ALEXIA] = { #line 1669 .trainerName = _("ALEXIA"), @@ -4026,7 +4026,7 @@ F_TRAINER_FEMALE | }, }, #line 1685 - [TRAINER_JODY] = + [DIFFICULTY_NORMAL][TRAINER_JODY] = { #line 1686 .trainerName = _("JODY"), @@ -4067,7 +4067,7 @@ F_TRAINER_FEMALE | }, }, #line 1701 - [TRAINER_WENDY] = + [DIFFICULTY_NORMAL][TRAINER_WENDY] = { #line 1702 .trainerName = _("WENDY"), @@ -4146,7 +4146,7 @@ F_TRAINER_FEMALE | }, }, #line 1735 - [TRAINER_KEIRA] = + [DIFFICULTY_NORMAL][TRAINER_KEIRA] = { #line 1736 .trainerName = _("KEIRA"), @@ -4193,7 +4193,7 @@ F_TRAINER_FEMALE | }, }, #line 1753 - [TRAINER_BROOKE_1] = + [DIFFICULTY_NORMAL][TRAINER_BROOKE_1] = { #line 1754 .trainerName = _("BROOKE"), @@ -4251,7 +4251,7 @@ F_TRAINER_FEMALE | }, }, #line 1775 - [TRAINER_JENNIFER] = + [DIFFICULTY_NORMAL][TRAINER_JENNIFER] = { #line 1776 .trainerName = _("JENNIFER"), @@ -4287,7 +4287,7 @@ F_TRAINER_FEMALE | }, }, #line 1789 - [TRAINER_HOPE] = + [DIFFICULTY_NORMAL][TRAINER_HOPE] = { #line 1790 .trainerName = _("HOPE"), @@ -4323,7 +4323,7 @@ F_TRAINER_FEMALE | }, }, #line 1803 - [TRAINER_SHANNON] = + [DIFFICULTY_NORMAL][TRAINER_SHANNON] = { #line 1804 .trainerName = _("SHANNON"), @@ -4359,7 +4359,7 @@ F_TRAINER_FEMALE | }, }, #line 1817 - [TRAINER_MICHELLE] = + [DIFFICULTY_NORMAL][TRAINER_MICHELLE] = { #line 1818 .trainerName = _("MICHELLE"), @@ -4417,7 +4417,7 @@ F_TRAINER_FEMALE | }, }, #line 1839 - [TRAINER_CAROLINE] = + [DIFFICULTY_NORMAL][TRAINER_CAROLINE] = { #line 1840 .trainerName = _("CAROLINE"), @@ -4464,7 +4464,7 @@ F_TRAINER_FEMALE | }, }, #line 1857 - [TRAINER_JULIE] = + [DIFFICULTY_NORMAL][TRAINER_JULIE] = { #line 1858 .trainerName = _("JULIE"), @@ -4522,7 +4522,7 @@ F_TRAINER_FEMALE | }, }, #line 1879 - [TRAINER_BROOKE_2] = + [DIFFICULTY_NORMAL][TRAINER_BROOKE_2] = { #line 1880 .trainerName = _("BROOKE"), @@ -4580,7 +4580,7 @@ F_TRAINER_FEMALE | }, }, #line 1901 - [TRAINER_BROOKE_3] = + [DIFFICULTY_NORMAL][TRAINER_BROOKE_3] = { #line 1902 .trainerName = _("BROOKE"), @@ -4638,7 +4638,7 @@ F_TRAINER_FEMALE | }, }, #line 1923 - [TRAINER_BROOKE_4] = + [DIFFICULTY_NORMAL][TRAINER_BROOKE_4] = { #line 1924 .trainerName = _("BROOKE"), @@ -4696,7 +4696,7 @@ F_TRAINER_FEMALE | }, }, #line 1945 - [TRAINER_BROOKE_5] = + [DIFFICULTY_NORMAL][TRAINER_BROOKE_5] = { #line 1946 .trainerName = _("BROOKE"), @@ -4754,7 +4754,7 @@ F_TRAINER_FEMALE | }, }, #line 1967 - [TRAINER_PATRICIA] = + [DIFFICULTY_NORMAL][TRAINER_PATRICIA] = { #line 1968 .trainerName = _("PATRICIA"), @@ -4799,7 +4799,7 @@ F_TRAINER_FEMALE | }, }, #line 1984 - [TRAINER_KINDRA] = + [DIFFICULTY_NORMAL][TRAINER_KINDRA] = { #line 1985 .trainerName = _("KINDRA"), @@ -4844,7 +4844,7 @@ F_TRAINER_FEMALE | }, }, #line 2001 - [TRAINER_TAMMY] = + [DIFFICULTY_NORMAL][TRAINER_TAMMY] = { #line 2002 .trainerName = _("TAMMY"), @@ -4889,7 +4889,7 @@ F_TRAINER_FEMALE | }, }, #line 2018 - [TRAINER_VALERIE_1] = + [DIFFICULTY_NORMAL][TRAINER_VALERIE_1] = { #line 2019 .trainerName = _("VALERIE"), @@ -4923,7 +4923,7 @@ F_TRAINER_FEMALE | }, }, #line 2031 - [TRAINER_TASHA] = + [DIFFICULTY_NORMAL][TRAINER_TASHA] = { #line 2032 .trainerName = _("TASHA"), @@ -4957,7 +4957,7 @@ F_TRAINER_FEMALE | }, }, #line 2044 - [TRAINER_VALERIE_2] = + [DIFFICULTY_NORMAL][TRAINER_VALERIE_2] = { #line 2045 .trainerName = _("VALERIE"), @@ -5002,7 +5002,7 @@ F_TRAINER_FEMALE | }, }, #line 2061 - [TRAINER_VALERIE_3] = + [DIFFICULTY_NORMAL][TRAINER_VALERIE_3] = { #line 2062 .trainerName = _("VALERIE"), @@ -5047,7 +5047,7 @@ F_TRAINER_FEMALE | }, }, #line 2078 - [TRAINER_VALERIE_4] = + [DIFFICULTY_NORMAL][TRAINER_VALERIE_4] = { #line 2079 .trainerName = _("VALERIE"), @@ -5092,7 +5092,7 @@ F_TRAINER_FEMALE | }, }, #line 2095 - [TRAINER_VALERIE_5] = + [DIFFICULTY_NORMAL][TRAINER_VALERIE_5] = { #line 2096 .trainerName = _("VALERIE"), @@ -5148,7 +5148,7 @@ F_TRAINER_FEMALE | }, }, #line 2116 - [TRAINER_CINDY_1] = + [DIFFICULTY_NORMAL][TRAINER_CINDY_1] = { #line 2117 .trainerName = _("CINDY"), @@ -5186,7 +5186,7 @@ F_TRAINER_FEMALE | }, }, #line 2130 - [TRAINER_DAPHNE] = + [DIFFICULTY_NORMAL][TRAINER_DAPHNE] = { #line 2131 .trainerName = _("DAPHNE"), @@ -5251,7 +5251,7 @@ F_TRAINER_FEMALE | }, }, #line 2156 - [TRAINER_GRUNT_SPACE_CENTER_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_2] = { #line 2157 .trainerName = _("GRUNT"), @@ -5305,7 +5305,7 @@ F_TRAINER_FEMALE | }, }, #line 2177 - [TRAINER_CINDY_2] = + [DIFFICULTY_NORMAL][TRAINER_CINDY_2] = { #line 2178 .trainerName = _("CINDY"), @@ -5348,7 +5348,7 @@ F_TRAINER_FEMALE | }, }, #line 2193 - [TRAINER_BRIANNA] = + [DIFFICULTY_NORMAL][TRAINER_BRIANNA] = { #line 2194 .trainerName = _("BRIANNA"), @@ -5386,7 +5386,7 @@ F_TRAINER_FEMALE | }, }, #line 2207 - [TRAINER_NAOMI] = + [DIFFICULTY_NORMAL][TRAINER_NAOMI] = { #line 2208 .trainerName = _("NAOMI"), @@ -5424,7 +5424,7 @@ F_TRAINER_FEMALE | }, }, #line 2221 - [TRAINER_CINDY_3] = + [DIFFICULTY_NORMAL][TRAINER_CINDY_3] = { #line 2222 .trainerName = _("CINDY"), @@ -5462,7 +5462,7 @@ F_TRAINER_FEMALE | }, }, #line 2235 - [TRAINER_CINDY_4] = + [DIFFICULTY_NORMAL][TRAINER_CINDY_4] = { #line 2236 .trainerName = _("CINDY"), @@ -5500,7 +5500,7 @@ F_TRAINER_FEMALE | }, }, #line 2249 - [TRAINER_CINDY_5] = + [DIFFICULTY_NORMAL][TRAINER_CINDY_5] = { #line 2250 .trainerName = _("CINDY"), @@ -5538,7 +5538,7 @@ F_TRAINER_FEMALE | }, }, #line 2263 - [TRAINER_CINDY_6] = + [DIFFICULTY_NORMAL][TRAINER_CINDY_6] = { #line 2264 .trainerName = _("CINDY"), @@ -5583,7 +5583,7 @@ F_TRAINER_FEMALE | }, }, #line 2281 - [TRAINER_MELISSA] = + [DIFFICULTY_NORMAL][TRAINER_MELISSA] = { #line 2282 .trainerName = _("MELISSA"), @@ -5617,7 +5617,7 @@ F_TRAINER_FEMALE | }, }, #line 2294 - [TRAINER_SHEILA] = + [DIFFICULTY_NORMAL][TRAINER_SHEILA] = { #line 2295 .trainerName = _("SHEILA"), @@ -5651,7 +5651,7 @@ F_TRAINER_FEMALE | }, }, #line 2307 - [TRAINER_SHIRLEY] = + [DIFFICULTY_NORMAL][TRAINER_SHIRLEY] = { #line 2308 .trainerName = _("SHIRLEY"), @@ -5685,7 +5685,7 @@ F_TRAINER_FEMALE | }, }, #line 2320 - [TRAINER_JESSICA_1] = + [DIFFICULTY_NORMAL][TRAINER_JESSICA_1] = { #line 2321 .trainerName = _("JESSICA"), @@ -5744,7 +5744,7 @@ F_TRAINER_FEMALE | }, }, #line 2345 - [TRAINER_CONNIE] = + [DIFFICULTY_NORMAL][TRAINER_CONNIE] = { #line 2346 .trainerName = _("CONNIE"), @@ -5778,7 +5778,7 @@ F_TRAINER_FEMALE | }, }, #line 2358 - [TRAINER_BRIDGET] = + [DIFFICULTY_NORMAL][TRAINER_BRIDGET] = { #line 2359 .trainerName = _("BRIDGET"), @@ -5812,7 +5812,7 @@ F_TRAINER_FEMALE | }, }, #line 2371 - [TRAINER_OLIVIA] = + [DIFFICULTY_NORMAL][TRAINER_OLIVIA] = { #line 2372 .trainerName = _("OLIVIA"), @@ -5888,7 +5888,7 @@ F_TRAINER_FEMALE | }, }, #line 2403 - [TRAINER_TIFFANY] = + [DIFFICULTY_NORMAL][TRAINER_TIFFANY] = { #line 2404 .trainerName = _("TIFFANY"), @@ -5933,7 +5933,7 @@ F_TRAINER_FEMALE | }, }, #line 2420 - [TRAINER_JESSICA_2] = + [DIFFICULTY_NORMAL][TRAINER_JESSICA_2] = { #line 2421 .trainerName = _("JESSICA"), @@ -5992,7 +5992,7 @@ F_TRAINER_FEMALE | }, }, #line 2445 - [TRAINER_JESSICA_3] = + [DIFFICULTY_NORMAL][TRAINER_JESSICA_3] = { #line 2446 .trainerName = _("JESSICA"), @@ -6051,7 +6051,7 @@ F_TRAINER_FEMALE | }, }, #line 2470 - [TRAINER_JESSICA_4] = + [DIFFICULTY_NORMAL][TRAINER_JESSICA_4] = { #line 2471 .trainerName = _("JESSICA"), @@ -6110,7 +6110,7 @@ F_TRAINER_FEMALE | }, }, #line 2495 - [TRAINER_JESSICA_5] = + [DIFFICULTY_NORMAL][TRAINER_JESSICA_5] = { #line 2496 .trainerName = _("JESSICA"), @@ -6169,7 +6169,7 @@ F_TRAINER_FEMALE | }, }, #line 2520 - [TRAINER_WINSTON_1] = + [DIFFICULTY_NORMAL][TRAINER_WINSTON_1] = { #line 2521 .trainerName = _("WINSTON"), @@ -6205,7 +6205,7 @@ F_TRAINER_FEMALE | }, }, #line 2534 - [TRAINER_MOLLIE] = + [DIFFICULTY_NORMAL][TRAINER_MOLLIE] = { #line 2535 .trainerName = _("MOLLIE"), @@ -6250,7 +6250,7 @@ F_TRAINER_FEMALE | }, }, #line 2551 - [TRAINER_GARRET] = + [DIFFICULTY_NORMAL][TRAINER_GARRET] = { #line 2552 .trainerName = _("GARRET"), @@ -6286,7 +6286,7 @@ F_TRAINER_FEMALE | }, }, #line 2565 - [TRAINER_WINSTON_2] = + [DIFFICULTY_NORMAL][TRAINER_WINSTON_2] = { #line 2566 .trainerName = _("WINSTON"), @@ -6322,7 +6322,7 @@ F_TRAINER_FEMALE | }, }, #line 2579 - [TRAINER_WINSTON_3] = + [DIFFICULTY_NORMAL][TRAINER_WINSTON_3] = { #line 2580 .trainerName = _("WINSTON"), @@ -6358,7 +6358,7 @@ F_TRAINER_FEMALE | }, }, #line 2593 - [TRAINER_WINSTON_4] = + [DIFFICULTY_NORMAL][TRAINER_WINSTON_4] = { #line 2594 .trainerName = _("WINSTON"), @@ -6394,7 +6394,7 @@ F_TRAINER_FEMALE | }, }, #line 2607 - [TRAINER_WINSTON_5] = + [DIFFICULTY_NORMAL][TRAINER_WINSTON_5] = { #line 2608 .trainerName = _("WINSTON"), @@ -6437,7 +6437,7 @@ F_TRAINER_FEMALE | }, }, #line 2625 - [TRAINER_STEVE_1] = + [DIFFICULTY_NORMAL][TRAINER_STEVE_1] = { #line 2626 .trainerName = _("STEVE"), @@ -6469,7 +6469,7 @@ F_TRAINER_FEMALE | }, }, #line 2638 - [TRAINER_THALIA_1] = + [DIFFICULTY_NORMAL][TRAINER_THALIA_1] = { #line 2639 .trainerName = _("THALIA"), @@ -6514,7 +6514,7 @@ F_TRAINER_FEMALE | }, }, #line 2655 - [TRAINER_MARK] = + [DIFFICULTY_NORMAL][TRAINER_MARK] = { #line 2656 .trainerName = _("MARK"), @@ -6546,7 +6546,7 @@ F_TRAINER_FEMALE | }, }, #line 2668 - [TRAINER_GRUNT_MT_CHIMNEY_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MT_CHIMNEY_1] = { #line 2669 .trainerName = _("GRUNT"), @@ -6580,7 +6580,7 @@ F_TRAINER_FEMALE | }, }, #line 2681 - [TRAINER_STEVE_2] = + [DIFFICULTY_NORMAL][TRAINER_STEVE_2] = { #line 2682 .trainerName = _("STEVE"), @@ -6612,7 +6612,7 @@ F_TRAINER_FEMALE | }, }, #line 2694 - [TRAINER_STEVE_3] = + [DIFFICULTY_NORMAL][TRAINER_STEVE_3] = { #line 2695 .trainerName = _("STEVE"), @@ -6655,7 +6655,7 @@ F_TRAINER_FEMALE | }, }, #line 2711 - [TRAINER_STEVE_4] = + [DIFFICULTY_NORMAL][TRAINER_STEVE_4] = { #line 2712 .trainerName = _("STEVE"), @@ -6698,7 +6698,7 @@ F_TRAINER_FEMALE | }, }, #line 2728 - [TRAINER_STEVE_5] = + [DIFFICULTY_NORMAL][TRAINER_STEVE_5] = { #line 2729 .trainerName = _("STEVE"), @@ -6741,7 +6741,7 @@ F_TRAINER_FEMALE | }, }, #line 2745 - [TRAINER_LUIS] = + [DIFFICULTY_NORMAL][TRAINER_LUIS] = { #line 2746 .trainerName = _("LUIS"), @@ -6773,7 +6773,7 @@ F_TRAINER_FEMALE | }, }, #line 2758 - [TRAINER_DOMINIK] = + [DIFFICULTY_NORMAL][TRAINER_DOMINIK] = { #line 2759 .trainerName = _("DOMINIK"), @@ -6805,7 +6805,7 @@ F_TRAINER_FEMALE | }, }, #line 2771 - [TRAINER_DOUGLAS] = + [DIFFICULTY_NORMAL][TRAINER_DOUGLAS] = { #line 2772 .trainerName = _("DOUGLAS"), @@ -6848,7 +6848,7 @@ F_TRAINER_FEMALE | }, }, #line 2788 - [TRAINER_DARRIN] = + [DIFFICULTY_NORMAL][TRAINER_DARRIN] = { #line 2789 .trainerName = _("DARRIN"), @@ -6902,7 +6902,7 @@ F_TRAINER_FEMALE | }, }, #line 2809 - [TRAINER_TONY_1] = + [DIFFICULTY_NORMAL][TRAINER_TONY_1] = { #line 2810 .trainerName = _("TONY"), @@ -6934,7 +6934,7 @@ F_TRAINER_FEMALE | }, }, #line 2822 - [TRAINER_JEROME] = + [DIFFICULTY_NORMAL][TRAINER_JEROME] = { #line 2823 .trainerName = _("JEROME"), @@ -6966,7 +6966,7 @@ F_TRAINER_FEMALE | }, }, #line 2835 - [TRAINER_MATTHEW] = + [DIFFICULTY_NORMAL][TRAINER_MATTHEW] = { #line 2836 .trainerName = _("MATTHEW"), @@ -6998,7 +6998,7 @@ F_TRAINER_FEMALE | }, }, #line 2848 - [TRAINER_DAVID] = + [DIFFICULTY_NORMAL][TRAINER_DAVID] = { #line 2849 .trainerName = _("DAVID"), @@ -7041,7 +7041,7 @@ F_TRAINER_FEMALE | }, }, #line 2865 - [TRAINER_SPENCER] = + [DIFFICULTY_NORMAL][TRAINER_SPENCER] = { #line 2866 .trainerName = _("SPENCER"), @@ -7084,7 +7084,7 @@ F_TRAINER_FEMALE | }, }, #line 2882 - [TRAINER_ROLAND] = + [DIFFICULTY_NORMAL][TRAINER_ROLAND] = { #line 2883 .trainerName = _("ROLAND"), @@ -7116,7 +7116,7 @@ F_TRAINER_FEMALE | }, }, #line 2895 - [TRAINER_NOLEN] = + [DIFFICULTY_NORMAL][TRAINER_NOLEN] = { #line 2896 .trainerName = _("NOLEN"), @@ -7148,7 +7148,7 @@ F_TRAINER_FEMALE | }, }, #line 2908 - [TRAINER_STAN] = + [DIFFICULTY_NORMAL][TRAINER_STAN] = { #line 2909 .trainerName = _("STAN"), @@ -7180,7 +7180,7 @@ F_TRAINER_FEMALE | }, }, #line 2921 - [TRAINER_BARRY] = + [DIFFICULTY_NORMAL][TRAINER_BARRY] = { #line 2922 .trainerName = _("BARRY"), @@ -7212,7 +7212,7 @@ F_TRAINER_FEMALE | }, }, #line 2934 - [TRAINER_DEAN] = + [DIFFICULTY_NORMAL][TRAINER_DEAN] = { #line 2935 .trainerName = _("DEAN"), @@ -7266,7 +7266,7 @@ F_TRAINER_FEMALE | }, }, #line 2955 - [TRAINER_RODNEY] = + [DIFFICULTY_NORMAL][TRAINER_RODNEY] = { #line 2956 .trainerName = _("RODNEY"), @@ -7298,7 +7298,7 @@ F_TRAINER_FEMALE | }, }, #line 2968 - [TRAINER_RICHARD] = + [DIFFICULTY_NORMAL][TRAINER_RICHARD] = { #line 2969 .trainerName = _("RICHARD"), @@ -7330,7 +7330,7 @@ F_TRAINER_FEMALE | }, }, #line 2981 - [TRAINER_HERMAN] = + [DIFFICULTY_NORMAL][TRAINER_HERMAN] = { #line 2982 .trainerName = _("HERMAN"), @@ -7373,7 +7373,7 @@ F_TRAINER_FEMALE | }, }, #line 2998 - [TRAINER_SANTIAGO] = + [DIFFICULTY_NORMAL][TRAINER_SANTIAGO] = { #line 2999 .trainerName = _("SANTIAGO"), @@ -7416,7 +7416,7 @@ F_TRAINER_FEMALE | }, }, #line 3015 - [TRAINER_GILBERT] = + [DIFFICULTY_NORMAL][TRAINER_GILBERT] = { #line 3016 .trainerName = _("GILBERT"), @@ -7448,7 +7448,7 @@ F_TRAINER_FEMALE | }, }, #line 3028 - [TRAINER_FRANKLIN] = + [DIFFICULTY_NORMAL][TRAINER_FRANKLIN] = { #line 3029 .trainerName = _("FRANKLIN"), @@ -7480,7 +7480,7 @@ F_TRAINER_FEMALE | }, }, #line 3041 - [TRAINER_KEVIN] = + [DIFFICULTY_NORMAL][TRAINER_KEVIN] = { #line 3042 .trainerName = _("KEVIN"), @@ -7512,7 +7512,7 @@ F_TRAINER_FEMALE | }, }, #line 3054 - [TRAINER_JACK] = + [DIFFICULTY_NORMAL][TRAINER_JACK] = { #line 3055 .trainerName = _("JACK"), @@ -7544,7 +7544,7 @@ F_TRAINER_FEMALE | }, }, #line 3067 - [TRAINER_DUDLEY] = + [DIFFICULTY_NORMAL][TRAINER_DUDLEY] = { #line 3068 .trainerName = _("DUDLEY"), @@ -7598,7 +7598,7 @@ F_TRAINER_FEMALE | }, }, #line 3088 - [TRAINER_CHAD] = + [DIFFICULTY_NORMAL][TRAINER_CHAD] = { #line 3089 .trainerName = _("CHAD"), @@ -7641,7 +7641,7 @@ F_TRAINER_FEMALE | }, }, #line 3105 - [TRAINER_TONY_2] = + [DIFFICULTY_NORMAL][TRAINER_TONY_2] = { #line 3106 .trainerName = _("TONY"), @@ -7673,7 +7673,7 @@ F_TRAINER_FEMALE | }, }, #line 3118 - [TRAINER_TONY_3] = + [DIFFICULTY_NORMAL][TRAINER_TONY_3] = { #line 3119 .trainerName = _("TONY"), @@ -7705,7 +7705,7 @@ F_TRAINER_FEMALE | }, }, #line 3131 - [TRAINER_TONY_4] = + [DIFFICULTY_NORMAL][TRAINER_TONY_4] = { #line 3132 .trainerName = _("TONY"), @@ -7748,7 +7748,7 @@ F_TRAINER_FEMALE | }, }, #line 3148 - [TRAINER_TONY_5] = + [DIFFICULTY_NORMAL][TRAINER_TONY_5] = { #line 3149 .trainerName = _("TONY"), @@ -7791,7 +7791,7 @@ F_TRAINER_FEMALE | }, }, #line 3165 - [TRAINER_TAKAO] = + [DIFFICULTY_NORMAL][TRAINER_TAKAO] = { #line 3166 .trainerName = _("TAKAO"), @@ -7823,7 +7823,7 @@ F_TRAINER_FEMALE | }, }, #line 3178 - [TRAINER_HITOSHI] = + [DIFFICULTY_NORMAL][TRAINER_HITOSHI] = { #line 3179 .trainerName = _("HITOSHI"), @@ -7866,7 +7866,7 @@ F_TRAINER_FEMALE | }, }, #line 3195 - [TRAINER_KIYO] = + [DIFFICULTY_NORMAL][TRAINER_KIYO] = { #line 3196 .trainerName = _("KIYO"), @@ -7898,7 +7898,7 @@ F_TRAINER_FEMALE | }, }, #line 3208 - [TRAINER_KOICHI] = + [DIFFICULTY_NORMAL][TRAINER_KOICHI] = { #line 3209 .trainerName = _("KOICHI"), @@ -7941,7 +7941,7 @@ F_TRAINER_FEMALE | }, }, #line 3225 - [TRAINER_NOB_1] = + [DIFFICULTY_NORMAL][TRAINER_NOB_1] = { #line 3226 .trainerName = _("NOB"), @@ -7973,7 +7973,7 @@ F_TRAINER_FEMALE | }, }, #line 3238 - [TRAINER_NOB_2] = + [DIFFICULTY_NORMAL][TRAINER_NOB_2] = { #line 3239 .trainerName = _("NOB"), @@ -8005,7 +8005,7 @@ F_TRAINER_FEMALE | }, }, #line 3251 - [TRAINER_NOB_3] = + [DIFFICULTY_NORMAL][TRAINER_NOB_3] = { #line 3252 .trainerName = _("NOB"), @@ -8048,7 +8048,7 @@ F_TRAINER_FEMALE | }, }, #line 3268 - [TRAINER_NOB_4] = + [DIFFICULTY_NORMAL][TRAINER_NOB_4] = { #line 3269 .trainerName = _("NOB"), @@ -8102,7 +8102,7 @@ F_TRAINER_FEMALE | }, }, #line 3289 - [TRAINER_NOB_5] = + [DIFFICULTY_NORMAL][TRAINER_NOB_5] = { #line 3290 .trainerName = _("NOB"), @@ -8169,7 +8169,7 @@ F_TRAINER_FEMALE | }, }, #line 3314 - [TRAINER_YUJI] = + [DIFFICULTY_NORMAL][TRAINER_YUJI] = { #line 3315 .trainerName = _("YUJI"), @@ -8212,7 +8212,7 @@ F_TRAINER_FEMALE | }, }, #line 3331 - [TRAINER_DAISUKE] = + [DIFFICULTY_NORMAL][TRAINER_DAISUKE] = { #line 3332 .trainerName = _("DAISUKE"), @@ -8244,7 +8244,7 @@ F_TRAINER_FEMALE | }, }, #line 3344 - [TRAINER_ATSUSHI] = + [DIFFICULTY_NORMAL][TRAINER_ATSUSHI] = { #line 3345 .trainerName = _("ATSUSHI"), @@ -8276,7 +8276,7 @@ F_TRAINER_FEMALE | }, }, #line 3357 - [TRAINER_KIRK] = + [DIFFICULTY_NORMAL][TRAINER_KIRK] = { #line 3358 .trainerName = _("KIRK"), @@ -8332,7 +8332,7 @@ F_TRAINER_FEMALE | }, }, #line 3381 - [TRAINER_GRUNT_AQUA_HIDEOUT_7] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_7] = { #line 3382 .trainerName = _("GRUNT"), @@ -8377,7 +8377,7 @@ F_TRAINER_FEMALE | }, }, #line 3398 - [TRAINER_GRUNT_AQUA_HIDEOUT_8] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_AQUA_HIDEOUT_8] = { #line 3399 .trainerName = _("GRUNT"), @@ -8409,7 +8409,7 @@ F_TRAINER_FEMALE | }, }, #line 3411 - [TRAINER_SHAWN] = + [DIFFICULTY_NORMAL][TRAINER_SHAWN] = { #line 3412 .trainerName = _("SHAWN"), @@ -8452,7 +8452,7 @@ F_TRAINER_FEMALE | }, }, #line 3428 - [TRAINER_FERNANDO_1] = + [DIFFICULTY_NORMAL][TRAINER_FERNANDO_1] = { #line 3429 .trainerName = _("FERNANDO"), @@ -8495,7 +8495,7 @@ F_TRAINER_FEMALE | }, }, #line 3445 - [TRAINER_DALTON_1] = + [DIFFICULTY_NORMAL][TRAINER_DALTON_1] = { #line 3446 .trainerName = _("DALTON"), @@ -8538,7 +8538,7 @@ F_TRAINER_FEMALE | }, }, #line 3462 - [TRAINER_DALTON_2] = + [DIFFICULTY_NORMAL][TRAINER_DALTON_2] = { #line 3463 .trainerName = _("DALTON"), @@ -8592,7 +8592,7 @@ F_TRAINER_FEMALE | }, }, #line 3483 - [TRAINER_DALTON_3] = + [DIFFICULTY_NORMAL][TRAINER_DALTON_3] = { #line 3484 .trainerName = _("DALTON"), @@ -8646,7 +8646,7 @@ F_TRAINER_FEMALE | }, }, #line 3504 - [TRAINER_DALTON_4] = + [DIFFICULTY_NORMAL][TRAINER_DALTON_4] = { #line 3505 .trainerName = _("DALTON"), @@ -8700,7 +8700,7 @@ F_TRAINER_FEMALE | }, }, #line 3525 - [TRAINER_DALTON_5] = + [DIFFICULTY_NORMAL][TRAINER_DALTON_5] = { #line 3526 .trainerName = _("DALTON"), @@ -8754,7 +8754,7 @@ F_TRAINER_FEMALE | }, }, #line 3546 - [TRAINER_COLE] = + [DIFFICULTY_NORMAL][TRAINER_COLE] = { #line 3547 .trainerName = _("COLE"), @@ -8786,7 +8786,7 @@ F_TRAINER_FEMALE | }, }, #line 3559 - [TRAINER_JEFF] = + [DIFFICULTY_NORMAL][TRAINER_JEFF] = { #line 3560 .trainerName = _("JEFF"), @@ -8829,7 +8829,7 @@ F_TRAINER_FEMALE | }, }, #line 3576 - [TRAINER_AXLE] = + [DIFFICULTY_NORMAL][TRAINER_AXLE] = { #line 3577 .trainerName = _("AXLE"), @@ -8861,7 +8861,7 @@ F_TRAINER_FEMALE | }, }, #line 3589 - [TRAINER_JACE] = + [DIFFICULTY_NORMAL][TRAINER_JACE] = { #line 3590 .trainerName = _("JACE"), @@ -8893,7 +8893,7 @@ F_TRAINER_FEMALE | }, }, #line 3602 - [TRAINER_KEEGAN] = + [DIFFICULTY_NORMAL][TRAINER_KEEGAN] = { #line 3603 .trainerName = _("KEEGAN"), @@ -8925,7 +8925,7 @@ F_TRAINER_FEMALE | }, }, #line 3615 - [TRAINER_BERNIE_1] = + [DIFFICULTY_NORMAL][TRAINER_BERNIE_1] = { #line 3616 .trainerName = _("BERNIE"), @@ -8968,7 +8968,7 @@ F_TRAINER_FEMALE | }, }, #line 3632 - [TRAINER_BERNIE_2] = + [DIFFICULTY_NORMAL][TRAINER_BERNIE_2] = { #line 3633 .trainerName = _("BERNIE"), @@ -9011,7 +9011,7 @@ F_TRAINER_FEMALE | }, }, #line 3649 - [TRAINER_BERNIE_3] = + [DIFFICULTY_NORMAL][TRAINER_BERNIE_3] = { #line 3650 .trainerName = _("BERNIE"), @@ -9054,7 +9054,7 @@ F_TRAINER_FEMALE | }, }, #line 3666 - [TRAINER_BERNIE_4] = + [DIFFICULTY_NORMAL][TRAINER_BERNIE_4] = { #line 3667 .trainerName = _("BERNIE"), @@ -9097,7 +9097,7 @@ F_TRAINER_FEMALE | }, }, #line 3683 - [TRAINER_BERNIE_5] = + [DIFFICULTY_NORMAL][TRAINER_BERNIE_5] = { #line 3684 .trainerName = _("BERNIE"), @@ -9140,7 +9140,7 @@ F_TRAINER_FEMALE | }, }, #line 3700 - [TRAINER_DREW] = + [DIFFICULTY_NORMAL][TRAINER_DREW] = { #line 3701 .trainerName = _("DREW"), @@ -9179,7 +9179,7 @@ F_TRAINER_FEMALE | }, }, #line 3717 - [TRAINER_BEAU] = + [DIFFICULTY_NORMAL][TRAINER_BEAU] = { #line 3718 .trainerName = _("BEAU"), @@ -9254,7 +9254,7 @@ F_TRAINER_FEMALE | }, }, #line 3750 - [TRAINER_LARRY] = + [DIFFICULTY_NORMAL][TRAINER_LARRY] = { #line 3751 .trainerName = _("LARRY"), @@ -9286,7 +9286,7 @@ F_TRAINER_FEMALE | }, }, #line 3763 - [TRAINER_SHANE] = + [DIFFICULTY_NORMAL][TRAINER_SHANE] = { #line 3764 .trainerName = _("SHANE"), @@ -9329,7 +9329,7 @@ F_TRAINER_FEMALE | }, }, #line 3780 - [TRAINER_JUSTIN] = + [DIFFICULTY_NORMAL][TRAINER_JUSTIN] = { #line 3781 .trainerName = _("JUSTIN"), @@ -9361,7 +9361,7 @@ F_TRAINER_FEMALE | }, }, #line 3793 - [TRAINER_ETHAN_1] = + [DIFFICULTY_NORMAL][TRAINER_ETHAN_1] = { #line 3794 .trainerName = _("ETHAN"), @@ -9404,7 +9404,7 @@ F_TRAINER_FEMALE | }, }, #line 3810 - [TRAINER_AUTUMN] = + [DIFFICULTY_NORMAL][TRAINER_AUTUMN] = { #line 3811 .trainerName = _("AUTUMN"), @@ -9438,7 +9438,7 @@ F_TRAINER_FEMALE | }, }, #line 3823 - [TRAINER_TRAVIS] = + [DIFFICULTY_NORMAL][TRAINER_TRAVIS] = { #line 3824 .trainerName = _("TRAVIS"), @@ -9470,7 +9470,7 @@ F_TRAINER_FEMALE | }, }, #line 3836 - [TRAINER_ETHAN_2] = + [DIFFICULTY_NORMAL][TRAINER_ETHAN_2] = { #line 3837 .trainerName = _("ETHAN"), @@ -9513,7 +9513,7 @@ F_TRAINER_FEMALE | }, }, #line 3853 - [TRAINER_ETHAN_3] = + [DIFFICULTY_NORMAL][TRAINER_ETHAN_3] = { #line 3854 .trainerName = _("ETHAN"), @@ -9556,7 +9556,7 @@ F_TRAINER_FEMALE | }, }, #line 3870 - [TRAINER_ETHAN_4] = + [DIFFICULTY_NORMAL][TRAINER_ETHAN_4] = { #line 3871 .trainerName = _("ETHAN"), @@ -9610,7 +9610,7 @@ F_TRAINER_FEMALE | }, }, #line 3891 - [TRAINER_ETHAN_5] = + [DIFFICULTY_NORMAL][TRAINER_ETHAN_5] = { #line 3892 .trainerName = _("ETHAN"), @@ -9664,7 +9664,7 @@ F_TRAINER_FEMALE | }, }, #line 3912 - [TRAINER_BRENT] = + [DIFFICULTY_NORMAL][TRAINER_BRENT] = { #line 3913 .trainerName = _("BRENT"), @@ -9696,7 +9696,7 @@ F_TRAINER_FEMALE | }, }, #line 3925 - [TRAINER_DONALD] = + [DIFFICULTY_NORMAL][TRAINER_DONALD] = { #line 3926 .trainerName = _("DONALD"), @@ -9750,7 +9750,7 @@ F_TRAINER_FEMALE | }, }, #line 3946 - [TRAINER_TAYLOR] = + [DIFFICULTY_NORMAL][TRAINER_TAYLOR] = { #line 3947 .trainerName = _("TAYLOR"), @@ -9804,7 +9804,7 @@ F_TRAINER_FEMALE | }, }, #line 3967 - [TRAINER_JEFFREY_1] = + [DIFFICULTY_NORMAL][TRAINER_JEFFREY_1] = { #line 3968 .trainerName = _("JEFFREY"), @@ -9858,7 +9858,7 @@ F_TRAINER_FEMALE | }, }, #line 3988 - [TRAINER_DEREK] = + [DIFFICULTY_NORMAL][TRAINER_DEREK] = { #line 3989 .trainerName = _("DEREK"), @@ -9901,7 +9901,7 @@ F_TRAINER_FEMALE | }, }, #line 4005 - [TRAINER_JEFFREY_2] = + [DIFFICULTY_NORMAL][TRAINER_JEFFREY_2] = { #line 4006 .trainerName = _("JEFFREY"), @@ -9955,7 +9955,7 @@ F_TRAINER_FEMALE | }, }, #line 4026 - [TRAINER_JEFFREY_3] = + [DIFFICULTY_NORMAL][TRAINER_JEFFREY_3] = { #line 4027 .trainerName = _("JEFFREY"), @@ -10009,7 +10009,7 @@ F_TRAINER_FEMALE | }, }, #line 4047 - [TRAINER_JEFFREY_4] = + [DIFFICULTY_NORMAL][TRAINER_JEFFREY_4] = { #line 4048 .trainerName = _("JEFFREY"), @@ -10074,7 +10074,7 @@ F_TRAINER_FEMALE | }, }, #line 4072 - [TRAINER_JEFFREY_5] = + [DIFFICULTY_NORMAL][TRAINER_JEFFREY_5] = { #line 4073 .trainerName = _("JEFFREY"), @@ -10152,7 +10152,7 @@ F_TRAINER_FEMALE | }, }, #line 4101 - [TRAINER_EDWARD] = + [DIFFICULTY_NORMAL][TRAINER_EDWARD] = { #line 4102 .trainerName = _("EDWARD"), @@ -10188,7 +10188,7 @@ F_TRAINER_FEMALE | }, }, #line 4115 - [TRAINER_PRESTON] = + [DIFFICULTY_NORMAL][TRAINER_PRESTON] = { #line 4116 .trainerName = _("PRESTON"), @@ -10220,7 +10220,7 @@ F_TRAINER_FEMALE | }, }, #line 4128 - [TRAINER_VIRGIL] = + [DIFFICULTY_NORMAL][TRAINER_VIRGIL] = { #line 4129 .trainerName = _("VIRGIL"), @@ -10252,7 +10252,7 @@ F_TRAINER_FEMALE | }, }, #line 4141 - [TRAINER_BLAKE] = + [DIFFICULTY_NORMAL][TRAINER_BLAKE] = { #line 4142 .trainerName = _("BLAKE"), @@ -10284,7 +10284,7 @@ F_TRAINER_FEMALE | }, }, #line 4154 - [TRAINER_WILLIAM] = + [DIFFICULTY_NORMAL][TRAINER_WILLIAM] = { #line 4155 .trainerName = _("WILLIAM"), @@ -10338,7 +10338,7 @@ F_TRAINER_FEMALE | }, }, #line 4175 - [TRAINER_JOSHUA] = + [DIFFICULTY_NORMAL][TRAINER_JOSHUA] = { #line 4176 .trainerName = _("JOSHUA"), @@ -10381,7 +10381,7 @@ F_TRAINER_FEMALE | }, }, #line 4192 - [TRAINER_CAMERON_1] = + [DIFFICULTY_NORMAL][TRAINER_CAMERON_1] = { #line 4193 .trainerName = _("CAMERON"), @@ -10413,7 +10413,7 @@ F_TRAINER_FEMALE | }, }, #line 4205 - [TRAINER_CAMERON_2] = + [DIFFICULTY_NORMAL][TRAINER_CAMERON_2] = { #line 4206 .trainerName = _("CAMERON"), @@ -10456,7 +10456,7 @@ F_TRAINER_FEMALE | }, }, #line 4222 - [TRAINER_CAMERON_3] = + [DIFFICULTY_NORMAL][TRAINER_CAMERON_3] = { #line 4223 .trainerName = _("CAMERON"), @@ -10499,7 +10499,7 @@ F_TRAINER_FEMALE | }, }, #line 4239 - [TRAINER_CAMERON_4] = + [DIFFICULTY_NORMAL][TRAINER_CAMERON_4] = { #line 4240 .trainerName = _("CAMERON"), @@ -10542,7 +10542,7 @@ F_TRAINER_FEMALE | }, }, #line 4256 - [TRAINER_CAMERON_5] = + [DIFFICULTY_NORMAL][TRAINER_CAMERON_5] = { #line 4257 .trainerName = _("CAMERON"), @@ -10585,7 +10585,7 @@ F_TRAINER_FEMALE | }, }, #line 4273 - [TRAINER_JACLYN] = + [DIFFICULTY_NORMAL][TRAINER_JACLYN] = { #line 4274 .trainerName = _("JACLYN"), @@ -10623,7 +10623,7 @@ F_TRAINER_FEMALE | }, }, #line 4287 - [TRAINER_HANNAH] = + [DIFFICULTY_NORMAL][TRAINER_HANNAH] = { #line 4288 .trainerName = _("HANNAH"), @@ -10657,7 +10657,7 @@ F_TRAINER_FEMALE | }, }, #line 4300 - [TRAINER_SAMANTHA] = + [DIFFICULTY_NORMAL][TRAINER_SAMANTHA] = { #line 4301 .trainerName = _("SAMANTHA"), @@ -10691,7 +10691,7 @@ F_TRAINER_FEMALE | }, }, #line 4313 - [TRAINER_MAURA] = + [DIFFICULTY_NORMAL][TRAINER_MAURA] = { #line 4314 .trainerName = _("MAURA"), @@ -10725,7 +10725,7 @@ F_TRAINER_FEMALE | }, }, #line 4326 - [TRAINER_KAYLA] = + [DIFFICULTY_NORMAL][TRAINER_KAYLA] = { #line 4327 .trainerName = _("KAYLA"), @@ -10781,7 +10781,7 @@ F_TRAINER_FEMALE | }, }, #line 4347 - [TRAINER_ALEXIS] = + [DIFFICULTY_NORMAL][TRAINER_ALEXIS] = { #line 4348 .trainerName = _("ALEXIS"), @@ -10826,7 +10826,7 @@ F_TRAINER_FEMALE | }, }, #line 4364 - [TRAINER_JACKI_1] = + [DIFFICULTY_NORMAL][TRAINER_JACKI_1] = { #line 4365 .trainerName = _("JACKI"), @@ -10871,7 +10871,7 @@ F_TRAINER_FEMALE | }, }, #line 4381 - [TRAINER_JACKI_2] = + [DIFFICULTY_NORMAL][TRAINER_JACKI_2] = { #line 4382 .trainerName = _("JACKI"), @@ -10916,7 +10916,7 @@ F_TRAINER_FEMALE | }, }, #line 4398 - [TRAINER_JACKI_3] = + [DIFFICULTY_NORMAL][TRAINER_JACKI_3] = { #line 4399 .trainerName = _("JACKI"), @@ -10961,7 +10961,7 @@ F_TRAINER_FEMALE | }, }, #line 4415 - [TRAINER_JACKI_4] = + [DIFFICULTY_NORMAL][TRAINER_JACKI_4] = { #line 4416 .trainerName = _("JACKI"), @@ -11006,7 +11006,7 @@ F_TRAINER_FEMALE | }, }, #line 4432 - [TRAINER_JACKI_5] = + [DIFFICULTY_NORMAL][TRAINER_JACKI_5] = { #line 4433 .trainerName = _("JACKI"), @@ -11051,7 +11051,7 @@ F_TRAINER_FEMALE | }, }, #line 4449 - [TRAINER_WALTER_1] = + [DIFFICULTY_NORMAL][TRAINER_WALTER_1] = { #line 4450 .trainerName = _("WALTER"), @@ -11083,7 +11083,7 @@ F_TRAINER_FEMALE | }, }, #line 4462 - [TRAINER_MICAH] = + [DIFFICULTY_NORMAL][TRAINER_MICAH] = { #line 4463 .trainerName = _("MICAH"), @@ -11126,7 +11126,7 @@ F_TRAINER_FEMALE | }, }, #line 4479 - [TRAINER_THOMAS] = + [DIFFICULTY_NORMAL][TRAINER_THOMAS] = { #line 4480 .trainerName = _("THOMAS"), @@ -11158,7 +11158,7 @@ F_TRAINER_FEMALE | }, }, #line 4492 - [TRAINER_WALTER_2] = + [DIFFICULTY_NORMAL][TRAINER_WALTER_2] = { #line 4493 .trainerName = _("WALTER"), @@ -11190,7 +11190,7 @@ F_TRAINER_FEMALE | }, }, #line 4505 - [TRAINER_WALTER_3] = + [DIFFICULTY_NORMAL][TRAINER_WALTER_3] = { #line 4506 .trainerName = _("WALTER"), @@ -11247,7 +11247,7 @@ F_TRAINER_FEMALE | }, }, #line 4530 - [TRAINER_WALTER_4] = + [DIFFICULTY_NORMAL][TRAINER_WALTER_4] = { #line 4531 .trainerName = _("WALTER"), @@ -11303,7 +11303,7 @@ F_TRAINER_FEMALE | }, }, #line 4554 - [TRAINER_WALTER_5] = + [DIFFICULTY_NORMAL][TRAINER_WALTER_5] = { #line 4555 .trainerName = _("WALTER"), @@ -11378,7 +11378,7 @@ F_TRAINER_FEMALE | }, }, #line 4587 - [TRAINER_SIDNEY] = + [DIFFICULTY_NORMAL][TRAINER_SIDNEY] = { #line 4588 .trainerName = _("SIDNEY"), @@ -11396,7 +11396,6 @@ F_TRAINER_FEMALE | #line 4595 .aiFlags = AI_FLAG_BASIC_TRAINER | AI_FLAG_FORCE_SETUP_FIRST_TURN, #line 4596 - .mugshotEnabled = TRUE, .mugshotColor = MUGSHOT_COLOR_PURPLE, .partySize = 5, .party = (const struct TrainerMon[]) @@ -11496,7 +11495,7 @@ F_TRAINER_FEMALE | }, }, #line 4638 - [TRAINER_PHOEBE] = + [DIFFICULTY_NORMAL][TRAINER_PHOEBE] = { #line 4639 .trainerName = _("PHOEBE"), @@ -11516,7 +11515,6 @@ F_TRAINER_FEMALE | #line 4646 .aiFlags = AI_FLAG_BASIC_TRAINER, #line 4647 - .mugshotEnabled = TRUE, .mugshotColor = MUGSHOT_COLOR_GREEN, .partySize = 5, .party = (const struct TrainerMon[]) @@ -11616,7 +11614,7 @@ F_TRAINER_FEMALE | }, }, #line 4689 - [TRAINER_GLACIA] = + [DIFFICULTY_NORMAL][TRAINER_GLACIA] = { #line 4690 .trainerName = _("GLACIA"), @@ -11636,7 +11634,6 @@ F_TRAINER_FEMALE | #line 4697 .aiFlags = AI_FLAG_BASIC_TRAINER, #line 4698 - .mugshotEnabled = TRUE, .mugshotColor = MUGSHOT_COLOR_PINK, .partySize = 5, .party = (const struct TrainerMon[]) @@ -11736,7 +11733,7 @@ F_TRAINER_FEMALE | }, }, #line 4740 - [TRAINER_DRAKE] = + [DIFFICULTY_NORMAL][TRAINER_DRAKE] = { #line 4741 .trainerName = _("DRAKE"), @@ -11754,7 +11751,6 @@ F_TRAINER_FEMALE | #line 4748 .aiFlags = AI_FLAG_BASIC_TRAINER, #line 4749 - .mugshotEnabled = TRUE, .mugshotColor = MUGSHOT_COLOR_BLUE, .partySize = 5, .party = (const struct TrainerMon[]) @@ -11854,7 +11850,7 @@ F_TRAINER_FEMALE | }, }, #line 4791 - [TRAINER_ROXANNE_1] = + [DIFFICULTY_NORMAL][TRAINER_ROXANNE_1] = { #line 4792 .trainerName = _("ROXANNE"), @@ -11935,7 +11931,7 @@ F_TRAINER_FEMALE | }, }, #line 4825 - [TRAINER_BRAWLY_1] = + [DIFFICULTY_NORMAL][TRAINER_BRAWLY_1] = { #line 4826 .trainerName = _("BRAWLY"), @@ -12014,7 +12010,7 @@ F_TRAINER_FEMALE | }, }, #line 4859 - [TRAINER_WATTSON_1] = + [DIFFICULTY_NORMAL][TRAINER_WATTSON_1] = { #line 4860 .trainerName = _("WATTSON"), @@ -12111,7 +12107,7 @@ F_TRAINER_FEMALE | }, }, #line 4901 - [TRAINER_FLANNERY_1] = + [DIFFICULTY_NORMAL][TRAINER_FLANNERY_1] = { #line 4902 .trainerName = _("FLANNERY"), @@ -12210,7 +12206,7 @@ F_TRAINER_FEMALE | }, }, #line 4943 - [TRAINER_NORMAN_1] = + [DIFFICULTY_NORMAL][TRAINER_NORMAN_1] = { #line 4944 .trainerName = _("NORMAN"), @@ -12307,7 +12303,7 @@ F_TRAINER_FEMALE | }, }, #line 4985 - [TRAINER_WINONA_1] = + [DIFFICULTY_NORMAL][TRAINER_WINONA_1] = { #line 4986 .trainerName = _("WINONA"), @@ -12424,7 +12420,7 @@ F_TRAINER_FEMALE | }, }, #line 5035 - [TRAINER_TATE_AND_LIZA_1] = + [DIFFICULTY_NORMAL][TRAINER_TATE_AND_LIZA_1] = { #line 5036 .trainerName = _("TATE&LIZA"), @@ -12523,7 +12519,7 @@ F_TRAINER_FEMALE | }, }, #line 5077 - [TRAINER_JUAN_1] = + [DIFFICULTY_NORMAL][TRAINER_JUAN_1] = { #line 5078 .trainerName = _("JUAN"), @@ -12638,7 +12634,7 @@ F_TRAINER_FEMALE | }, }, #line 5127 - [TRAINER_JERRY_1] = + [DIFFICULTY_NORMAL][TRAINER_JERRY_1] = { #line 5128 .trainerName = _("JERRY"), @@ -12670,7 +12666,7 @@ F_TRAINER_FEMALE | }, }, #line 5140 - [TRAINER_TED] = + [DIFFICULTY_NORMAL][TRAINER_TED] = { #line 5141 .trainerName = _("TED"), @@ -12702,7 +12698,7 @@ F_TRAINER_FEMALE | }, }, #line 5153 - [TRAINER_PAUL] = + [DIFFICULTY_NORMAL][TRAINER_PAUL] = { #line 5154 .trainerName = _("PAUL"), @@ -12756,7 +12752,7 @@ F_TRAINER_FEMALE | }, }, #line 5174 - [TRAINER_JERRY_2] = + [DIFFICULTY_NORMAL][TRAINER_JERRY_2] = { #line 5175 .trainerName = _("JERRY"), @@ -12799,7 +12795,7 @@ F_TRAINER_FEMALE | }, }, #line 5191 - [TRAINER_JERRY_3] = + [DIFFICULTY_NORMAL][TRAINER_JERRY_3] = { #line 5192 .trainerName = _("JERRY"), @@ -12842,7 +12838,7 @@ F_TRAINER_FEMALE | }, }, #line 5208 - [TRAINER_JERRY_4] = + [DIFFICULTY_NORMAL][TRAINER_JERRY_4] = { #line 5209 .trainerName = _("JERRY"), @@ -12885,7 +12881,7 @@ F_TRAINER_FEMALE | }, }, #line 5225 - [TRAINER_JERRY_5] = + [DIFFICULTY_NORMAL][TRAINER_JERRY_5] = { #line 5226 .trainerName = _("JERRY"), @@ -12939,7 +12935,7 @@ F_TRAINER_FEMALE | }, }, #line 5246 - [TRAINER_KAREN_1] = + [DIFFICULTY_NORMAL][TRAINER_KAREN_1] = { #line 5247 .trainerName = _("KAREN"), @@ -12973,7 +12969,7 @@ F_TRAINER_FEMALE | }, }, #line 5259 - [TRAINER_GEORGIA] = + [DIFFICULTY_NORMAL][TRAINER_GEORGIA] = { #line 5260 .trainerName = _("GEORGIA"), @@ -13018,7 +13014,7 @@ F_TRAINER_FEMALE | }, }, #line 5276 - [TRAINER_KAREN_2] = + [DIFFICULTY_NORMAL][TRAINER_KAREN_2] = { #line 5277 .trainerName = _("KAREN"), @@ -13063,7 +13059,7 @@ F_TRAINER_FEMALE | }, }, #line 5293 - [TRAINER_KAREN_3] = + [DIFFICULTY_NORMAL][TRAINER_KAREN_3] = { #line 5294 .trainerName = _("KAREN"), @@ -13108,7 +13104,7 @@ F_TRAINER_FEMALE | }, }, #line 5310 - [TRAINER_KAREN_4] = + [DIFFICULTY_NORMAL][TRAINER_KAREN_4] = { #line 5311 .trainerName = _("KAREN"), @@ -13153,7 +13149,7 @@ F_TRAINER_FEMALE | }, }, #line 5327 - [TRAINER_KAREN_5] = + [DIFFICULTY_NORMAL][TRAINER_KAREN_5] = { #line 5328 .trainerName = _("KAREN"), @@ -13198,7 +13194,7 @@ F_TRAINER_FEMALE | }, }, #line 5344 - [TRAINER_KATE_AND_JOY] = + [DIFFICULTY_NORMAL][TRAINER_KATE_AND_JOY] = { #line 5345 .trainerName = _("KATE & JOY"), @@ -13255,7 +13251,7 @@ F_TRAINER_FEMALE | }, }, #line 5369 - [TRAINER_ANNA_AND_MEG_1] = + [DIFFICULTY_NORMAL][TRAINER_ANNA_AND_MEG_1] = { #line 5370 .trainerName = _("ANNA & MEG"), @@ -13311,7 +13307,7 @@ F_TRAINER_FEMALE | }, }, #line 5393 - [TRAINER_ANNA_AND_MEG_2] = + [DIFFICULTY_NORMAL][TRAINER_ANNA_AND_MEG_2] = { #line 5394 .trainerName = _("ANNA & MEG"), @@ -13367,7 +13363,7 @@ F_TRAINER_FEMALE | }, }, #line 5417 - [TRAINER_ANNA_AND_MEG_3] = + [DIFFICULTY_NORMAL][TRAINER_ANNA_AND_MEG_3] = { #line 5418 .trainerName = _("ANNA & MEG"), @@ -13423,7 +13419,7 @@ F_TRAINER_FEMALE | }, }, #line 5441 - [TRAINER_ANNA_AND_MEG_4] = + [DIFFICULTY_NORMAL][TRAINER_ANNA_AND_MEG_4] = { #line 5442 .trainerName = _("ANNA & MEG"), @@ -13479,7 +13475,7 @@ F_TRAINER_FEMALE | }, }, #line 5465 - [TRAINER_ANNA_AND_MEG_5] = + [DIFFICULTY_NORMAL][TRAINER_ANNA_AND_MEG_5] = { #line 5466 .trainerName = _("ANNA & MEG"), @@ -13535,7 +13531,7 @@ F_TRAINER_FEMALE | }, }, #line 5489 - [TRAINER_VICTOR] = + [DIFFICULTY_NORMAL][TRAINER_VICTOR] = { #line 5490 .trainerName = _("VICTOR"), @@ -13582,7 +13578,7 @@ F_TRAINER_FEMALE | }, }, #line 5506 - [TRAINER_MIGUEL_1] = + [DIFFICULTY_NORMAL][TRAINER_MIGUEL_1] = { #line 5507 .trainerName = _("MIGUEL"), @@ -13616,7 +13612,7 @@ F_TRAINER_FEMALE | }, }, #line 5519 - [TRAINER_COLTON] = + [DIFFICULTY_NORMAL][TRAINER_COLTON] = { #line 5520 .trainerName = _("COLTON"), @@ -13757,7 +13753,7 @@ F_TRAINER_FEMALE | }, }, #line 5576 - [TRAINER_MIGUEL_2] = + [DIFFICULTY_NORMAL][TRAINER_MIGUEL_2] = { #line 5577 .trainerName = _("MIGUEL"), @@ -13791,7 +13787,7 @@ F_TRAINER_FEMALE | }, }, #line 5589 - [TRAINER_MIGUEL_3] = + [DIFFICULTY_NORMAL][TRAINER_MIGUEL_3] = { #line 5590 .trainerName = _("MIGUEL"), @@ -13825,7 +13821,7 @@ F_TRAINER_FEMALE | }, }, #line 5602 - [TRAINER_MIGUEL_4] = + [DIFFICULTY_NORMAL][TRAINER_MIGUEL_4] = { #line 5603 .trainerName = _("MIGUEL"), @@ -13859,7 +13855,7 @@ F_TRAINER_FEMALE | }, }, #line 5615 - [TRAINER_MIGUEL_5] = + [DIFFICULTY_NORMAL][TRAINER_MIGUEL_5] = { #line 5616 .trainerName = _("MIGUEL"), @@ -13893,7 +13889,7 @@ F_TRAINER_FEMALE | }, }, #line 5628 - [TRAINER_VICTORIA] = + [DIFFICULTY_NORMAL][TRAINER_VICTORIA] = { #line 5629 .trainerName = _("VICTORIA"), @@ -13929,7 +13925,7 @@ F_TRAINER_FEMALE | }, }, #line 5641 - [TRAINER_VANESSA] = + [DIFFICULTY_NORMAL][TRAINER_VANESSA] = { #line 5642 .trainerName = _("VANESSA"), @@ -13965,7 +13961,7 @@ F_TRAINER_FEMALE | }, }, #line 5654 - [TRAINER_BETHANY] = + [DIFFICULTY_NORMAL][TRAINER_BETHANY] = { #line 5655 .trainerName = _("BETHANY"), @@ -14027,7 +14023,7 @@ F_TRAINER_FEMALE | }, }, #line 5675 - [TRAINER_ISABEL_1] = + [DIFFICULTY_NORMAL][TRAINER_ISABEL_1] = { #line 5676 .trainerName = _("ISABEL"), @@ -14076,7 +14072,7 @@ F_TRAINER_FEMALE | }, }, #line 5692 - [TRAINER_ISABEL_2] = + [DIFFICULTY_NORMAL][TRAINER_ISABEL_2] = { #line 5693 .trainerName = _("ISABEL"), @@ -14125,7 +14121,7 @@ F_TRAINER_FEMALE | }, }, #line 5709 - [TRAINER_ISABEL_3] = + [DIFFICULTY_NORMAL][TRAINER_ISABEL_3] = { #line 5710 .trainerName = _("ISABEL"), @@ -14174,7 +14170,7 @@ F_TRAINER_FEMALE | }, }, #line 5726 - [TRAINER_ISABEL_4] = + [DIFFICULTY_NORMAL][TRAINER_ISABEL_4] = { #line 5727 .trainerName = _("ISABEL"), @@ -14223,7 +14219,7 @@ F_TRAINER_FEMALE | }, }, #line 5743 - [TRAINER_ISABEL_5] = + [DIFFICULTY_NORMAL][TRAINER_ISABEL_5] = { #line 5744 .trainerName = _("ISABEL"), @@ -14272,7 +14268,7 @@ F_TRAINER_FEMALE | }, }, #line 5760 - [TRAINER_TIMOTHY_1] = + [DIFFICULTY_NORMAL][TRAINER_TIMOTHY_1] = { #line 5761 .trainerName = _("TIMOTHY"), @@ -14304,7 +14300,7 @@ F_TRAINER_FEMALE | }, }, #line 5773 - [TRAINER_TIMOTHY_2] = + [DIFFICULTY_NORMAL][TRAINER_TIMOTHY_2] = { #line 5774 .trainerName = _("TIMOTHY"), @@ -14343,7 +14339,7 @@ F_TRAINER_FEMALE | }, }, #line 5790 - [TRAINER_TIMOTHY_3] = + [DIFFICULTY_NORMAL][TRAINER_TIMOTHY_3] = { #line 5791 .trainerName = _("TIMOTHY"), @@ -14382,7 +14378,7 @@ F_TRAINER_FEMALE | }, }, #line 5807 - [TRAINER_TIMOTHY_4] = + [DIFFICULTY_NORMAL][TRAINER_TIMOTHY_4] = { #line 5808 .trainerName = _("TIMOTHY"), @@ -14421,7 +14417,7 @@ F_TRAINER_FEMALE | }, }, #line 5824 - [TRAINER_TIMOTHY_5] = + [DIFFICULTY_NORMAL][TRAINER_TIMOTHY_5] = { #line 5825 .trainerName = _("TIMOTHY"), @@ -14460,7 +14456,7 @@ F_TRAINER_FEMALE | }, }, #line 5841 - [TRAINER_VICKY] = + [DIFFICULTY_NORMAL][TRAINER_VICKY] = { #line 5842 .trainerName = _("VICKY"), @@ -14501,7 +14497,7 @@ F_TRAINER_FEMALE | }, }, #line 5858 - [TRAINER_SHELBY_1] = + [DIFFICULTY_NORMAL][TRAINER_SHELBY_1] = { #line 5859 .trainerName = _("SHELBY"), @@ -14546,7 +14542,7 @@ F_TRAINER_FEMALE | }, }, #line 5875 - [TRAINER_SHELBY_2] = + [DIFFICULTY_NORMAL][TRAINER_SHELBY_2] = { #line 5876 .trainerName = _("SHELBY"), @@ -14591,7 +14587,7 @@ F_TRAINER_FEMALE | }, }, #line 5892 - [TRAINER_SHELBY_3] = + [DIFFICULTY_NORMAL][TRAINER_SHELBY_3] = { #line 5893 .trainerName = _("SHELBY"), @@ -14636,7 +14632,7 @@ F_TRAINER_FEMALE | }, }, #line 5909 - [TRAINER_SHELBY_4] = + [DIFFICULTY_NORMAL][TRAINER_SHELBY_4] = { #line 5910 .trainerName = _("SHELBY"), @@ -14681,7 +14677,7 @@ F_TRAINER_FEMALE | }, }, #line 5926 - [TRAINER_SHELBY_5] = + [DIFFICULTY_NORMAL][TRAINER_SHELBY_5] = { #line 5927 .trainerName = _("SHELBY"), @@ -14726,7 +14722,7 @@ F_TRAINER_FEMALE | }, }, #line 5943 - [TRAINER_CALVIN_1] = + [DIFFICULTY_NORMAL][TRAINER_CALVIN_1] = { #line 5944 .trainerName = _("CALVIN"), @@ -14758,7 +14754,7 @@ F_TRAINER_FEMALE | }, }, #line 5956 - [TRAINER_BILLY] = + [DIFFICULTY_NORMAL][TRAINER_BILLY] = { #line 5957 .trainerName = _("BILLY"), @@ -14801,7 +14797,7 @@ F_TRAINER_FEMALE | }, }, #line 5973 - [TRAINER_JOSH] = + [DIFFICULTY_NORMAL][TRAINER_JOSH] = { #line 5974 .trainerName = _("JOSH"), @@ -14837,7 +14833,7 @@ F_TRAINER_FEMALE | }, }, #line 5987 - [TRAINER_TOMMY] = + [DIFFICULTY_NORMAL][TRAINER_TOMMY] = { #line 5988 .trainerName = _("TOMMY"), @@ -14880,7 +14876,7 @@ F_TRAINER_FEMALE | }, }, #line 6004 - [TRAINER_JOEY] = + [DIFFICULTY_NORMAL][TRAINER_JOEY] = { #line 6005 .trainerName = _("JOEY"), @@ -14912,7 +14908,7 @@ F_TRAINER_FEMALE | }, }, #line 6017 - [TRAINER_BEN] = + [DIFFICULTY_NORMAL][TRAINER_BEN] = { #line 6018 .trainerName = _("BEN"), @@ -14969,7 +14965,7 @@ F_TRAINER_FEMALE | }, }, #line 6042 - [TRAINER_QUINCY] = + [DIFFICULTY_NORMAL][TRAINER_QUINCY] = { #line 6043 .trainerName = _("QUINCY"), @@ -15028,7 +15024,7 @@ F_TRAINER_FEMALE | }, }, #line 6068 - [TRAINER_KATELYNN] = + [DIFFICULTY_NORMAL][TRAINER_KATELYNN] = { #line 6069 .trainerName = _("KATELYNN"), @@ -15089,7 +15085,7 @@ F_TRAINER_FEMALE | }, }, #line 6094 - [TRAINER_JAYLEN] = + [DIFFICULTY_NORMAL][TRAINER_JAYLEN] = { #line 6095 .trainerName = _("JAYLEN"), @@ -15121,7 +15117,7 @@ F_TRAINER_FEMALE | }, }, #line 6107 - [TRAINER_DILLON] = + [DIFFICULTY_NORMAL][TRAINER_DILLON] = { #line 6108 .trainerName = _("DILLON"), @@ -15153,7 +15149,7 @@ F_TRAINER_FEMALE | }, }, #line 6120 - [TRAINER_CALVIN_2] = + [DIFFICULTY_NORMAL][TRAINER_CALVIN_2] = { #line 6121 .trainerName = _("CALVIN"), @@ -15185,7 +15181,7 @@ F_TRAINER_FEMALE | }, }, #line 6133 - [TRAINER_CALVIN_3] = + [DIFFICULTY_NORMAL][TRAINER_CALVIN_3] = { #line 6134 .trainerName = _("CALVIN"), @@ -15228,7 +15224,7 @@ F_TRAINER_FEMALE | }, }, #line 6150 - [TRAINER_CALVIN_4] = + [DIFFICULTY_NORMAL][TRAINER_CALVIN_4] = { #line 6151 .trainerName = _("CALVIN"), @@ -15282,7 +15278,7 @@ F_TRAINER_FEMALE | }, }, #line 6171 - [TRAINER_CALVIN_5] = + [DIFFICULTY_NORMAL][TRAINER_CALVIN_5] = { #line 6172 .trainerName = _("CALVIN"), @@ -15336,7 +15332,7 @@ F_TRAINER_FEMALE | }, }, #line 6192 - [TRAINER_EDDIE] = + [DIFFICULTY_NORMAL][TRAINER_EDDIE] = { #line 6193 .trainerName = _("EDDIE"), @@ -15379,7 +15375,7 @@ F_TRAINER_FEMALE | }, }, #line 6209 - [TRAINER_ALLEN] = + [DIFFICULTY_NORMAL][TRAINER_ALLEN] = { #line 6210 .trainerName = _("ALLEN"), @@ -15422,7 +15418,7 @@ F_TRAINER_FEMALE | }, }, #line 6226 - [TRAINER_TIMMY] = + [DIFFICULTY_NORMAL][TRAINER_TIMMY] = { #line 6227 .trainerName = _("TIMMY"), @@ -15465,7 +15461,7 @@ F_TRAINER_FEMALE | }, }, #line 6243 - [TRAINER_WALLACE] = + [DIFFICULTY_NORMAL][TRAINER_WALLACE] = { #line 6244 .trainerName = _("WALLACE"), @@ -15483,7 +15479,6 @@ F_TRAINER_FEMALE | #line 6251 .aiFlags = AI_FLAG_BASIC_TRAINER, #line 6252 - .mugshotEnabled = TRUE, .mugshotColor = MUGSHOT_COLOR_YELLOW, .partySize = 6, .party = (const struct TrainerMon[]) @@ -15601,7 +15596,7 @@ F_TRAINER_FEMALE | }, }, #line 6302 - [TRAINER_ANDREW] = + [DIFFICULTY_NORMAL][TRAINER_ANDREW] = { #line 6303 .trainerName = _("ANDREW"), @@ -15655,7 +15650,7 @@ F_TRAINER_FEMALE | }, }, #line 6323 - [TRAINER_IVAN] = + [DIFFICULTY_NORMAL][TRAINER_IVAN] = { #line 6324 .trainerName = _("IVAN"), @@ -15709,7 +15704,7 @@ F_TRAINER_FEMALE | }, }, #line 6344 - [TRAINER_CLAUDE] = + [DIFFICULTY_NORMAL][TRAINER_CLAUDE] = { #line 6345 .trainerName = _("CLAUDE"), @@ -15763,7 +15758,7 @@ F_TRAINER_FEMALE | }, }, #line 6365 - [TRAINER_ELLIOT_1] = + [DIFFICULTY_NORMAL][TRAINER_ELLIOT_1] = { #line 6366 .trainerName = _("ELLIOT"), @@ -15817,7 +15812,7 @@ F_TRAINER_FEMALE | }, }, #line 6386 - [TRAINER_NED] = + [DIFFICULTY_NORMAL][TRAINER_NED] = { #line 6387 .trainerName = _("NED"), @@ -15849,7 +15844,7 @@ F_TRAINER_FEMALE | }, }, #line 6399 - [TRAINER_DALE] = + [DIFFICULTY_NORMAL][TRAINER_DALE] = { #line 6400 .trainerName = _("DALE"), @@ -15914,7 +15909,7 @@ F_TRAINER_FEMALE | }, }, #line 6424 - [TRAINER_NOLAN] = + [DIFFICULTY_NORMAL][TRAINER_NOLAN] = { #line 6425 .trainerName = _("NOLAN"), @@ -15946,7 +15941,7 @@ F_TRAINER_FEMALE | }, }, #line 6437 - [TRAINER_BARNY] = + [DIFFICULTY_NORMAL][TRAINER_BARNY] = { #line 6438 .trainerName = _("BARNY"), @@ -15989,7 +15984,7 @@ F_TRAINER_FEMALE | }, }, #line 6454 - [TRAINER_WADE] = + [DIFFICULTY_NORMAL][TRAINER_WADE] = { #line 6455 .trainerName = _("WADE"), @@ -16021,7 +16016,7 @@ F_TRAINER_FEMALE | }, }, #line 6467 - [TRAINER_CARTER] = + [DIFFICULTY_NORMAL][TRAINER_CARTER] = { #line 6468 .trainerName = _("CARTER"), @@ -16064,7 +16059,7 @@ F_TRAINER_FEMALE | }, }, #line 6484 - [TRAINER_ELLIOT_2] = + [DIFFICULTY_NORMAL][TRAINER_ELLIOT_2] = { #line 6485 .trainerName = _("ELLIOT"), @@ -16118,7 +16113,7 @@ F_TRAINER_FEMALE | }, }, #line 6505 - [TRAINER_ELLIOT_3] = + [DIFFICULTY_NORMAL][TRAINER_ELLIOT_3] = { #line 6506 .trainerName = _("ELLIOT"), @@ -16183,7 +16178,7 @@ F_TRAINER_FEMALE | }, }, #line 6530 - [TRAINER_ELLIOT_4] = + [DIFFICULTY_NORMAL][TRAINER_ELLIOT_4] = { #line 6531 .trainerName = _("ELLIOT"), @@ -16248,7 +16243,7 @@ F_TRAINER_FEMALE | }, }, #line 6555 - [TRAINER_ELLIOT_5] = + [DIFFICULTY_NORMAL][TRAINER_ELLIOT_5] = { #line 6556 .trainerName = _("ELLIOT"), @@ -16313,7 +16308,7 @@ F_TRAINER_FEMALE | }, }, #line 6580 - [TRAINER_RONALD] = + [DIFFICULTY_NORMAL][TRAINER_RONALD] = { #line 6581 .trainerName = _("RONALD"), @@ -16400,7 +16395,7 @@ F_TRAINER_FEMALE | }, }, #line 6613 - [TRAINER_JACOB] = + [DIFFICULTY_NORMAL][TRAINER_JACOB] = { #line 6614 .trainerName = _("JACOB"), @@ -16454,7 +16449,7 @@ F_TRAINER_FEMALE | }, }, #line 6634 - [TRAINER_ANTHONY] = + [DIFFICULTY_NORMAL][TRAINER_ANTHONY] = { #line 6635 .trainerName = _("ANTHONY"), @@ -16497,7 +16492,7 @@ F_TRAINER_FEMALE | }, }, #line 6651 - [TRAINER_BENJAMIN_1] = + [DIFFICULTY_NORMAL][TRAINER_BENJAMIN_1] = { #line 6652 .trainerName = _("BENJAMIN"), @@ -16529,7 +16524,7 @@ F_TRAINER_FEMALE | }, }, #line 6664 - [TRAINER_BENJAMIN_2] = + [DIFFICULTY_NORMAL][TRAINER_BENJAMIN_2] = { #line 6665 .trainerName = _("BENJAMIN"), @@ -16561,7 +16556,7 @@ F_TRAINER_FEMALE | }, }, #line 6677 - [TRAINER_BENJAMIN_3] = + [DIFFICULTY_NORMAL][TRAINER_BENJAMIN_3] = { #line 6678 .trainerName = _("BENJAMIN"), @@ -16593,7 +16588,7 @@ F_TRAINER_FEMALE | }, }, #line 6690 - [TRAINER_BENJAMIN_4] = + [DIFFICULTY_NORMAL][TRAINER_BENJAMIN_4] = { #line 6691 .trainerName = _("BENJAMIN"), @@ -16625,7 +16620,7 @@ F_TRAINER_FEMALE | }, }, #line 6703 - [TRAINER_BENJAMIN_5] = + [DIFFICULTY_NORMAL][TRAINER_BENJAMIN_5] = { #line 6704 .trainerName = _("BENJAMIN"), @@ -16657,7 +16652,7 @@ F_TRAINER_FEMALE | }, }, #line 6716 - [TRAINER_ABIGAIL_1] = + [DIFFICULTY_NORMAL][TRAINER_ABIGAIL_1] = { #line 6717 .trainerName = _("ABIGAIL"), @@ -16691,7 +16686,7 @@ F_TRAINER_FEMALE | }, }, #line 6729 - [TRAINER_JASMINE] = + [DIFFICULTY_NORMAL][TRAINER_JASMINE] = { #line 6730 .trainerName = _("JASMINE"), @@ -16747,7 +16742,7 @@ F_TRAINER_FEMALE | }, }, #line 6750 - [TRAINER_ABIGAIL_2] = + [DIFFICULTY_NORMAL][TRAINER_ABIGAIL_2] = { #line 6751 .trainerName = _("ABIGAIL"), @@ -16781,7 +16776,7 @@ F_TRAINER_FEMALE | }, }, #line 6763 - [TRAINER_ABIGAIL_3] = + [DIFFICULTY_NORMAL][TRAINER_ABIGAIL_3] = { #line 6764 .trainerName = _("ABIGAIL"), @@ -16815,7 +16810,7 @@ F_TRAINER_FEMALE | }, }, #line 6776 - [TRAINER_ABIGAIL_4] = + [DIFFICULTY_NORMAL][TRAINER_ABIGAIL_4] = { #line 6777 .trainerName = _("ABIGAIL"), @@ -16849,7 +16844,7 @@ F_TRAINER_FEMALE | }, }, #line 6789 - [TRAINER_ABIGAIL_5] = + [DIFFICULTY_NORMAL][TRAINER_ABIGAIL_5] = { #line 6790 .trainerName = _("ABIGAIL"), @@ -16883,7 +16878,7 @@ F_TRAINER_FEMALE | }, }, #line 6802 - [TRAINER_DYLAN_1] = + [DIFFICULTY_NORMAL][TRAINER_DYLAN_1] = { #line 6803 .trainerName = _("DYLAN"), @@ -16915,7 +16910,7 @@ F_TRAINER_FEMALE | }, }, #line 6815 - [TRAINER_DYLAN_2] = + [DIFFICULTY_NORMAL][TRAINER_DYLAN_2] = { #line 6816 .trainerName = _("DYLAN"), @@ -16947,7 +16942,7 @@ F_TRAINER_FEMALE | }, }, #line 6828 - [TRAINER_DYLAN_3] = + [DIFFICULTY_NORMAL][TRAINER_DYLAN_3] = { #line 6829 .trainerName = _("DYLAN"), @@ -16979,7 +16974,7 @@ F_TRAINER_FEMALE | }, }, #line 6841 - [TRAINER_DYLAN_4] = + [DIFFICULTY_NORMAL][TRAINER_DYLAN_4] = { #line 6842 .trainerName = _("DYLAN"), @@ -17011,7 +17006,7 @@ F_TRAINER_FEMALE | }, }, #line 6854 - [TRAINER_DYLAN_5] = + [DIFFICULTY_NORMAL][TRAINER_DYLAN_5] = { #line 6855 .trainerName = _("DYLAN"), @@ -17043,7 +17038,7 @@ F_TRAINER_FEMALE | }, }, #line 6867 - [TRAINER_MARIA_1] = + [DIFFICULTY_NORMAL][TRAINER_MARIA_1] = { #line 6868 .trainerName = _("MARIA"), @@ -17077,7 +17072,7 @@ F_TRAINER_FEMALE | }, }, #line 6880 - [TRAINER_MARIA_2] = + [DIFFICULTY_NORMAL][TRAINER_MARIA_2] = { #line 6881 .trainerName = _("MARIA"), @@ -17111,7 +17106,7 @@ F_TRAINER_FEMALE | }, }, #line 6893 - [TRAINER_MARIA_3] = + [DIFFICULTY_NORMAL][TRAINER_MARIA_3] = { #line 6894 .trainerName = _("MARIA"), @@ -17145,7 +17140,7 @@ F_TRAINER_FEMALE | }, }, #line 6906 - [TRAINER_MARIA_4] = + [DIFFICULTY_NORMAL][TRAINER_MARIA_4] = { #line 6907 .trainerName = _("MARIA"), @@ -17179,7 +17174,7 @@ F_TRAINER_FEMALE | }, }, #line 6919 - [TRAINER_MARIA_5] = + [DIFFICULTY_NORMAL][TRAINER_MARIA_5] = { #line 6920 .trainerName = _("MARIA"), @@ -17213,7 +17208,7 @@ F_TRAINER_FEMALE | }, }, #line 6932 - [TRAINER_CAMDEN] = + [DIFFICULTY_NORMAL][TRAINER_CAMDEN] = { #line 6933 .trainerName = _("CAMDEN"), @@ -17256,7 +17251,7 @@ F_TRAINER_FEMALE | }, }, #line 6949 - [TRAINER_DEMETRIUS] = + [DIFFICULTY_NORMAL][TRAINER_DEMETRIUS] = { #line 6950 .trainerName = _("DEMETRIUS"), @@ -17299,7 +17294,7 @@ F_TRAINER_FEMALE | }, }, #line 6966 - [TRAINER_ISAIAH_1] = + [DIFFICULTY_NORMAL][TRAINER_ISAIAH_1] = { #line 6967 .trainerName = _("ISAIAH"), @@ -17331,7 +17326,7 @@ F_TRAINER_FEMALE | }, }, #line 6979 - [TRAINER_PABLO_1] = + [DIFFICULTY_NORMAL][TRAINER_PABLO_1] = { #line 6980 .trainerName = _("PABLO"), @@ -17374,7 +17369,7 @@ F_TRAINER_FEMALE | }, }, #line 6996 - [TRAINER_CHASE] = + [DIFFICULTY_NORMAL][TRAINER_CHASE] = { #line 6997 .trainerName = _("CHASE"), @@ -17417,7 +17412,7 @@ F_TRAINER_FEMALE | }, }, #line 7013 - [TRAINER_ISAIAH_2] = + [DIFFICULTY_NORMAL][TRAINER_ISAIAH_2] = { #line 7014 .trainerName = _("ISAIAH"), @@ -17449,7 +17444,7 @@ F_TRAINER_FEMALE | }, }, #line 7026 - [TRAINER_ISAIAH_3] = + [DIFFICULTY_NORMAL][TRAINER_ISAIAH_3] = { #line 7027 .trainerName = _("ISAIAH"), @@ -17481,7 +17476,7 @@ F_TRAINER_FEMALE | }, }, #line 7039 - [TRAINER_ISAIAH_4] = + [DIFFICULTY_NORMAL][TRAINER_ISAIAH_4] = { #line 7040 .trainerName = _("ISAIAH"), @@ -17513,7 +17508,7 @@ F_TRAINER_FEMALE | }, }, #line 7052 - [TRAINER_ISAIAH_5] = + [DIFFICULTY_NORMAL][TRAINER_ISAIAH_5] = { #line 7053 .trainerName = _("ISAIAH"), @@ -17545,7 +17540,7 @@ F_TRAINER_FEMALE | }, }, #line 7065 - [TRAINER_ISOBEL] = + [DIFFICULTY_NORMAL][TRAINER_ISOBEL] = { #line 7066 .trainerName = _("ISOBEL"), @@ -17579,7 +17574,7 @@ F_TRAINER_FEMALE | }, }, #line 7078 - [TRAINER_DONNY] = + [DIFFICULTY_NORMAL][TRAINER_DONNY] = { #line 7079 .trainerName = _("DONNY"), @@ -17624,7 +17619,7 @@ F_TRAINER_FEMALE | }, }, #line 7095 - [TRAINER_TALIA] = + [DIFFICULTY_NORMAL][TRAINER_TALIA] = { #line 7096 .trainerName = _("TALIA"), @@ -17658,7 +17653,7 @@ F_TRAINER_FEMALE | }, }, #line 7108 - [TRAINER_KATELYN_1] = + [DIFFICULTY_NORMAL][TRAINER_KATELYN_1] = { #line 7109 .trainerName = _("KATELYN"), @@ -17692,7 +17687,7 @@ F_TRAINER_FEMALE | }, }, #line 7121 - [TRAINER_ALLISON] = + [DIFFICULTY_NORMAL][TRAINER_ALLISON] = { #line 7122 .trainerName = _("ALLISON"), @@ -17737,7 +17732,7 @@ F_TRAINER_FEMALE | }, }, #line 7138 - [TRAINER_KATELYN_2] = + [DIFFICULTY_NORMAL][TRAINER_KATELYN_2] = { #line 7139 .trainerName = _("KATELYN"), @@ -17771,7 +17766,7 @@ F_TRAINER_FEMALE | }, }, #line 7151 - [TRAINER_KATELYN_3] = + [DIFFICULTY_NORMAL][TRAINER_KATELYN_3] = { #line 7152 .trainerName = _("KATELYN"), @@ -17805,7 +17800,7 @@ F_TRAINER_FEMALE | }, }, #line 7164 - [TRAINER_KATELYN_4] = + [DIFFICULTY_NORMAL][TRAINER_KATELYN_4] = { #line 7165 .trainerName = _("KATELYN"), @@ -17839,7 +17834,7 @@ F_TRAINER_FEMALE | }, }, #line 7177 - [TRAINER_KATELYN_5] = + [DIFFICULTY_NORMAL][TRAINER_KATELYN_5] = { #line 7178 .trainerName = _("KATELYN"), @@ -17873,7 +17868,7 @@ F_TRAINER_FEMALE | }, }, #line 7190 - [TRAINER_NICOLAS_1] = + [DIFFICULTY_NORMAL][TRAINER_NICOLAS_1] = { #line 7191 .trainerName = _("NICOLAS"), @@ -17916,7 +17911,7 @@ F_TRAINER_FEMALE | }, }, #line 7207 - [TRAINER_NICOLAS_2] = + [DIFFICULTY_NORMAL][TRAINER_NICOLAS_2] = { #line 7208 .trainerName = _("NICOLAS"), @@ -17959,7 +17954,7 @@ F_TRAINER_FEMALE | }, }, #line 7224 - [TRAINER_NICOLAS_3] = + [DIFFICULTY_NORMAL][TRAINER_NICOLAS_3] = { #line 7225 .trainerName = _("NICOLAS"), @@ -18002,7 +17997,7 @@ F_TRAINER_FEMALE | }, }, #line 7241 - [TRAINER_NICOLAS_4] = + [DIFFICULTY_NORMAL][TRAINER_NICOLAS_4] = { #line 7242 .trainerName = _("NICOLAS"), @@ -18056,7 +18051,7 @@ F_TRAINER_FEMALE | }, }, #line 7262 - [TRAINER_NICOLAS_5] = + [DIFFICULTY_NORMAL][TRAINER_NICOLAS_5] = { #line 7263 .trainerName = _("NICOLAS"), @@ -18112,7 +18107,7 @@ F_TRAINER_FEMALE | }, }, #line 7283 - [TRAINER_AARON] = + [DIFFICULTY_NORMAL][TRAINER_AARON] = { #line 7284 .trainerName = _("AARON"), @@ -18151,7 +18146,7 @@ F_TRAINER_FEMALE | }, }, #line 7300 - [TRAINER_PERRY] = + [DIFFICULTY_NORMAL][TRAINER_PERRY] = { #line 7301 .trainerName = _("PERRY"), @@ -18183,7 +18178,7 @@ F_TRAINER_FEMALE | }, }, #line 7313 - [TRAINER_HUGH] = + [DIFFICULTY_NORMAL][TRAINER_HUGH] = { #line 7314 .trainerName = _("HUGH"), @@ -18226,7 +18221,7 @@ F_TRAINER_FEMALE | }, }, #line 7330 - [TRAINER_PHIL] = + [DIFFICULTY_NORMAL][TRAINER_PHIL] = { #line 7331 .trainerName = _("PHIL"), @@ -18258,7 +18253,7 @@ F_TRAINER_FEMALE | }, }, #line 7343 - [TRAINER_JARED] = + [DIFFICULTY_NORMAL][TRAINER_JARED] = { #line 7344 .trainerName = _("JARED"), @@ -18312,7 +18307,7 @@ F_TRAINER_FEMALE | }, }, #line 7364 - [TRAINER_HUMBERTO] = + [DIFFICULTY_NORMAL][TRAINER_HUMBERTO] = { #line 7365 .trainerName = _("HUMBERTO"), @@ -18344,7 +18339,7 @@ F_TRAINER_FEMALE | }, }, #line 7377 - [TRAINER_PRESLEY] = + [DIFFICULTY_NORMAL][TRAINER_PRESLEY] = { #line 7378 .trainerName = _("PRESLEY"), @@ -18387,7 +18382,7 @@ F_TRAINER_FEMALE | }, }, #line 7394 - [TRAINER_EDWARDO] = + [DIFFICULTY_NORMAL][TRAINER_EDWARDO] = { #line 7395 .trainerName = _("EDWARDO"), @@ -18430,7 +18425,7 @@ F_TRAINER_FEMALE | }, }, #line 7411 - [TRAINER_COLIN] = + [DIFFICULTY_NORMAL][TRAINER_COLIN] = { #line 7412 .trainerName = _("COLIN"), @@ -18473,7 +18468,7 @@ F_TRAINER_FEMALE | }, }, #line 7428 - [TRAINER_ROBERT_1] = + [DIFFICULTY_NORMAL][TRAINER_ROBERT_1] = { #line 7429 .trainerName = _("ROBERT"), @@ -18505,7 +18500,7 @@ F_TRAINER_FEMALE | }, }, #line 7441 - [TRAINER_BENNY] = + [DIFFICULTY_NORMAL][TRAINER_BENNY] = { #line 7442 .trainerName = _("BENNY"), @@ -18559,7 +18554,7 @@ F_TRAINER_FEMALE | }, }, #line 7462 - [TRAINER_CHESTER] = + [DIFFICULTY_NORMAL][TRAINER_CHESTER] = { #line 7463 .trainerName = _("CHESTER"), @@ -18602,7 +18597,7 @@ F_TRAINER_FEMALE | }, }, #line 7479 - [TRAINER_ROBERT_2] = + [DIFFICULTY_NORMAL][TRAINER_ROBERT_2] = { #line 7480 .trainerName = _("ROBERT"), @@ -18645,7 +18640,7 @@ F_TRAINER_FEMALE | }, }, #line 7496 - [TRAINER_ROBERT_3] = + [DIFFICULTY_NORMAL][TRAINER_ROBERT_3] = { #line 7497 .trainerName = _("ROBERT"), @@ -18688,7 +18683,7 @@ F_TRAINER_FEMALE | }, }, #line 7513 - [TRAINER_ROBERT_4] = + [DIFFICULTY_NORMAL][TRAINER_ROBERT_4] = { #line 7514 .trainerName = _("ROBERT"), @@ -18731,7 +18726,7 @@ F_TRAINER_FEMALE | }, }, #line 7530 - [TRAINER_ROBERT_5] = + [DIFFICULTY_NORMAL][TRAINER_ROBERT_5] = { #line 7531 .trainerName = _("ROBERT"), @@ -18774,7 +18769,7 @@ F_TRAINER_FEMALE | }, }, #line 7547 - [TRAINER_ALEX] = + [DIFFICULTY_NORMAL][TRAINER_ALEX] = { #line 7548 .trainerName = _("ALEX"), @@ -18817,7 +18812,7 @@ F_TRAINER_FEMALE | }, }, #line 7564 - [TRAINER_BECK] = + [DIFFICULTY_NORMAL][TRAINER_BECK] = { #line 7565 .trainerName = _("BECK"), @@ -18849,7 +18844,7 @@ F_TRAINER_FEMALE | }, }, #line 7577 - [TRAINER_YASU] = + [DIFFICULTY_NORMAL][TRAINER_YASU] = { #line 7578 .trainerName = _("YASU"), @@ -18881,7 +18876,7 @@ F_TRAINER_FEMALE | }, }, #line 7590 - [TRAINER_TAKASHI] = + [DIFFICULTY_NORMAL][TRAINER_TAKASHI] = { #line 7591 .trainerName = _("TAKASHI"), @@ -18924,7 +18919,7 @@ F_TRAINER_FEMALE | }, }, #line 7607 - [TRAINER_DIANNE] = + [DIFFICULTY_NORMAL][TRAINER_DIANNE] = { #line 7608 .trainerName = _("DIANNE"), @@ -18979,7 +18974,7 @@ F_TRAINER_FEMALE | }, }, #line 7628 - [TRAINER_JANI] = + [DIFFICULTY_NORMAL][TRAINER_JANI] = { #line 7629 .trainerName = _("JANI"), @@ -19011,7 +19006,7 @@ F_TRAINER_FEMALE | }, }, #line 7640 - [TRAINER_LAO_1] = + [DIFFICULTY_NORMAL][TRAINER_LAO_1] = { #line 7641 .trainerName = _("LAO"), @@ -19084,7 +19079,7 @@ F_TRAINER_FEMALE | }, }, #line 7672 - [TRAINER_LUNG] = + [DIFFICULTY_NORMAL][TRAINER_LUNG] = { #line 7673 .trainerName = _("LUNG"), @@ -19125,7 +19120,7 @@ F_TRAINER_FEMALE | }, }, #line 7688 - [TRAINER_LAO_2] = + [DIFFICULTY_NORMAL][TRAINER_LAO_2] = { #line 7689 .trainerName = _("LAO"), @@ -19213,7 +19208,7 @@ F_TRAINER_FEMALE | }, }, #line 7725 - [TRAINER_LAO_3] = + [DIFFICULTY_NORMAL][TRAINER_LAO_3] = { #line 7726 .trainerName = _("LAO"), @@ -19301,7 +19296,7 @@ F_TRAINER_FEMALE | }, }, #line 7762 - [TRAINER_LAO_4] = + [DIFFICULTY_NORMAL][TRAINER_LAO_4] = { #line 7763 .trainerName = _("LAO"), @@ -19387,7 +19382,7 @@ F_TRAINER_FEMALE | }, }, #line 7797 - [TRAINER_LAO_5] = + [DIFFICULTY_NORMAL][TRAINER_LAO_5] = { #line 7798 .trainerName = _("LAO"), @@ -19477,7 +19472,7 @@ F_TRAINER_FEMALE | }, }, #line 7834 - [TRAINER_JOCELYN] = + [DIFFICULTY_NORMAL][TRAINER_JOCELYN] = { #line 7835 .trainerName = _("JOCELYN"), @@ -19511,7 +19506,7 @@ F_TRAINER_FEMALE | }, }, #line 7847 - [TRAINER_LAURA] = + [DIFFICULTY_NORMAL][TRAINER_LAURA] = { #line 7848 .trainerName = _("LAURA"), @@ -19545,7 +19540,7 @@ F_TRAINER_FEMALE | }, }, #line 7860 - [TRAINER_CYNDY_1] = + [DIFFICULTY_NORMAL][TRAINER_CYNDY_1] = { #line 7861 .trainerName = _("CYNDY"), @@ -19590,7 +19585,7 @@ F_TRAINER_FEMALE | }, }, #line 7877 - [TRAINER_CORA] = + [DIFFICULTY_NORMAL][TRAINER_CORA] = { #line 7878 .trainerName = _("CORA"), @@ -19624,7 +19619,7 @@ F_TRAINER_FEMALE | }, }, #line 7890 - [TRAINER_PAULA] = + [DIFFICULTY_NORMAL][TRAINER_PAULA] = { #line 7891 .trainerName = _("PAULA"), @@ -19658,7 +19653,7 @@ F_TRAINER_FEMALE | }, }, #line 7903 - [TRAINER_CYNDY_2] = + [DIFFICULTY_NORMAL][TRAINER_CYNDY_2] = { #line 7904 .trainerName = _("CYNDY"), @@ -19703,7 +19698,7 @@ F_TRAINER_FEMALE | }, }, #line 7920 - [TRAINER_CYNDY_3] = + [DIFFICULTY_NORMAL][TRAINER_CYNDY_3] = { #line 7921 .trainerName = _("CYNDY"), @@ -19748,7 +19743,7 @@ F_TRAINER_FEMALE | }, }, #line 7937 - [TRAINER_CYNDY_4] = + [DIFFICULTY_NORMAL][TRAINER_CYNDY_4] = { #line 7938 .trainerName = _("CYNDY"), @@ -19793,7 +19788,7 @@ F_TRAINER_FEMALE | }, }, #line 7954 - [TRAINER_CYNDY_5] = + [DIFFICULTY_NORMAL][TRAINER_CYNDY_5] = { #line 7955 .trainerName = _("CYNDY"), @@ -19838,7 +19833,7 @@ F_TRAINER_FEMALE | }, }, #line 7971 - [TRAINER_MADELINE_1] = + [DIFFICULTY_NORMAL][TRAINER_MADELINE_1] = { #line 7972 .trainerName = _("MADELINE"), @@ -19879,7 +19874,7 @@ F_TRAINER_FEMALE | }, }, #line 7988 - [TRAINER_CLARISSA] = + [DIFFICULTY_NORMAL][TRAINER_CLARISSA] = { #line 7989 .trainerName = _("CLARISSA"), @@ -19924,7 +19919,7 @@ F_TRAINER_FEMALE | }, }, #line 8005 - [TRAINER_ANGELICA] = + [DIFFICULTY_NORMAL][TRAINER_ANGELICA] = { #line 8006 .trainerName = _("ANGELICA"), @@ -19965,7 +19960,7 @@ F_TRAINER_FEMALE | }, }, #line 8022 - [TRAINER_MADELINE_2] = + [DIFFICULTY_NORMAL][TRAINER_MADELINE_2] = { #line 8023 .trainerName = _("MADELINE"), @@ -20006,7 +20001,7 @@ F_TRAINER_FEMALE | }, }, #line 8039 - [TRAINER_MADELINE_3] = + [DIFFICULTY_NORMAL][TRAINER_MADELINE_3] = { #line 8040 .trainerName = _("MADELINE"), @@ -20047,7 +20042,7 @@ F_TRAINER_FEMALE | }, }, #line 8056 - [TRAINER_MADELINE_4] = + [DIFFICULTY_NORMAL][TRAINER_MADELINE_4] = { #line 8057 .trainerName = _("MADELINE"), @@ -20106,7 +20101,7 @@ F_TRAINER_FEMALE | }, }, #line 8081 - [TRAINER_MADELINE_5] = + [DIFFICULTY_NORMAL][TRAINER_MADELINE_5] = { #line 8082 .trainerName = _("MADELINE"), @@ -20165,7 +20160,7 @@ F_TRAINER_FEMALE | }, }, #line 8106 - [TRAINER_BEVERLY] = + [DIFFICULTY_NORMAL][TRAINER_BEVERLY] = { #line 8107 .trainerName = _("BEVERLY"), @@ -20210,7 +20205,7 @@ F_TRAINER_FEMALE | }, }, #line 8123 - [TRAINER_IMANI] = + [DIFFICULTY_NORMAL][TRAINER_IMANI] = { #line 8124 .trainerName = _("IMANI"), @@ -20244,7 +20239,7 @@ F_TRAINER_FEMALE | }, }, #line 8136 - [TRAINER_KYLA] = + [DIFFICULTY_NORMAL][TRAINER_KYLA] = { #line 8137 .trainerName = _("KYLA"), @@ -20278,7 +20273,7 @@ F_TRAINER_FEMALE | }, }, #line 8149 - [TRAINER_DENISE] = + [DIFFICULTY_NORMAL][TRAINER_DENISE] = { #line 8150 .trainerName = _("DENISE"), @@ -20323,7 +20318,7 @@ F_TRAINER_FEMALE | }, }, #line 8166 - [TRAINER_BETH] = + [DIFFICULTY_NORMAL][TRAINER_BETH] = { #line 8167 .trainerName = _("BETH"), @@ -20357,7 +20352,7 @@ F_TRAINER_FEMALE | }, }, #line 8179 - [TRAINER_TARA] = + [DIFFICULTY_NORMAL][TRAINER_TARA] = { #line 8180 .trainerName = _("TARA"), @@ -20402,7 +20397,7 @@ F_TRAINER_FEMALE | }, }, #line 8196 - [TRAINER_MISSY] = + [DIFFICULTY_NORMAL][TRAINER_MISSY] = { #line 8197 .trainerName = _("MISSY"), @@ -20436,7 +20431,7 @@ F_TRAINER_FEMALE | }, }, #line 8209 - [TRAINER_ALICE] = + [DIFFICULTY_NORMAL][TRAINER_ALICE] = { #line 8210 .trainerName = _("ALICE"), @@ -20492,7 +20487,7 @@ F_TRAINER_FEMALE | }, }, #line 8230 - [TRAINER_JENNY_1] = + [DIFFICULTY_NORMAL][TRAINER_JENNY_1] = { #line 8231 .trainerName = _("JENNY"), @@ -20526,7 +20521,7 @@ F_TRAINER_FEMALE | }, }, #line 8243 - [TRAINER_GRACE] = + [DIFFICULTY_NORMAL][TRAINER_GRACE] = { #line 8244 .trainerName = _("GRACE"), @@ -20560,7 +20555,7 @@ F_TRAINER_FEMALE | }, }, #line 8256 - [TRAINER_TANYA] = + [DIFFICULTY_NORMAL][TRAINER_TANYA] = { #line 8257 .trainerName = _("TANYA"), @@ -20594,7 +20589,7 @@ F_TRAINER_FEMALE | }, }, #line 8269 - [TRAINER_SHARON] = + [DIFFICULTY_NORMAL][TRAINER_SHARON] = { #line 8270 .trainerName = _("SHARON"), @@ -20628,7 +20623,7 @@ F_TRAINER_FEMALE | }, }, #line 8282 - [TRAINER_NIKKI] = + [DIFFICULTY_NORMAL][TRAINER_NIKKI] = { #line 8283 .trainerName = _("NIKKI"), @@ -20673,7 +20668,7 @@ F_TRAINER_FEMALE | }, }, #line 8299 - [TRAINER_BRENDA] = + [DIFFICULTY_NORMAL][TRAINER_BRENDA] = { #line 8300 .trainerName = _("BRENDA"), @@ -20707,7 +20702,7 @@ F_TRAINER_FEMALE | }, }, #line 8312 - [TRAINER_KATIE] = + [DIFFICULTY_NORMAL][TRAINER_KATIE] = { #line 8313 .trainerName = _("KATIE"), @@ -20752,7 +20747,7 @@ F_TRAINER_FEMALE | }, }, #line 8329 - [TRAINER_SUSIE] = + [DIFFICULTY_NORMAL][TRAINER_SUSIE] = { #line 8330 .trainerName = _("SUSIE"), @@ -20786,7 +20781,7 @@ F_TRAINER_FEMALE | }, }, #line 8342 - [TRAINER_KARA] = + [DIFFICULTY_NORMAL][TRAINER_KARA] = { #line 8343 .trainerName = _("KARA"), @@ -20820,7 +20815,7 @@ F_TRAINER_FEMALE | }, }, #line 8355 - [TRAINER_DANA] = + [DIFFICULTY_NORMAL][TRAINER_DANA] = { #line 8356 .trainerName = _("DANA"), @@ -20854,7 +20849,7 @@ F_TRAINER_FEMALE | }, }, #line 8368 - [TRAINER_SIENNA] = + [DIFFICULTY_NORMAL][TRAINER_SIENNA] = { #line 8369 .trainerName = _("SIENNA"), @@ -20899,7 +20894,7 @@ F_TRAINER_FEMALE | }, }, #line 8385 - [TRAINER_DEBRA] = + [DIFFICULTY_NORMAL][TRAINER_DEBRA] = { #line 8386 .trainerName = _("DEBRA"), @@ -20933,7 +20928,7 @@ F_TRAINER_FEMALE | }, }, #line 8398 - [TRAINER_LINDA] = + [DIFFICULTY_NORMAL][TRAINER_LINDA] = { #line 8399 .trainerName = _("LINDA"), @@ -20978,7 +20973,7 @@ F_TRAINER_FEMALE | }, }, #line 8415 - [TRAINER_KAYLEE] = + [DIFFICULTY_NORMAL][TRAINER_KAYLEE] = { #line 8416 .trainerName = _("KAYLEE"), @@ -21023,7 +21018,7 @@ F_TRAINER_FEMALE | }, }, #line 8432 - [TRAINER_LAUREL] = + [DIFFICULTY_NORMAL][TRAINER_LAUREL] = { #line 8433 .trainerName = _("LAUREL"), @@ -21068,7 +21063,7 @@ F_TRAINER_FEMALE | }, }, #line 8449 - [TRAINER_CARLEE] = + [DIFFICULTY_NORMAL][TRAINER_CARLEE] = { #line 8450 .trainerName = _("CARLEE"), @@ -21102,7 +21097,7 @@ F_TRAINER_FEMALE | }, }, #line 8462 - [TRAINER_JENNY_2] = + [DIFFICULTY_NORMAL][TRAINER_JENNY_2] = { #line 8463 .trainerName = _("JENNY"), @@ -21136,7 +21131,7 @@ F_TRAINER_FEMALE | }, }, #line 8475 - [TRAINER_JENNY_3] = + [DIFFICULTY_NORMAL][TRAINER_JENNY_3] = { #line 8476 .trainerName = _("JENNY"), @@ -21170,7 +21165,7 @@ F_TRAINER_FEMALE | }, }, #line 8488 - [TRAINER_JENNY_4] = + [DIFFICULTY_NORMAL][TRAINER_JENNY_4] = { #line 8489 .trainerName = _("JENNY"), @@ -21215,7 +21210,7 @@ F_TRAINER_FEMALE | }, }, #line 8505 - [TRAINER_JENNY_5] = + [DIFFICULTY_NORMAL][TRAINER_JENNY_5] = { #line 8506 .trainerName = _("JENNY"), @@ -21271,7 +21266,7 @@ F_TRAINER_FEMALE | }, }, #line 8526 - [TRAINER_HEIDI] = + [DIFFICULTY_NORMAL][TRAINER_HEIDI] = { #line 8527 .trainerName = _("HEIDI"), @@ -21330,7 +21325,7 @@ F_TRAINER_FEMALE | }, }, #line 8551 - [TRAINER_BECKY] = + [DIFFICULTY_NORMAL][TRAINER_BECKY] = { #line 8552 .trainerName = _("BECKY"), @@ -21389,7 +21384,7 @@ F_TRAINER_FEMALE | }, }, #line 8576 - [TRAINER_CAROL] = + [DIFFICULTY_NORMAL][TRAINER_CAROL] = { #line 8577 .trainerName = _("CAROL"), @@ -21434,7 +21429,7 @@ F_TRAINER_FEMALE | }, }, #line 8593 - [TRAINER_NANCY] = + [DIFFICULTY_NORMAL][TRAINER_NANCY] = { #line 8594 .trainerName = _("NANCY"), @@ -21479,7 +21474,7 @@ F_TRAINER_FEMALE | }, }, #line 8610 - [TRAINER_MARTHA] = + [DIFFICULTY_NORMAL][TRAINER_MARTHA] = { #line 8611 .trainerName = _("MARTHA"), @@ -21524,7 +21519,7 @@ F_TRAINER_FEMALE | }, }, #line 8627 - [TRAINER_DIANA_1] = + [DIFFICULTY_NORMAL][TRAINER_DIANA_1] = { #line 8628 .trainerName = _("DIANA"), @@ -21580,7 +21575,7 @@ F_TRAINER_FEMALE | }, }, #line 8648 - [TRAINER_CEDRIC] = + [DIFFICULTY_NORMAL][TRAINER_CEDRIC] = { #line 8649 .trainerName = _("CEDRIC"), @@ -21619,7 +21614,7 @@ F_TRAINER_FEMALE | }, }, #line 8665 - [TRAINER_IRENE] = + [DIFFICULTY_NORMAL][TRAINER_IRENE] = { #line 8666 .trainerName = _("IRENE"), @@ -21664,7 +21659,7 @@ F_TRAINER_FEMALE | }, }, #line 8682 - [TRAINER_DIANA_2] = + [DIFFICULTY_NORMAL][TRAINER_DIANA_2] = { #line 8683 .trainerName = _("DIANA"), @@ -21720,7 +21715,7 @@ F_TRAINER_FEMALE | }, }, #line 8703 - [TRAINER_DIANA_3] = + [DIFFICULTY_NORMAL][TRAINER_DIANA_3] = { #line 8704 .trainerName = _("DIANA"), @@ -21776,7 +21771,7 @@ F_TRAINER_FEMALE | }, }, #line 8724 - [TRAINER_DIANA_4] = + [DIFFICULTY_NORMAL][TRAINER_DIANA_4] = { #line 8725 .trainerName = _("DIANA"), @@ -21832,7 +21827,7 @@ F_TRAINER_FEMALE | }, }, #line 8745 - [TRAINER_DIANA_5] = + [DIFFICULTY_NORMAL][TRAINER_DIANA_5] = { #line 8746 .trainerName = _("DIANA"), @@ -21888,7 +21883,7 @@ F_TRAINER_FEMALE | }, }, #line 8766 - [TRAINER_AMY_AND_LIV_1] = + [DIFFICULTY_NORMAL][TRAINER_AMY_AND_LIV_1] = { #line 8767 .trainerName = _("AMY & LIV"), @@ -21931,7 +21926,7 @@ F_TRAINER_FEMALE | }, }, #line 8783 - [TRAINER_AMY_AND_LIV_2] = + [DIFFICULTY_NORMAL][TRAINER_AMY_AND_LIV_2] = { #line 8784 .trainerName = _("AMY & LIV"), @@ -21974,7 +21969,7 @@ F_TRAINER_FEMALE | }, }, #line 8800 - [TRAINER_GINA_AND_MIA_1] = + [DIFFICULTY_NORMAL][TRAINER_GINA_AND_MIA_1] = { #line 8801 .trainerName = _("GINA & MIA"), @@ -22017,7 +22012,7 @@ F_TRAINER_FEMALE | }, }, #line 8817 - [TRAINER_MIU_AND_YUKI] = + [DIFFICULTY_NORMAL][TRAINER_MIU_AND_YUKI] = { #line 8818 .trainerName = _("MIU & YUKI"), @@ -22060,7 +22055,7 @@ F_TRAINER_FEMALE | }, }, #line 8834 - [TRAINER_AMY_AND_LIV_3] = + [DIFFICULTY_NORMAL][TRAINER_AMY_AND_LIV_3] = { #line 8835 .trainerName = _("AMY & LIV"), @@ -22103,7 +22098,7 @@ F_TRAINER_FEMALE | }, }, #line 8851 - [TRAINER_GINA_AND_MIA_2] = + [DIFFICULTY_NORMAL][TRAINER_GINA_AND_MIA_2] = { #line 8852 .trainerName = _("GINA & MIA"), @@ -22156,7 +22151,7 @@ F_TRAINER_FEMALE | }, }, #line 8872 - [TRAINER_AMY_AND_LIV_4] = + [DIFFICULTY_NORMAL][TRAINER_AMY_AND_LIV_4] = { #line 8873 .trainerName = _("AMY & LIV"), @@ -22199,7 +22194,7 @@ F_TRAINER_FEMALE | }, }, #line 8889 - [TRAINER_AMY_AND_LIV_5] = + [DIFFICULTY_NORMAL][TRAINER_AMY_AND_LIV_5] = { #line 8890 .trainerName = _("AMY & LIV"), @@ -22256,7 +22251,7 @@ F_TRAINER_FEMALE | }, }, #line 8914 - [TRAINER_AMY_AND_LIV_6] = + [DIFFICULTY_NORMAL][TRAINER_AMY_AND_LIV_6] = { #line 8915 .trainerName = _("AMY & LIV"), @@ -22313,7 +22308,7 @@ F_TRAINER_FEMALE | }, }, #line 8939 - [TRAINER_HUEY] = + [DIFFICULTY_NORMAL][TRAINER_HUEY] = { #line 8940 .trainerName = _("HUEY"), @@ -22356,7 +22351,7 @@ F_TRAINER_FEMALE | }, }, #line 8956 - [TRAINER_EDMOND] = + [DIFFICULTY_NORMAL][TRAINER_EDMOND] = { #line 8957 .trainerName = _("EDMOND"), @@ -22388,7 +22383,7 @@ F_TRAINER_FEMALE | }, }, #line 8969 - [TRAINER_ERNEST_1] = + [DIFFICULTY_NORMAL][TRAINER_ERNEST_1] = { #line 8970 .trainerName = _("ERNEST"), @@ -22431,7 +22426,7 @@ F_TRAINER_FEMALE | }, }, #line 8986 - [TRAINER_DWAYNE] = + [DIFFICULTY_NORMAL][TRAINER_DWAYNE] = { #line 8987 .trainerName = _("DWAYNE"), @@ -22485,7 +22480,7 @@ F_TRAINER_FEMALE | }, }, #line 9007 - [TRAINER_PHILLIP] = + [DIFFICULTY_NORMAL][TRAINER_PHILLIP] = { #line 9008 .trainerName = _("PHILLIP"), @@ -22528,7 +22523,7 @@ F_TRAINER_FEMALE | }, }, #line 9024 - [TRAINER_LEONARD] = + [DIFFICULTY_NORMAL][TRAINER_LEONARD] = { #line 9025 .trainerName = _("LEONARD"), @@ -22582,7 +22577,7 @@ F_TRAINER_FEMALE | }, }, #line 9045 - [TRAINER_DUNCAN] = + [DIFFICULTY_NORMAL][TRAINER_DUNCAN] = { #line 9046 .trainerName = _("DUNCAN"), @@ -22625,7 +22620,7 @@ F_TRAINER_FEMALE | }, }, #line 9062 - [TRAINER_ERNEST_2] = + [DIFFICULTY_NORMAL][TRAINER_ERNEST_2] = { #line 9063 .trainerName = _("ERNEST"), @@ -22679,7 +22674,7 @@ F_TRAINER_FEMALE | }, }, #line 9083 - [TRAINER_ERNEST_3] = + [DIFFICULTY_NORMAL][TRAINER_ERNEST_3] = { #line 9084 .trainerName = _("ERNEST"), @@ -22733,7 +22728,7 @@ F_TRAINER_FEMALE | }, }, #line 9104 - [TRAINER_ERNEST_4] = + [DIFFICULTY_NORMAL][TRAINER_ERNEST_4] = { #line 9105 .trainerName = _("ERNEST"), @@ -22787,7 +22782,7 @@ F_TRAINER_FEMALE | }, }, #line 9125 - [TRAINER_ERNEST_5] = + [DIFFICULTY_NORMAL][TRAINER_ERNEST_5] = { #line 9126 .trainerName = _("ERNEST"), @@ -22841,7 +22836,7 @@ F_TRAINER_FEMALE | }, }, #line 9146 - [TRAINER_ELI] = + [DIFFICULTY_NORMAL][TRAINER_ELI] = { #line 9147 .trainerName = _("ELI"), @@ -22873,7 +22868,7 @@ F_TRAINER_FEMALE | }, }, #line 9159 - [TRAINER_ANNIKA] = + [DIFFICULTY_NORMAL][TRAINER_ANNIKA] = { #line 9160 .trainerName = _("ANNIKA"), @@ -22936,7 +22931,7 @@ F_TRAINER_FEMALE | }, }, #line 9184 - [TRAINER_JAZMYN] = + [DIFFICULTY_NORMAL][TRAINER_JAZMYN] = { #line 9185 .trainerName = _("JAZMYN"), @@ -22972,7 +22967,7 @@ F_TRAINER_FEMALE | }, }, #line 9198 - [TRAINER_JONAS] = + [DIFFICULTY_NORMAL][TRAINER_JONAS] = { #line 9199 .trainerName = _("JONAS"), @@ -23011,7 +23006,7 @@ F_TRAINER_FEMALE | }, }, #line 9215 - [TRAINER_KAYLEY] = + [DIFFICULTY_NORMAL][TRAINER_KAYLEY] = { #line 9216 .trainerName = _("KAYLEY"), @@ -23052,7 +23047,7 @@ F_TRAINER_FEMALE | }, }, #line 9232 - [TRAINER_AURON] = + [DIFFICULTY_NORMAL][TRAINER_AURON] = { #line 9233 .trainerName = _("AURON"), @@ -23095,7 +23090,7 @@ F_TRAINER_FEMALE | }, }, #line 9249 - [TRAINER_KELVIN] = + [DIFFICULTY_NORMAL][TRAINER_KELVIN] = { #line 9250 .trainerName = _("KELVIN"), @@ -23138,7 +23133,7 @@ F_TRAINER_FEMALE | }, }, #line 9266 - [TRAINER_MARLEY] = + [DIFFICULTY_NORMAL][TRAINER_MARLEY] = { #line 9267 .trainerName = _("MARLEY"), @@ -23181,7 +23176,7 @@ F_TRAINER_FEMALE | }, }, #line 9284 - [TRAINER_REYNA] = + [DIFFICULTY_NORMAL][TRAINER_REYNA] = { #line 9285 .trainerName = _("REYNA"), @@ -23226,7 +23221,7 @@ F_TRAINER_FEMALE | }, }, #line 9301 - [TRAINER_HUDSON] = + [DIFFICULTY_NORMAL][TRAINER_HUDSON] = { #line 9302 .trainerName = _("HUDSON"), @@ -23258,7 +23253,7 @@ F_TRAINER_FEMALE | }, }, #line 9314 - [TRAINER_CONOR] = + [DIFFICULTY_NORMAL][TRAINER_CONOR] = { #line 9315 .trainerName = _("CONOR"), @@ -23301,7 +23296,7 @@ F_TRAINER_FEMALE | }, }, #line 9331 - [TRAINER_EDWIN_1] = + [DIFFICULTY_NORMAL][TRAINER_EDWIN_1] = { #line 9332 .trainerName = _("EDWIN"), @@ -23344,7 +23339,7 @@ F_TRAINER_FEMALE | }, }, #line 9348 - [TRAINER_HECTOR] = + [DIFFICULTY_NORMAL][TRAINER_HECTOR] = { #line 9349 .trainerName = _("HECTOR"), @@ -23387,7 +23382,7 @@ F_TRAINER_FEMALE | }, }, #line 9365 - [TRAINER_TABITHA_MOSSDEEP] = + [DIFFICULTY_NORMAL][TRAINER_TABITHA_MOSSDEEP] = { #line 9366 .trainerName = _("TABITHA"), @@ -23441,7 +23436,7 @@ F_TRAINER_FEMALE | }, }, #line 9386 - [TRAINER_EDWIN_2] = + [DIFFICULTY_NORMAL][TRAINER_EDWIN_2] = { #line 9387 .trainerName = _("EDWIN"), @@ -23484,7 +23479,7 @@ F_TRAINER_FEMALE | }, }, #line 9403 - [TRAINER_EDWIN_3] = + [DIFFICULTY_NORMAL][TRAINER_EDWIN_3] = { #line 9404 .trainerName = _("EDWIN"), @@ -23527,7 +23522,7 @@ F_TRAINER_FEMALE | }, }, #line 9420 - [TRAINER_EDWIN_4] = + [DIFFICULTY_NORMAL][TRAINER_EDWIN_4] = { #line 9421 .trainerName = _("EDWIN"), @@ -23570,7 +23565,7 @@ F_TRAINER_FEMALE | }, }, #line 9437 - [TRAINER_EDWIN_5] = + [DIFFICULTY_NORMAL][TRAINER_EDWIN_5] = { #line 9438 .trainerName = _("EDWIN"), @@ -23613,7 +23608,7 @@ F_TRAINER_FEMALE | }, }, #line 9454 - [TRAINER_WALLY_VR_1] = + [DIFFICULTY_NORMAL][TRAINER_WALLY_VR_1] = { #line 9455 .trainerName = _("WALLY"), @@ -23726,7 +23721,7 @@ F_TRAINER_FEMALE | }, }, #line 9504 - [TRAINER_BRENDAN_ROUTE_103_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_103_MUDKIP] = { #line 9505 .trainerName = _("BRENDAN"), @@ -23758,7 +23753,7 @@ F_TRAINER_FEMALE | }, }, #line 9517 - [TRAINER_BRENDAN_ROUTE_110_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_110_MUDKIP] = { #line 9518 .trainerName = _("BRENDAN"), @@ -23812,7 +23807,7 @@ F_TRAINER_FEMALE | }, }, #line 9538 - [TRAINER_BRENDAN_ROUTE_119_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_119_MUDKIP] = { #line 9539 .trainerName = _("BRENDAN"), @@ -23866,7 +23861,7 @@ F_TRAINER_FEMALE | }, }, #line 9559 - [TRAINER_BRENDAN_ROUTE_103_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_103_TREECKO] = { #line 9560 .trainerName = _("BRENDAN"), @@ -23898,7 +23893,7 @@ F_TRAINER_FEMALE | }, }, #line 9572 - [TRAINER_BRENDAN_ROUTE_110_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_110_TREECKO] = { #line 9573 .trainerName = _("BRENDAN"), @@ -23952,7 +23947,7 @@ F_TRAINER_FEMALE | }, }, #line 9593 - [TRAINER_BRENDAN_ROUTE_119_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_119_TREECKO] = { #line 9594 .trainerName = _("BRENDAN"), @@ -24006,7 +24001,7 @@ F_TRAINER_FEMALE | }, }, #line 9614 - [TRAINER_BRENDAN_ROUTE_103_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_103_TORCHIC] = { #line 9615 .trainerName = _("BRENDAN"), @@ -24038,7 +24033,7 @@ F_TRAINER_FEMALE | }, }, #line 9627 - [TRAINER_BRENDAN_ROUTE_110_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_110_TORCHIC] = { #line 9628 .trainerName = _("BRENDAN"), @@ -24092,7 +24087,7 @@ F_TRAINER_FEMALE | }, }, #line 9648 - [TRAINER_BRENDAN_ROUTE_119_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_ROUTE_119_TORCHIC] = { #line 9649 .trainerName = _("BRENDAN"), @@ -24146,7 +24141,7 @@ F_TRAINER_FEMALE | }, }, #line 9669 - [TRAINER_MAY_ROUTE_103_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_103_MUDKIP] = { #line 9670 .trainerName = _("MAY"), @@ -24180,7 +24175,7 @@ F_TRAINER_FEMALE | }, }, #line 9682 - [TRAINER_MAY_ROUTE_110_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_110_MUDKIP] = { #line 9683 .trainerName = _("MAY"), @@ -24236,7 +24231,7 @@ F_TRAINER_FEMALE | }, }, #line 9703 - [TRAINER_MAY_ROUTE_119_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_119_MUDKIP] = { #line 9704 .trainerName = _("MAY"), @@ -24292,7 +24287,7 @@ F_TRAINER_FEMALE | }, }, #line 9724 - [TRAINER_MAY_ROUTE_103_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_103_TREECKO] = { #line 9725 .trainerName = _("MAY"), @@ -24326,7 +24321,7 @@ F_TRAINER_FEMALE | }, }, #line 9737 - [TRAINER_MAY_ROUTE_110_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_110_TREECKO] = { #line 9738 .trainerName = _("MAY"), @@ -24382,7 +24377,7 @@ F_TRAINER_FEMALE | }, }, #line 9758 - [TRAINER_MAY_ROUTE_119_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_119_TREECKO] = { #line 9759 .trainerName = _("MAY"), @@ -24438,7 +24433,7 @@ F_TRAINER_FEMALE | }, }, #line 9779 - [TRAINER_MAY_ROUTE_103_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_103_TORCHIC] = { #line 9780 .trainerName = _("MAY"), @@ -24472,7 +24467,7 @@ F_TRAINER_FEMALE | }, }, #line 9792 - [TRAINER_MAY_ROUTE_110_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_110_TORCHIC] = { #line 9793 .trainerName = _("MAY"), @@ -24528,7 +24523,7 @@ F_TRAINER_FEMALE | }, }, #line 9813 - [TRAINER_MAY_ROUTE_119_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_MAY_ROUTE_119_TORCHIC] = { #line 9814 .trainerName = _("MAY"), @@ -24584,7 +24579,7 @@ F_TRAINER_FEMALE | }, }, #line 9834 - [TRAINER_ISAAC_1] = + [DIFFICULTY_NORMAL][TRAINER_ISAAC_1] = { #line 9835 .trainerName = _("ISAAC"), @@ -24671,7 +24666,7 @@ F_TRAINER_FEMALE | }, }, #line 9867 - [TRAINER_DAVIS] = + [DIFFICULTY_NORMAL][TRAINER_DAVIS] = { #line 9868 .trainerName = _("DAVIS"), @@ -24703,7 +24698,7 @@ F_TRAINER_FEMALE | }, }, #line 9880 - [TRAINER_MITCHELL] = + [DIFFICULTY_NORMAL][TRAINER_MITCHELL] = { #line 9881 .trainerName = _("MITCHELL"), @@ -24760,7 +24755,7 @@ F_TRAINER_FEMALE | }, }, #line 9905 - [TRAINER_ISAAC_2] = + [DIFFICULTY_NORMAL][TRAINER_ISAAC_2] = { #line 9906 .trainerName = _("ISAAC"), @@ -24847,7 +24842,7 @@ F_TRAINER_FEMALE | }, }, #line 9938 - [TRAINER_ISAAC_3] = + [DIFFICULTY_NORMAL][TRAINER_ISAAC_3] = { #line 9939 .trainerName = _("ISAAC"), @@ -24934,7 +24929,7 @@ F_TRAINER_FEMALE | }, }, #line 9971 - [TRAINER_ISAAC_4] = + [DIFFICULTY_NORMAL][TRAINER_ISAAC_4] = { #line 9972 .trainerName = _("ISAAC"), @@ -25021,7 +25016,7 @@ F_TRAINER_FEMALE | }, }, #line 10004 - [TRAINER_ISAAC_5] = + [DIFFICULTY_NORMAL][TRAINER_ISAAC_5] = { #line 10005 .trainerName = _("ISAAC"), @@ -25108,7 +25103,7 @@ F_TRAINER_FEMALE | }, }, #line 10037 - [TRAINER_LYDIA_1] = + [DIFFICULTY_NORMAL][TRAINER_LYDIA_1] = { #line 10038 .trainerName = _("LYDIA"), @@ -25197,7 +25192,7 @@ F_TRAINER_FEMALE | }, }, #line 10070 - [TRAINER_HALLE] = + [DIFFICULTY_NORMAL][TRAINER_HALLE] = { #line 10071 .trainerName = _("HALLE"), @@ -25244,7 +25239,7 @@ F_TRAINER_FEMALE | }, }, #line 10088 - [TRAINER_GARRISON] = + [DIFFICULTY_NORMAL][TRAINER_GARRISON] = { #line 10089 .trainerName = _("GARRISON"), @@ -25276,7 +25271,7 @@ F_TRAINER_FEMALE | }, }, #line 10101 - [TRAINER_LYDIA_2] = + [DIFFICULTY_NORMAL][TRAINER_LYDIA_2] = { #line 10102 .trainerName = _("LYDIA"), @@ -25365,7 +25360,7 @@ F_TRAINER_FEMALE | }, }, #line 10134 - [TRAINER_LYDIA_3] = + [DIFFICULTY_NORMAL][TRAINER_LYDIA_3] = { #line 10135 .trainerName = _("LYDIA"), @@ -25454,7 +25449,7 @@ F_TRAINER_FEMALE | }, }, #line 10167 - [TRAINER_LYDIA_4] = + [DIFFICULTY_NORMAL][TRAINER_LYDIA_4] = { #line 10168 .trainerName = _("LYDIA"), @@ -25543,7 +25538,7 @@ F_TRAINER_FEMALE | }, }, #line 10200 - [TRAINER_LYDIA_5] = + [DIFFICULTY_NORMAL][TRAINER_LYDIA_5] = { #line 10201 .trainerName = _("LYDIA"), @@ -25632,7 +25627,7 @@ F_TRAINER_FEMALE | }, }, #line 10233 - [TRAINER_JACKSON_1] = + [DIFFICULTY_NORMAL][TRAINER_JACKSON_1] = { #line 10234 .trainerName = _("JACKSON"), @@ -25666,7 +25661,7 @@ F_TRAINER_FEMALE | }, }, #line 10247 - [TRAINER_LORENZO] = + [DIFFICULTY_NORMAL][TRAINER_LORENZO] = { #line 10248 .trainerName = _("LORENZO"), @@ -25722,7 +25717,7 @@ F_TRAINER_FEMALE | }, }, #line 10269 - [TRAINER_SEBASTIAN] = + [DIFFICULTY_NORMAL][TRAINER_SEBASTIAN] = { #line 10270 .trainerName = _("SEBASTIAN"), @@ -25756,7 +25751,7 @@ F_TRAINER_FEMALE | }, }, #line 10283 - [TRAINER_JACKSON_2] = + [DIFFICULTY_NORMAL][TRAINER_JACKSON_2] = { #line 10284 .trainerName = _("JACKSON"), @@ -25790,7 +25785,7 @@ F_TRAINER_FEMALE | }, }, #line 10297 - [TRAINER_JACKSON_3] = + [DIFFICULTY_NORMAL][TRAINER_JACKSON_3] = { #line 10298 .trainerName = _("JACKSON"), @@ -25824,7 +25819,7 @@ F_TRAINER_FEMALE | }, }, #line 10311 - [TRAINER_JACKSON_4] = + [DIFFICULTY_NORMAL][TRAINER_JACKSON_4] = { #line 10312 .trainerName = _("JACKSON"), @@ -25858,7 +25853,7 @@ F_TRAINER_FEMALE | }, }, #line 10325 - [TRAINER_JACKSON_5] = + [DIFFICULTY_NORMAL][TRAINER_JACKSON_5] = { #line 10326 .trainerName = _("JACKSON"), @@ -25903,7 +25898,7 @@ F_TRAINER_FEMALE | }, }, #line 10343 - [TRAINER_CATHERINE_1] = + [DIFFICULTY_NORMAL][TRAINER_CATHERINE_1] = { #line 10344 .trainerName = _("CATHERINE"), @@ -25950,7 +25945,7 @@ F_TRAINER_FEMALE | }, }, #line 10361 - [TRAINER_JENNA] = + [DIFFICULTY_NORMAL][TRAINER_JENNA] = { #line 10362 .trainerName = _("JENNA"), @@ -26008,7 +26003,7 @@ F_TRAINER_FEMALE | }, }, #line 10383 - [TRAINER_SOPHIA] = + [DIFFICULTY_NORMAL][TRAINER_SOPHIA] = { #line 10384 .trainerName = _("SOPHIA"), @@ -26055,7 +26050,7 @@ F_TRAINER_FEMALE | }, }, #line 10401 - [TRAINER_CATHERINE_2] = + [DIFFICULTY_NORMAL][TRAINER_CATHERINE_2] = { #line 10402 .trainerName = _("CATHERINE"), @@ -26102,7 +26097,7 @@ F_TRAINER_FEMALE | }, }, #line 10419 - [TRAINER_CATHERINE_3] = + [DIFFICULTY_NORMAL][TRAINER_CATHERINE_3] = { #line 10420 .trainerName = _("CATHERINE"), @@ -26149,7 +26144,7 @@ F_TRAINER_FEMALE | }, }, #line 10437 - [TRAINER_CATHERINE_4] = + [DIFFICULTY_NORMAL][TRAINER_CATHERINE_4] = { #line 10438 .trainerName = _("CATHERINE"), @@ -26196,7 +26191,7 @@ F_TRAINER_FEMALE | }, }, #line 10455 - [TRAINER_CATHERINE_5] = + [DIFFICULTY_NORMAL][TRAINER_CATHERINE_5] = { #line 10456 .trainerName = _("CATHERINE"), @@ -26243,7 +26238,7 @@ F_TRAINER_FEMALE | }, }, #line 10473 - [TRAINER_JULIO] = + [DIFFICULTY_NORMAL][TRAINER_JULIO] = { #line 10474 .trainerName = _("JULIO"), @@ -26275,7 +26270,7 @@ F_TRAINER_FEMALE | }, }, #line 10486 - [TRAINER_GRUNT_SEAFLOOR_CAVERN_5] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SEAFLOOR_CAVERN_5] = { #line 10487 .trainerName = _("GRUNT"), @@ -26318,7 +26313,7 @@ F_TRAINER_FEMALE | }, }, #line 10503 - [TRAINER_GRUNT_UNUSED] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_UNUSED] = { #line 10504 .trainerName = _("GRUNT"), @@ -26363,7 +26358,7 @@ F_TRAINER_FEMALE | }, }, #line 10520 - [TRAINER_GRUNT_MT_PYRE_4] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MT_PYRE_4] = { #line 10521 .trainerName = _("GRUNT"), @@ -26408,7 +26403,7 @@ F_TRAINER_FEMALE | }, }, #line 10537 - [TRAINER_GRUNT_JAGGED_PASS] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_JAGGED_PASS] = { #line 10538 .trainerName = _("GRUNT"), @@ -26451,7 +26446,7 @@ F_TRAINER_FEMALE | }, }, #line 10554 - [TRAINER_MARC] = + [DIFFICULTY_NORMAL][TRAINER_MARC] = { #line 10555 .trainerName = _("MARC"), @@ -26494,7 +26489,7 @@ F_TRAINER_FEMALE | }, }, #line 10571 - [TRAINER_BRENDEN] = + [DIFFICULTY_NORMAL][TRAINER_BRENDEN] = { #line 10572 .trainerName = _("BRENDEN"), @@ -26526,7 +26521,7 @@ F_TRAINER_FEMALE | }, }, #line 10584 - [TRAINER_LILITH] = + [DIFFICULTY_NORMAL][TRAINER_LILITH] = { #line 10585 .trainerName = _("LILITH"), @@ -26560,7 +26555,7 @@ F_TRAINER_FEMALE | }, }, #line 10597 - [TRAINER_CRISTIAN] = + [DIFFICULTY_NORMAL][TRAINER_CRISTIAN] = { #line 10598 .trainerName = _("CRISTIAN"), @@ -26592,7 +26587,7 @@ F_TRAINER_FEMALE | }, }, #line 10610 - [TRAINER_SYLVIA] = + [DIFFICULTY_NORMAL][TRAINER_SYLVIA] = { #line 10611 .trainerName = _("SYLVIA"), @@ -26626,7 +26621,7 @@ F_TRAINER_FEMALE | }, }, #line 10623 - [TRAINER_LEONARDO] = + [DIFFICULTY_NORMAL][TRAINER_LEONARDO] = { #line 10624 .trainerName = _("LEONARDO"), @@ -26658,7 +26653,7 @@ F_TRAINER_FEMALE | }, }, #line 10636 - [TRAINER_ATHENA] = + [DIFFICULTY_NORMAL][TRAINER_ATHENA] = { #line 10637 .trainerName = _("ATHENA"), @@ -26716,7 +26711,7 @@ F_TRAINER_FEMALE | }, }, #line 10659 - [TRAINER_HARRISON] = + [DIFFICULTY_NORMAL][TRAINER_HARRISON] = { #line 10660 .trainerName = _("HARRISON"), @@ -26748,7 +26743,7 @@ F_TRAINER_FEMALE | }, }, #line 10672 - [TRAINER_GRUNT_MT_CHIMNEY_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MT_CHIMNEY_2] = { #line 10673 .trainerName = _("GRUNT"), @@ -26780,7 +26775,7 @@ F_TRAINER_FEMALE | }, }, #line 10685 - [TRAINER_CLARENCE] = + [DIFFICULTY_NORMAL][TRAINER_CLARENCE] = { #line 10686 .trainerName = _("CLARENCE"), @@ -26812,7 +26807,7 @@ F_TRAINER_FEMALE | }, }, #line 10698 - [TRAINER_TERRY] = + [DIFFICULTY_NORMAL][TRAINER_TERRY] = { #line 10699 .trainerName = _("TERRY"), @@ -26846,7 +26841,7 @@ F_TRAINER_FEMALE | }, }, #line 10711 - [TRAINER_NATE] = + [DIFFICULTY_NORMAL][TRAINER_NATE] = { #line 10712 .trainerName = _("NATE"), @@ -26878,7 +26873,7 @@ F_TRAINER_FEMALE | }, }, #line 10724 - [TRAINER_KATHLEEN] = + [DIFFICULTY_NORMAL][TRAINER_KATHLEEN] = { #line 10725 .trainerName = _("KATHLEEN"), @@ -26912,7 +26907,7 @@ F_TRAINER_FEMALE | }, }, #line 10737 - [TRAINER_CLIFFORD] = + [DIFFICULTY_NORMAL][TRAINER_CLIFFORD] = { #line 10738 .trainerName = _("CLIFFORD"), @@ -26944,7 +26939,7 @@ F_TRAINER_FEMALE | }, }, #line 10750 - [TRAINER_NICHOLAS] = + [DIFFICULTY_NORMAL][TRAINER_NICHOLAS] = { #line 10751 .trainerName = _("NICHOLAS"), @@ -26976,7 +26971,7 @@ F_TRAINER_FEMALE | }, }, #line 10763 - [TRAINER_GRUNT_SPACE_CENTER_3] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_3] = { #line 10764 .trainerName = _("GRUNT"), @@ -27021,7 +27016,7 @@ F_TRAINER_FEMALE | }, }, #line 10780 - [TRAINER_GRUNT_SPACE_CENTER_4] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_4] = { #line 10781 .trainerName = _("GRUNT"), @@ -27053,7 +27048,7 @@ F_TRAINER_FEMALE | }, }, #line 10793 - [TRAINER_GRUNT_SPACE_CENTER_5] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_5] = { #line 10794 .trainerName = _("GRUNT"), @@ -27085,7 +27080,7 @@ F_TRAINER_FEMALE | }, }, #line 10806 - [TRAINER_GRUNT_SPACE_CENTER_6] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_6] = { #line 10807 .trainerName = _("GRUNT"), @@ -27117,7 +27112,7 @@ F_TRAINER_FEMALE | }, }, #line 10819 - [TRAINER_GRUNT_SPACE_CENTER_7] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_SPACE_CENTER_7] = { #line 10820 .trainerName = _("GRUNT"), @@ -27149,7 +27144,7 @@ F_TRAINER_FEMALE | }, }, #line 10832 - [TRAINER_MACEY] = + [DIFFICULTY_NORMAL][TRAINER_MACEY] = { #line 10833 .trainerName = _("MACEY"), @@ -27183,7 +27178,7 @@ F_TRAINER_FEMALE | }, }, #line 10845 - [TRAINER_BRENDAN_RUSTBORO_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_RUSTBORO_TREECKO] = { #line 10846 .trainerName = _("BRENDAN"), @@ -27226,7 +27221,7 @@ F_TRAINER_FEMALE | }, }, #line 10862 - [TRAINER_BRENDAN_RUSTBORO_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_RUSTBORO_MUDKIP] = { #line 10863 .trainerName = _("BRENDAN"), @@ -27269,7 +27264,7 @@ F_TRAINER_FEMALE | }, }, #line 10879 - [TRAINER_PAXTON] = + [DIFFICULTY_NORMAL][TRAINER_PAXTON] = { #line 10880 .trainerName = _("PAXTON"), @@ -27312,7 +27307,7 @@ F_TRAINER_FEMALE | }, }, #line 10896 - [TRAINER_ISABELLA] = + [DIFFICULTY_NORMAL][TRAINER_ISABELLA] = { #line 10897 .trainerName = _("ISABELLA"), @@ -27346,7 +27341,7 @@ F_TRAINER_FEMALE | }, }, #line 10909 - [TRAINER_GRUNT_WEATHER_INST_5] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_WEATHER_INST_5] = { #line 10910 .trainerName = _("GRUNT"), @@ -27391,7 +27386,7 @@ F_TRAINER_FEMALE | }, }, #line 10926 - [TRAINER_TABITHA_MT_CHIMNEY] = + [DIFFICULTY_NORMAL][TRAINER_TABITHA_MT_CHIMNEY] = { #line 10927 .trainerName = _("TABITHA"), @@ -27456,7 +27451,7 @@ F_TRAINER_FEMALE | }, }, #line 10951 - [TRAINER_JONATHAN] = + [DIFFICULTY_NORMAL][TRAINER_JONATHAN] = { #line 10952 .trainerName = _("JONATHAN"), @@ -27501,7 +27496,7 @@ F_TRAINER_FEMALE | }, }, #line 10969 - [TRAINER_BRENDAN_RUSTBORO_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_RUSTBORO_TORCHIC] = { #line 10970 .trainerName = _("BRENDAN"), @@ -27544,7 +27539,7 @@ F_TRAINER_FEMALE | }, }, #line 10986 - [TRAINER_MAY_RUSTBORO_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_MAY_RUSTBORO_MUDKIP] = { #line 10987 .trainerName = _("MAY"), @@ -27589,7 +27584,7 @@ F_TRAINER_FEMALE | }, }, #line 11003 - [TRAINER_MAXIE_MAGMA_HIDEOUT] = + [DIFFICULTY_NORMAL][TRAINER_MAXIE_MAGMA_HIDEOUT] = { #line 11004 .trainerName = _("MAXIE"), @@ -27645,7 +27640,7 @@ F_TRAINER_FEMALE | }, }, #line 11025 - [TRAINER_MAXIE_MT_CHIMNEY] = + [DIFFICULTY_NORMAL][TRAINER_MAXIE_MT_CHIMNEY] = { #line 11026 .trainerName = _("MAXIE"), @@ -27701,7 +27696,7 @@ F_TRAINER_FEMALE | }, }, #line 11047 - [TRAINER_TIANA] = + [DIFFICULTY_NORMAL][TRAINER_TIANA] = { #line 11048 .trainerName = _("TIANA"), @@ -27746,7 +27741,7 @@ F_TRAINER_FEMALE | }, }, #line 11064 - [TRAINER_HALEY_1] = + [DIFFICULTY_NORMAL][TRAINER_HALEY_1] = { #line 11065 .trainerName = _("HALEY"), @@ -27791,7 +27786,7 @@ F_TRAINER_FEMALE | }, }, #line 11081 - [TRAINER_JANICE] = + [DIFFICULTY_NORMAL][TRAINER_JANICE] = { #line 11082 .trainerName = _("JANICE"), @@ -27825,7 +27820,7 @@ F_TRAINER_FEMALE | }, }, #line 11094 - [TRAINER_VIVI] = + [DIFFICULTY_NORMAL][TRAINER_VIVI] = { #line 11095 .trainerName = _("VIVI"), @@ -27881,7 +27876,7 @@ F_TRAINER_FEMALE | }, }, #line 11115 - [TRAINER_HALEY_2] = + [DIFFICULTY_NORMAL][TRAINER_HALEY_2] = { #line 11116 .trainerName = _("HALEY"), @@ -27926,7 +27921,7 @@ F_TRAINER_FEMALE | }, }, #line 11132 - [TRAINER_HALEY_3] = + [DIFFICULTY_NORMAL][TRAINER_HALEY_3] = { #line 11133 .trainerName = _("HALEY"), @@ -27971,7 +27966,7 @@ F_TRAINER_FEMALE | }, }, #line 11149 - [TRAINER_HALEY_4] = + [DIFFICULTY_NORMAL][TRAINER_HALEY_4] = { #line 11150 .trainerName = _("HALEY"), @@ -28016,7 +28011,7 @@ F_TRAINER_FEMALE | }, }, #line 11166 - [TRAINER_HALEY_5] = + [DIFFICULTY_NORMAL][TRAINER_HALEY_5] = { #line 11167 .trainerName = _("HALEY"), @@ -28072,7 +28067,7 @@ F_TRAINER_FEMALE | }, }, #line 11187 - [TRAINER_SALLY] = + [DIFFICULTY_NORMAL][TRAINER_SALLY] = { #line 11188 .trainerName = _("SALLY"), @@ -28106,7 +28101,7 @@ F_TRAINER_FEMALE | }, }, #line 11200 - [TRAINER_ROBIN] = + [DIFFICULTY_NORMAL][TRAINER_ROBIN] = { #line 11201 .trainerName = _("ROBIN"), @@ -28162,7 +28157,7 @@ F_TRAINER_FEMALE | }, }, #line 11221 - [TRAINER_ANDREA] = + [DIFFICULTY_NORMAL][TRAINER_ANDREA] = { #line 11222 .trainerName = _("ANDREA"), @@ -28196,7 +28191,7 @@ F_TRAINER_FEMALE | }, }, #line 11234 - [TRAINER_CRISSY] = + [DIFFICULTY_NORMAL][TRAINER_CRISSY] = { #line 11235 .trainerName = _("CRISSY"), @@ -28241,7 +28236,7 @@ F_TRAINER_FEMALE | }, }, #line 11251 - [TRAINER_RICK] = + [DIFFICULTY_NORMAL][TRAINER_RICK] = { #line 11252 .trainerName = _("RICK"), @@ -28284,7 +28279,7 @@ F_TRAINER_FEMALE | }, }, #line 11268 - [TRAINER_LYLE] = + [DIFFICULTY_NORMAL][TRAINER_LYLE] = { #line 11269 .trainerName = _("LYLE"), @@ -28349,7 +28344,7 @@ F_TRAINER_FEMALE | }, }, #line 11293 - [TRAINER_JOSE] = + [DIFFICULTY_NORMAL][TRAINER_JOSE] = { #line 11294 .trainerName = _("JOSE"), @@ -28392,7 +28387,7 @@ F_TRAINER_FEMALE | }, }, #line 11310 - [TRAINER_DOUG] = + [DIFFICULTY_NORMAL][TRAINER_DOUG] = { #line 11311 .trainerName = _("DOUG"), @@ -28435,7 +28430,7 @@ F_TRAINER_FEMALE | }, }, #line 11327 - [TRAINER_GREG] = + [DIFFICULTY_NORMAL][TRAINER_GREG] = { #line 11328 .trainerName = _("GREG"), @@ -28478,7 +28473,7 @@ F_TRAINER_FEMALE | }, }, #line 11344 - [TRAINER_KENT] = + [DIFFICULTY_NORMAL][TRAINER_KENT] = { #line 11345 .trainerName = _("KENT"), @@ -28510,7 +28505,7 @@ F_TRAINER_FEMALE | }, }, #line 11357 - [TRAINER_JAMES_1] = + [DIFFICULTY_NORMAL][TRAINER_JAMES_1] = { #line 11358 .trainerName = _("JAMES"), @@ -28553,7 +28548,7 @@ F_TRAINER_FEMALE | }, }, #line 11374 - [TRAINER_JAMES_2] = + [DIFFICULTY_NORMAL][TRAINER_JAMES_2] = { #line 11375 .trainerName = _("JAMES"), @@ -28585,7 +28580,7 @@ F_TRAINER_FEMALE | }, }, #line 11387 - [TRAINER_JAMES_3] = + [DIFFICULTY_NORMAL][TRAINER_JAMES_3] = { #line 11388 .trainerName = _("JAMES"), @@ -28628,7 +28623,7 @@ F_TRAINER_FEMALE | }, }, #line 11404 - [TRAINER_JAMES_4] = + [DIFFICULTY_NORMAL][TRAINER_JAMES_4] = { #line 11405 .trainerName = _("JAMES"), @@ -28682,7 +28677,7 @@ F_TRAINER_FEMALE | }, }, #line 11425 - [TRAINER_JAMES_5] = + [DIFFICULTY_NORMAL][TRAINER_JAMES_5] = { #line 11426 .trainerName = _("JAMES"), @@ -28747,7 +28742,7 @@ F_TRAINER_FEMALE | }, }, #line 11450 - [TRAINER_BRICE] = + [DIFFICULTY_NORMAL][TRAINER_BRICE] = { #line 11451 .trainerName = _("BRICE"), @@ -28790,7 +28785,7 @@ F_TRAINER_FEMALE | }, }, #line 11467 - [TRAINER_TRENT_1] = + [DIFFICULTY_NORMAL][TRAINER_TRENT_1] = { #line 11468 .trainerName = _("TRENT"), @@ -28844,7 +28839,7 @@ F_TRAINER_FEMALE | }, }, #line 11488 - [TRAINER_LENNY] = + [DIFFICULTY_NORMAL][TRAINER_LENNY] = { #line 11489 .trainerName = _("LENNY"), @@ -28887,7 +28882,7 @@ F_TRAINER_FEMALE | }, }, #line 11505 - [TRAINER_LUCAS_1] = + [DIFFICULTY_NORMAL][TRAINER_LUCAS_1] = { #line 11506 .trainerName = _("LUCAS"), @@ -28930,7 +28925,7 @@ F_TRAINER_FEMALE | }, }, #line 11522 - [TRAINER_ALAN] = + [DIFFICULTY_NORMAL][TRAINER_ALAN] = { #line 11523 .trainerName = _("ALAN"), @@ -28984,7 +28979,7 @@ F_TRAINER_FEMALE | }, }, #line 11543 - [TRAINER_CLARK] = + [DIFFICULTY_NORMAL][TRAINER_CLARK] = { #line 11544 .trainerName = _("CLARK"), @@ -29016,7 +29011,7 @@ F_TRAINER_FEMALE | }, }, #line 11556 - [TRAINER_ERIC] = + [DIFFICULTY_NORMAL][TRAINER_ERIC] = { #line 11557 .trainerName = _("ERIC"), @@ -29059,7 +29054,7 @@ F_TRAINER_FEMALE | }, }, #line 11573 - [TRAINER_LUCAS_2] = + [DIFFICULTY_NORMAL][TRAINER_LUCAS_2] = { #line 11574 .trainerName = _("LUCAS"), @@ -29096,7 +29091,7 @@ F_TRAINER_FEMALE | }, }, #line 11588 - [TRAINER_MIKE_1] = + [DIFFICULTY_NORMAL][TRAINER_MIKE_1] = { #line 11589 .trainerName = _("MIKE"), @@ -29149,7 +29144,7 @@ F_TRAINER_FEMALE | }, }, #line 11609 - [TRAINER_MIKE_2] = + [DIFFICULTY_NORMAL][TRAINER_MIKE_2] = { #line 11610 .trainerName = _("MIKE"), @@ -29203,7 +29198,7 @@ F_TRAINER_FEMALE | }, }, #line 11630 - [TRAINER_TRENT_2] = + [DIFFICULTY_NORMAL][TRAINER_TRENT_2] = { #line 11631 .trainerName = _("TRENT"), @@ -29268,7 +29263,7 @@ F_TRAINER_FEMALE | }, }, #line 11655 - [TRAINER_TRENT_3] = + [DIFFICULTY_NORMAL][TRAINER_TRENT_3] = { #line 11656 .trainerName = _("TRENT"), @@ -29333,7 +29328,7 @@ F_TRAINER_FEMALE | }, }, #line 11680 - [TRAINER_TRENT_4] = + [DIFFICULTY_NORMAL][TRAINER_TRENT_4] = { #line 11681 .trainerName = _("TRENT"), @@ -29398,7 +29393,7 @@ F_TRAINER_FEMALE | }, }, #line 11705 - [TRAINER_TRENT_5] = + [DIFFICULTY_NORMAL][TRAINER_TRENT_5] = { #line 11706 .trainerName = _("TRENT"), @@ -29463,7 +29458,7 @@ F_TRAINER_FEMALE | }, }, #line 11730 - [TRAINER_DEZ_AND_LUKE] = + [DIFFICULTY_NORMAL][TRAINER_DEZ_AND_LUKE] = { #line 11731 .trainerName = _("DEZ & LUKE"), @@ -29506,7 +29501,7 @@ F_TRAINER_FEMALE | }, }, #line 11747 - [TRAINER_LEA_AND_JED] = + [DIFFICULTY_NORMAL][TRAINER_LEA_AND_JED] = { #line 11748 .trainerName = _("LEA & JED"), @@ -29549,7 +29544,7 @@ F_TRAINER_FEMALE | }, }, #line 11764 - [TRAINER_KIRA_AND_DAN_1] = + [DIFFICULTY_NORMAL][TRAINER_KIRA_AND_DAN_1] = { #line 11765 .trainerName = _("KIRA & DAN"), @@ -29592,7 +29587,7 @@ F_TRAINER_FEMALE | }, }, #line 11781 - [TRAINER_KIRA_AND_DAN_2] = + [DIFFICULTY_NORMAL][TRAINER_KIRA_AND_DAN_2] = { #line 11782 .trainerName = _("KIRA & DAN"), @@ -29635,7 +29630,7 @@ F_TRAINER_FEMALE | }, }, #line 11798 - [TRAINER_KIRA_AND_DAN_3] = + [DIFFICULTY_NORMAL][TRAINER_KIRA_AND_DAN_3] = { #line 11799 .trainerName = _("KIRA & DAN"), @@ -29678,7 +29673,7 @@ F_TRAINER_FEMALE | }, }, #line 11815 - [TRAINER_KIRA_AND_DAN_4] = + [DIFFICULTY_NORMAL][TRAINER_KIRA_AND_DAN_4] = { #line 11816 .trainerName = _("KIRA & DAN"), @@ -29721,7 +29716,7 @@ F_TRAINER_FEMALE | }, }, #line 11832 - [TRAINER_KIRA_AND_DAN_5] = + [DIFFICULTY_NORMAL][TRAINER_KIRA_AND_DAN_5] = { #line 11833 .trainerName = _("KIRA & DAN"), @@ -29764,7 +29759,7 @@ F_TRAINER_FEMALE | }, }, #line 11849 - [TRAINER_JOHANNA] = + [DIFFICULTY_NORMAL][TRAINER_JOHANNA] = { #line 11850 .trainerName = _("JOHANNA"), @@ -29798,7 +29793,7 @@ F_TRAINER_FEMALE | }, }, #line 11862 - [TRAINER_GERALD] = + [DIFFICULTY_NORMAL][TRAINER_GERALD] = { #line 11863 .trainerName = _("GERALD"), @@ -29839,7 +29834,7 @@ F_TRAINER_FEMALE | }, }, #line 11880 - [TRAINER_VIVIAN] = + [DIFFICULTY_NORMAL][TRAINER_VIVIAN] = { #line 11881 .trainerName = _("VIVIAN"), @@ -29898,7 +29893,7 @@ F_TRAINER_FEMALE | }, }, #line 11905 - [TRAINER_DANIELLE] = + [DIFFICULTY_NORMAL][TRAINER_DANIELLE] = { #line 11906 .trainerName = _("DANIELLE"), @@ -29939,7 +29934,7 @@ F_TRAINER_FEMALE | }, }, #line 11922 - [TRAINER_HIDEO] = + [DIFFICULTY_NORMAL][TRAINER_HIDEO] = { #line 11923 .trainerName = _("HIDEO"), @@ -29996,7 +29991,7 @@ F_TRAINER_FEMALE | }, }, #line 11947 - [TRAINER_KEIGO] = + [DIFFICULTY_NORMAL][TRAINER_KEIGO] = { #line 11948 .trainerName = _("KEIGO"), @@ -30053,7 +30048,7 @@ F_TRAINER_FEMALE | }, }, #line 11972 - [TRAINER_RILEY] = + [DIFFICULTY_NORMAL][TRAINER_RILEY] = { #line 11973 .trainerName = _("RILEY"), @@ -30110,7 +30105,7 @@ F_TRAINER_FEMALE | }, }, #line 11997 - [TRAINER_FLINT] = + [DIFFICULTY_NORMAL][TRAINER_FLINT] = { #line 11998 .trainerName = _("FLINT"), @@ -30153,7 +30148,7 @@ F_TRAINER_FEMALE | }, }, #line 12014 - [TRAINER_ASHLEY] = + [DIFFICULTY_NORMAL][TRAINER_ASHLEY] = { #line 12015 .trainerName = _("ASHLEY"), @@ -30209,7 +30204,7 @@ F_TRAINER_FEMALE | }, }, #line 12035 - [TRAINER_WALLY_MAUVILLE] = + [DIFFICULTY_NORMAL][TRAINER_WALLY_MAUVILLE] = { #line 12036 .trainerName = _("WALLY"), @@ -30241,7 +30236,7 @@ F_TRAINER_FEMALE | }, }, #line 12048 - [TRAINER_WALLY_VR_2] = + [DIFFICULTY_NORMAL][TRAINER_WALLY_VR_2] = { #line 12049 .trainerName = _("WALLY"), @@ -30354,7 +30349,7 @@ F_TRAINER_FEMALE | }, }, #line 12098 - [TRAINER_WALLY_VR_3] = + [DIFFICULTY_NORMAL][TRAINER_WALLY_VR_3] = { #line 12099 .trainerName = _("WALLY"), @@ -30467,7 +30462,7 @@ F_TRAINER_FEMALE | }, }, #line 12148 - [TRAINER_WALLY_VR_4] = + [DIFFICULTY_NORMAL][TRAINER_WALLY_VR_4] = { #line 12149 .trainerName = _("WALLY"), @@ -30580,7 +30575,7 @@ F_TRAINER_FEMALE | }, }, #line 12198 - [TRAINER_WALLY_VR_5] = + [DIFFICULTY_NORMAL][TRAINER_WALLY_VR_5] = { #line 12199 .trainerName = _("WALLY"), @@ -30693,7 +30688,7 @@ F_TRAINER_FEMALE | }, }, #line 12248 - [TRAINER_BRENDAN_LILYCOVE_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_LILYCOVE_MUDKIP] = { #line 12249 .trainerName = _("BRENDAN"), @@ -30758,7 +30753,7 @@ F_TRAINER_FEMALE | }, }, #line 12273 - [TRAINER_BRENDAN_LILYCOVE_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_LILYCOVE_TREECKO] = { #line 12274 .trainerName = _("BRENDAN"), @@ -30823,7 +30818,7 @@ F_TRAINER_FEMALE | }, }, #line 12298 - [TRAINER_BRENDAN_LILYCOVE_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_LILYCOVE_TORCHIC] = { #line 12299 .trainerName = _("BRENDAN"), @@ -30888,7 +30883,7 @@ F_TRAINER_FEMALE | }, }, #line 12323 - [TRAINER_MAY_LILYCOVE_MUDKIP] = + [DIFFICULTY_NORMAL][TRAINER_MAY_LILYCOVE_MUDKIP] = { #line 12324 .trainerName = _("MAY"), @@ -30955,7 +30950,7 @@ F_TRAINER_FEMALE | }, }, #line 12348 - [TRAINER_MAY_LILYCOVE_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_MAY_LILYCOVE_TREECKO] = { #line 12349 .trainerName = _("MAY"), @@ -31022,7 +31017,7 @@ F_TRAINER_FEMALE | }, }, #line 12373 - [TRAINER_MAY_LILYCOVE_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_MAY_LILYCOVE_TORCHIC] = { #line 12374 .trainerName = _("MAY"), @@ -31089,7 +31084,7 @@ F_TRAINER_FEMALE | }, }, #line 12398 - [TRAINER_JONAH] = + [DIFFICULTY_NORMAL][TRAINER_JONAH] = { #line 12399 .trainerName = _("JONAH"), @@ -31143,7 +31138,7 @@ F_TRAINER_FEMALE | }, }, #line 12419 - [TRAINER_HENRY] = + [DIFFICULTY_NORMAL][TRAINER_HENRY] = { #line 12420 .trainerName = _("HENRY"), @@ -31186,7 +31181,7 @@ F_TRAINER_FEMALE | }, }, #line 12436 - [TRAINER_ROGER] = + [DIFFICULTY_NORMAL][TRAINER_ROGER] = { #line 12437 .trainerName = _("ROGER"), @@ -31240,7 +31235,7 @@ F_TRAINER_FEMALE | }, }, #line 12457 - [TRAINER_ALEXA] = + [DIFFICULTY_NORMAL][TRAINER_ALEXA] = { #line 12458 .trainerName = _("ALEXA"), @@ -31287,7 +31282,7 @@ F_TRAINER_FEMALE | }, }, #line 12475 - [TRAINER_RUBEN] = + [DIFFICULTY_NORMAL][TRAINER_RUBEN] = { #line 12476 .trainerName = _("RUBEN"), @@ -31332,7 +31327,7 @@ F_TRAINER_FEMALE | }, }, #line 12493 - [TRAINER_KOJI_1] = + [DIFFICULTY_NORMAL][TRAINER_KOJI_1] = { #line 12494 .trainerName = _("KOJI"), @@ -31364,7 +31359,7 @@ F_TRAINER_FEMALE | }, }, #line 12506 - [TRAINER_WAYNE] = + [DIFFICULTY_NORMAL][TRAINER_WAYNE] = { #line 12507 .trainerName = _("WAYNE"), @@ -31418,7 +31413,7 @@ F_TRAINER_FEMALE | }, }, #line 12527 - [TRAINER_AIDAN] = + [DIFFICULTY_NORMAL][TRAINER_AIDAN] = { #line 12528 .trainerName = _("AIDAN"), @@ -31461,7 +31456,7 @@ F_TRAINER_FEMALE | }, }, #line 12544 - [TRAINER_REED] = + [DIFFICULTY_NORMAL][TRAINER_REED] = { #line 12545 .trainerName = _("REED"), @@ -31504,7 +31499,7 @@ F_TRAINER_FEMALE | }, }, #line 12561 - [TRAINER_TISHA] = + [DIFFICULTY_NORMAL][TRAINER_TISHA] = { #line 12562 .trainerName = _("TISHA"), @@ -31538,7 +31533,7 @@ F_TRAINER_FEMALE | }, }, #line 12574 - [TRAINER_TORI_AND_TIA] = + [DIFFICULTY_NORMAL][TRAINER_TORI_AND_TIA] = { #line 12575 .trainerName = _("TORI & TIA"), @@ -31581,7 +31576,7 @@ F_TRAINER_FEMALE | }, }, #line 12591 - [TRAINER_KIM_AND_IRIS] = + [DIFFICULTY_NORMAL][TRAINER_KIM_AND_IRIS] = { #line 12592 .trainerName = _("KIM & IRIS"), @@ -31638,7 +31633,7 @@ F_TRAINER_FEMALE | }, }, #line 12616 - [TRAINER_TYRA_AND_IVY] = + [DIFFICULTY_NORMAL][TRAINER_TYRA_AND_IVY] = { #line 12617 .trainerName = _("TYRA & IVY"), @@ -31695,7 +31690,7 @@ F_TRAINER_FEMALE | }, }, #line 12641 - [TRAINER_MEL_AND_PAUL] = + [DIFFICULTY_NORMAL][TRAINER_MEL_AND_PAUL] = { #line 12642 .trainerName = _("MEL & PAUL"), @@ -31752,7 +31747,7 @@ F_TRAINER_FEMALE | }, }, #line 12666 - [TRAINER_JOHN_AND_JAY_1] = + [DIFFICULTY_NORMAL][TRAINER_JOHN_AND_JAY_1] = { #line 12667 .trainerName = _("JOHN & JAY"), @@ -31809,7 +31804,7 @@ F_TRAINER_FEMALE | }, }, #line 12691 - [TRAINER_JOHN_AND_JAY_2] = + [DIFFICULTY_NORMAL][TRAINER_JOHN_AND_JAY_2] = { #line 12692 .trainerName = _("JOHN & JAY"), @@ -31866,7 +31861,7 @@ F_TRAINER_FEMALE | }, }, #line 12716 - [TRAINER_JOHN_AND_JAY_3] = + [DIFFICULTY_NORMAL][TRAINER_JOHN_AND_JAY_3] = { #line 12717 .trainerName = _("JOHN & JAY"), @@ -31923,7 +31918,7 @@ F_TRAINER_FEMALE | }, }, #line 12741 - [TRAINER_JOHN_AND_JAY_4] = + [DIFFICULTY_NORMAL][TRAINER_JOHN_AND_JAY_4] = { #line 12742 .trainerName = _("JOHN & JAY"), @@ -31980,7 +31975,7 @@ F_TRAINER_FEMALE | }, }, #line 12766 - [TRAINER_JOHN_AND_JAY_5] = + [DIFFICULTY_NORMAL][TRAINER_JOHN_AND_JAY_5] = { #line 12767 .trainerName = _("JOHN & JAY"), @@ -32037,7 +32032,7 @@ F_TRAINER_FEMALE | }, }, #line 12791 - [TRAINER_RELI_AND_IAN] = + [DIFFICULTY_NORMAL][TRAINER_RELI_AND_IAN] = { #line 12792 .trainerName = _("RELI & IAN"), @@ -32080,7 +32075,7 @@ F_TRAINER_FEMALE | }, }, #line 12808 - [TRAINER_LILA_AND_ROY_1] = + [DIFFICULTY_NORMAL][TRAINER_LILA_AND_ROY_1] = { #line 12809 .trainerName = _("LILA & ROY"), @@ -32123,7 +32118,7 @@ F_TRAINER_FEMALE | }, }, #line 12825 - [TRAINER_LILA_AND_ROY_2] = + [DIFFICULTY_NORMAL][TRAINER_LILA_AND_ROY_2] = { #line 12826 .trainerName = _("LILA & ROY"), @@ -32166,7 +32161,7 @@ F_TRAINER_FEMALE | }, }, #line 12842 - [TRAINER_LILA_AND_ROY_3] = + [DIFFICULTY_NORMAL][TRAINER_LILA_AND_ROY_3] = { #line 12843 .trainerName = _("LILA & ROY"), @@ -32209,7 +32204,7 @@ F_TRAINER_FEMALE | }, }, #line 12859 - [TRAINER_LILA_AND_ROY_4] = + [DIFFICULTY_NORMAL][TRAINER_LILA_AND_ROY_4] = { #line 12860 .trainerName = _("LILA & ROY"), @@ -32252,7 +32247,7 @@ F_TRAINER_FEMALE | }, }, #line 12876 - [TRAINER_LILA_AND_ROY_5] = + [DIFFICULTY_NORMAL][TRAINER_LILA_AND_ROY_5] = { #line 12877 .trainerName = _("LILA & ROY"), @@ -32295,7 +32290,7 @@ F_TRAINER_FEMALE | }, }, #line 12893 - [TRAINER_LISA_AND_RAY] = + [DIFFICULTY_NORMAL][TRAINER_LISA_AND_RAY] = { #line 12894 .trainerName = _("LISA & RAY"), @@ -32338,7 +32333,7 @@ F_TRAINER_FEMALE | }, }, #line 12910 - [TRAINER_CHRIS] = + [DIFFICULTY_NORMAL][TRAINER_CHRIS] = { #line 12911 .trainerName = _("CHRIS"), @@ -32403,7 +32398,7 @@ F_TRAINER_FEMALE | }, }, #line 12935 - [TRAINER_DAWSON] = + [DIFFICULTY_NORMAL][TRAINER_DAWSON] = { #line 12936 .trainerName = _("DAWSON"), @@ -32448,7 +32443,7 @@ F_TRAINER_FEMALE | }, }, #line 12952 - [TRAINER_SARAH] = + [DIFFICULTY_NORMAL][TRAINER_SARAH] = { #line 12953 .trainerName = _("SARAH"), @@ -32497,7 +32492,7 @@ F_TRAINER_FEMALE | }, }, #line 12970 - [TRAINER_DARIAN] = + [DIFFICULTY_NORMAL][TRAINER_DARIAN] = { #line 12971 .trainerName = _("DARIAN"), @@ -32529,7 +32524,7 @@ F_TRAINER_FEMALE | }, }, #line 12983 - [TRAINER_HAILEY] = + [DIFFICULTY_NORMAL][TRAINER_HAILEY] = { #line 12984 .trainerName = _("HAILEY"), @@ -32563,7 +32558,7 @@ F_TRAINER_FEMALE | }, }, #line 12996 - [TRAINER_CHANDLER] = + [DIFFICULTY_NORMAL][TRAINER_CHANDLER] = { #line 12997 .trainerName = _("CHANDLER"), @@ -32606,7 +32601,7 @@ F_TRAINER_FEMALE | }, }, #line 13013 - [TRAINER_KALEB] = + [DIFFICULTY_NORMAL][TRAINER_KALEB] = { #line 13014 .trainerName = _("KALEB"), @@ -32653,7 +32648,7 @@ F_TRAINER_FEMALE | }, }, #line 13030 - [TRAINER_JOSEPH] = + [DIFFICULTY_NORMAL][TRAINER_JOSEPH] = { #line 13031 .trainerName = _("JOSEPH"), @@ -32696,7 +32691,7 @@ F_TRAINER_FEMALE | }, }, #line 13047 - [TRAINER_ALYSSA] = + [DIFFICULTY_NORMAL][TRAINER_ALYSSA] = { #line 13048 .trainerName = _("ALYSSA"), @@ -32730,7 +32725,7 @@ F_TRAINER_FEMALE | }, }, #line 13060 - [TRAINER_MARCOS] = + [DIFFICULTY_NORMAL][TRAINER_MARCOS] = { #line 13061 .trainerName = _("MARCOS"), @@ -32762,7 +32757,7 @@ F_TRAINER_FEMALE | }, }, #line 13073 - [TRAINER_RHETT] = + [DIFFICULTY_NORMAL][TRAINER_RHETT] = { #line 13074 .trainerName = _("RHETT"), @@ -32794,7 +32789,7 @@ F_TRAINER_FEMALE | }, }, #line 13086 - [TRAINER_TYRON] = + [DIFFICULTY_NORMAL][TRAINER_TYRON] = { #line 13087 .trainerName = _("TYRON"), @@ -32826,7 +32821,7 @@ F_TRAINER_FEMALE | }, }, #line 13099 - [TRAINER_CELINA] = + [DIFFICULTY_NORMAL][TRAINER_CELINA] = { #line 13100 .trainerName = _("CELINA"), @@ -32860,7 +32855,7 @@ F_TRAINER_FEMALE | }, }, #line 13112 - [TRAINER_BIANCA] = + [DIFFICULTY_NORMAL][TRAINER_BIANCA] = { #line 13113 .trainerName = _("BIANCA"), @@ -32894,7 +32889,7 @@ F_TRAINER_FEMALE | }, }, #line 13125 - [TRAINER_HAYDEN] = + [DIFFICULTY_NORMAL][TRAINER_HAYDEN] = { #line 13126 .trainerName = _("HAYDEN"), @@ -32926,7 +32921,7 @@ F_TRAINER_FEMALE | }, }, #line 13138 - [TRAINER_SOPHIE] = + [DIFFICULTY_NORMAL][TRAINER_SOPHIE] = { #line 13139 .trainerName = _("SOPHIE"), @@ -32971,7 +32966,7 @@ F_TRAINER_FEMALE | }, }, #line 13155 - [TRAINER_COBY] = + [DIFFICULTY_NORMAL][TRAINER_COBY] = { #line 13156 .trainerName = _("COBY"), @@ -33014,7 +33009,7 @@ F_TRAINER_FEMALE | }, }, #line 13172 - [TRAINER_LAWRENCE] = + [DIFFICULTY_NORMAL][TRAINER_LAWRENCE] = { #line 13173 .trainerName = _("LAWRENCE"), @@ -33057,7 +33052,7 @@ F_TRAINER_FEMALE | }, }, #line 13189 - [TRAINER_WYATT] = + [DIFFICULTY_NORMAL][TRAINER_WYATT] = { #line 13190 .trainerName = _("WYATT"), @@ -33100,7 +33095,7 @@ F_TRAINER_FEMALE | }, }, #line 13206 - [TRAINER_ANGELINA] = + [DIFFICULTY_NORMAL][TRAINER_ANGELINA] = { #line 13207 .trainerName = _("ANGELINA"), @@ -33145,7 +33140,7 @@ F_TRAINER_FEMALE | }, }, #line 13223 - [TRAINER_KAI] = + [DIFFICULTY_NORMAL][TRAINER_KAI] = { #line 13224 .trainerName = _("KAI"), @@ -33177,7 +33172,7 @@ F_TRAINER_FEMALE | }, }, #line 13236 - [TRAINER_CHARLOTTE] = + [DIFFICULTY_NORMAL][TRAINER_CHARLOTTE] = { #line 13237 .trainerName = _("CHARLOTTE"), @@ -33211,7 +33206,7 @@ F_TRAINER_FEMALE | }, }, #line 13249 - [TRAINER_DEANDRE] = + [DIFFICULTY_NORMAL][TRAINER_DEANDRE] = { #line 13250 .trainerName = _("DEANDRE"), @@ -33265,7 +33260,7 @@ F_TRAINER_FEMALE | }, }, #line 13270 - [TRAINER_GRUNT_MAGMA_HIDEOUT_1] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_1] = { #line 13271 .trainerName = _("GRUNT"), @@ -33297,7 +33292,7 @@ F_TRAINER_FEMALE | }, }, #line 13283 - [TRAINER_GRUNT_MAGMA_HIDEOUT_2] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_2] = { #line 13284 .trainerName = _("GRUNT"), @@ -33329,7 +33324,7 @@ F_TRAINER_FEMALE | }, }, #line 13296 - [TRAINER_GRUNT_MAGMA_HIDEOUT_3] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_3] = { #line 13297 .trainerName = _("GRUNT"), @@ -33361,7 +33356,7 @@ F_TRAINER_FEMALE | }, }, #line 13309 - [TRAINER_GRUNT_MAGMA_HIDEOUT_4] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_4] = { #line 13310 .trainerName = _("GRUNT"), @@ -33404,7 +33399,7 @@ F_TRAINER_FEMALE | }, }, #line 13326 - [TRAINER_GRUNT_MAGMA_HIDEOUT_5] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_5] = { #line 13327 .trainerName = _("GRUNT"), @@ -33447,7 +33442,7 @@ F_TRAINER_FEMALE | }, }, #line 13343 - [TRAINER_GRUNT_MAGMA_HIDEOUT_6] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_6] = { #line 13344 .trainerName = _("GRUNT"), @@ -33479,7 +33474,7 @@ F_TRAINER_FEMALE | }, }, #line 13356 - [TRAINER_GRUNT_MAGMA_HIDEOUT_7] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_7] = { #line 13357 .trainerName = _("GRUNT"), @@ -33511,7 +33506,7 @@ F_TRAINER_FEMALE | }, }, #line 13369 - [TRAINER_GRUNT_MAGMA_HIDEOUT_8] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_8] = { #line 13370 .trainerName = _("GRUNT"), @@ -33543,7 +33538,7 @@ F_TRAINER_FEMALE | }, }, #line 13382 - [TRAINER_GRUNT_MAGMA_HIDEOUT_9] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_9] = { #line 13383 .trainerName = _("GRUNT"), @@ -33575,7 +33570,7 @@ F_TRAINER_FEMALE | }, }, #line 13395 - [TRAINER_GRUNT_MAGMA_HIDEOUT_10] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_10] = { #line 13396 .trainerName = _("GRUNT"), @@ -33607,7 +33602,7 @@ F_TRAINER_FEMALE | }, }, #line 13408 - [TRAINER_GRUNT_MAGMA_HIDEOUT_11] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_11] = { #line 13409 .trainerName = _("GRUNT"), @@ -33639,7 +33634,7 @@ F_TRAINER_FEMALE | }, }, #line 13421 - [TRAINER_GRUNT_MAGMA_HIDEOUT_12] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_12] = { #line 13422 .trainerName = _("GRUNT"), @@ -33671,7 +33666,7 @@ F_TRAINER_FEMALE | }, }, #line 13434 - [TRAINER_GRUNT_MAGMA_HIDEOUT_13] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_13] = { #line 13435 .trainerName = _("GRUNT"), @@ -33703,7 +33698,7 @@ F_TRAINER_FEMALE | }, }, #line 13447 - [TRAINER_GRUNT_MAGMA_HIDEOUT_14] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_14] = { #line 13448 .trainerName = _("GRUNT"), @@ -33737,7 +33732,7 @@ F_TRAINER_FEMALE | }, }, #line 13460 - [TRAINER_GRUNT_MAGMA_HIDEOUT_15] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_15] = { #line 13461 .trainerName = _("GRUNT"), @@ -33771,7 +33766,7 @@ F_TRAINER_FEMALE | }, }, #line 13473 - [TRAINER_GRUNT_MAGMA_HIDEOUT_16] = + [DIFFICULTY_NORMAL][TRAINER_GRUNT_MAGMA_HIDEOUT_16] = { #line 13474 .trainerName = _("GRUNT"), @@ -33805,7 +33800,7 @@ F_TRAINER_FEMALE | }, }, #line 13486 - [TRAINER_TABITHA_MAGMA_HIDEOUT] = + [DIFFICULTY_NORMAL][TRAINER_TABITHA_MAGMA_HIDEOUT] = { #line 13487 .trainerName = _("TABITHA"), @@ -33870,7 +33865,7 @@ F_TRAINER_FEMALE | }, }, #line 13511 - [TRAINER_DARCY] = + [DIFFICULTY_NORMAL][TRAINER_DARCY] = { #line 13512 .trainerName = _("DARCY"), @@ -33917,7 +33912,7 @@ F_TRAINER_FEMALE | }, }, #line 13529 - [TRAINER_MAXIE_MOSSDEEP] = + [DIFFICULTY_NORMAL][TRAINER_MAXIE_MOSSDEEP] = { #line 13530 .trainerName = _("MAXIE"), @@ -33971,7 +33966,7 @@ F_TRAINER_FEMALE | }, }, #line 13550 - [TRAINER_PETE] = + [DIFFICULTY_NORMAL][TRAINER_PETE] = { #line 13551 .trainerName = _("PETE"), @@ -34003,7 +33998,7 @@ F_TRAINER_FEMALE | }, }, #line 13563 - [TRAINER_ISABELLE] = + [DIFFICULTY_NORMAL][TRAINER_ISABELLE] = { #line 13564 .trainerName = _("ISABELLE"), @@ -34037,7 +34032,7 @@ F_TRAINER_FEMALE | }, }, #line 13576 - [TRAINER_ANDRES_1] = + [DIFFICULTY_NORMAL][TRAINER_ANDRES_1] = { #line 13577 .trainerName = _("ANDRES"), @@ -34080,7 +34075,7 @@ F_TRAINER_FEMALE | }, }, #line 13593 - [TRAINER_JOSUE] = + [DIFFICULTY_NORMAL][TRAINER_JOSUE] = { #line 13594 .trainerName = _("JOSUE"), @@ -34123,7 +34118,7 @@ F_TRAINER_FEMALE | }, }, #line 13610 - [TRAINER_CAMRON] = + [DIFFICULTY_NORMAL][TRAINER_CAMRON] = { #line 13611 .trainerName = _("CAMRON"), @@ -34155,7 +34150,7 @@ F_TRAINER_FEMALE | }, }, #line 13623 - [TRAINER_CORY_1] = + [DIFFICULTY_NORMAL][TRAINER_CORY_1] = { #line 13624 .trainerName = _("CORY"), @@ -34209,7 +34204,7 @@ F_TRAINER_FEMALE | }, }, #line 13644 - [TRAINER_CAROLINA] = + [DIFFICULTY_NORMAL][TRAINER_CAROLINA] = { #line 13645 .trainerName = _("CAROLINA"), @@ -34267,7 +34262,7 @@ F_TRAINER_FEMALE | }, }, #line 13666 - [TRAINER_ELIJAH] = + [DIFFICULTY_NORMAL][TRAINER_ELIJAH] = { #line 13667 .trainerName = _("ELIJAH"), @@ -34310,7 +34305,7 @@ F_TRAINER_FEMALE | }, }, #line 13683 - [TRAINER_CELIA] = + [DIFFICULTY_NORMAL][TRAINER_CELIA] = { #line 13684 .trainerName = _("CELIA"), @@ -34355,7 +34350,7 @@ F_TRAINER_FEMALE | }, }, #line 13700 - [TRAINER_BRYAN] = + [DIFFICULTY_NORMAL][TRAINER_BRYAN] = { #line 13701 .trainerName = _("BRYAN"), @@ -34398,7 +34393,7 @@ F_TRAINER_FEMALE | }, }, #line 13717 - [TRAINER_BRANDEN] = + [DIFFICULTY_NORMAL][TRAINER_BRANDEN] = { #line 13718 .trainerName = _("BRANDEN"), @@ -34441,7 +34436,7 @@ F_TRAINER_FEMALE | }, }, #line 13734 - [TRAINER_BRYANT] = + [DIFFICULTY_NORMAL][TRAINER_BRYANT] = { #line 13735 .trainerName = _("BRYANT"), @@ -34484,7 +34479,7 @@ F_TRAINER_FEMALE | }, }, #line 13751 - [TRAINER_SHAYLA] = + [DIFFICULTY_NORMAL][TRAINER_SHAYLA] = { #line 13752 .trainerName = _("SHAYLA"), @@ -34529,7 +34524,7 @@ F_TRAINER_FEMALE | }, }, #line 13768 - [TRAINER_KYRA] = + [DIFFICULTY_NORMAL][TRAINER_KYRA] = { #line 13769 .trainerName = _("KYRA"), @@ -34574,7 +34569,7 @@ F_TRAINER_FEMALE | }, }, #line 13785 - [TRAINER_JAIDEN] = + [DIFFICULTY_NORMAL][TRAINER_JAIDEN] = { #line 13786 .trainerName = _("JAIDEN"), @@ -34617,7 +34612,7 @@ F_TRAINER_FEMALE | }, }, #line 13802 - [TRAINER_ALIX] = + [DIFFICULTY_NORMAL][TRAINER_ALIX] = { #line 13803 .trainerName = _("ALIX"), @@ -34662,7 +34657,7 @@ F_TRAINER_FEMALE | }, }, #line 13819 - [TRAINER_HELENE] = + [DIFFICULTY_NORMAL][TRAINER_HELENE] = { #line 13820 .trainerName = _("HELENE"), @@ -34707,7 +34702,7 @@ F_TRAINER_FEMALE | }, }, #line 13836 - [TRAINER_MARLENE] = + [DIFFICULTY_NORMAL][TRAINER_MARLENE] = { #line 13837 .trainerName = _("MARLENE"), @@ -34752,7 +34747,7 @@ F_TRAINER_FEMALE | }, }, #line 13853 - [TRAINER_DEVAN] = + [DIFFICULTY_NORMAL][TRAINER_DEVAN] = { #line 13854 .trainerName = _("DEVAN"), @@ -34795,7 +34790,7 @@ F_TRAINER_FEMALE | }, }, #line 13870 - [TRAINER_JOHNSON] = + [DIFFICULTY_NORMAL][TRAINER_JOHNSON] = { #line 13871 .trainerName = _("JOHNSON"), @@ -34838,7 +34833,7 @@ F_TRAINER_FEMALE | }, }, #line 13887 - [TRAINER_MELINA] = + [DIFFICULTY_NORMAL][TRAINER_MELINA] = { #line 13888 .trainerName = _("MELINA"), @@ -34872,7 +34867,7 @@ F_TRAINER_FEMALE | }, }, #line 13900 - [TRAINER_BRANDI] = + [DIFFICULTY_NORMAL][TRAINER_BRANDI] = { #line 13901 .trainerName = _("BRANDI"), @@ -34906,7 +34901,7 @@ F_TRAINER_FEMALE | }, }, #line 13913 - [TRAINER_AISHA] = + [DIFFICULTY_NORMAL][TRAINER_AISHA] = { #line 13914 .trainerName = _("AISHA"), @@ -34940,7 +34935,7 @@ F_TRAINER_FEMALE | }, }, #line 13926 - [TRAINER_MAKAYLA] = + [DIFFICULTY_NORMAL][TRAINER_MAKAYLA] = { #line 13927 .trainerName = _("MAKAYLA"), @@ -34987,7 +34982,7 @@ F_TRAINER_FEMALE | }, }, #line 13944 - [TRAINER_FABIAN] = + [DIFFICULTY_NORMAL][TRAINER_FABIAN] = { #line 13945 .trainerName = _("FABIAN"), @@ -35019,7 +35014,7 @@ F_TRAINER_FEMALE | }, }, #line 13957 - [TRAINER_DAYTON] = + [DIFFICULTY_NORMAL][TRAINER_DAYTON] = { #line 13958 .trainerName = _("DAYTON"), @@ -35062,7 +35057,7 @@ F_TRAINER_FEMALE | }, }, #line 13974 - [TRAINER_RACHEL] = + [DIFFICULTY_NORMAL][TRAINER_RACHEL] = { #line 13975 .trainerName = _("RACHEL"), @@ -35096,7 +35091,7 @@ F_TRAINER_FEMALE | }, }, #line 13987 - [TRAINER_LEONEL] = + [DIFFICULTY_NORMAL][TRAINER_LEONEL] = { #line 13988 .trainerName = _("LEONEL"), @@ -35136,7 +35131,7 @@ F_TRAINER_FEMALE | }, }, #line 14004 - [TRAINER_CALLIE] = + [DIFFICULTY_NORMAL][TRAINER_CALLIE] = { #line 14005 .trainerName = _("CALLIE"), @@ -35181,7 +35176,7 @@ F_TRAINER_FEMALE | }, }, #line 14021 - [TRAINER_CALE] = + [DIFFICULTY_NORMAL][TRAINER_CALE] = { #line 14022 .trainerName = _("CALE"), @@ -35224,7 +35219,7 @@ F_TRAINER_FEMALE | }, }, #line 14038 - [TRAINER_MYLES] = + [DIFFICULTY_NORMAL][TRAINER_MYLES] = { #line 14039 .trainerName = _("MYLES"), @@ -35311,7 +35306,7 @@ F_TRAINER_FEMALE | }, }, #line 14071 - [TRAINER_PAT] = + [DIFFICULTY_NORMAL][TRAINER_PAT] = { #line 14072 .trainerName = _("PAT"), @@ -35400,7 +35395,7 @@ F_TRAINER_FEMALE | }, }, #line 14104 - [TRAINER_CRISTIN_1] = + [DIFFICULTY_NORMAL][TRAINER_CRISTIN_1] = { #line 14105 .trainerName = _("CRISTIN"), @@ -35447,7 +35442,7 @@ F_TRAINER_FEMALE | }, }, #line 14122 - [TRAINER_MAY_RUSTBORO_TREECKO] = + [DIFFICULTY_NORMAL][TRAINER_MAY_RUSTBORO_TREECKO] = { #line 14123 .trainerName = _("MAY"), @@ -35492,7 +35487,7 @@ F_TRAINER_FEMALE | }, }, #line 14139 - [TRAINER_MAY_RUSTBORO_TORCHIC] = + [DIFFICULTY_NORMAL][TRAINER_MAY_RUSTBORO_TORCHIC] = { #line 14140 .trainerName = _("MAY"), @@ -35537,7 +35532,7 @@ F_TRAINER_FEMALE | }, }, #line 14156 - [TRAINER_ROXANNE_2] = + [DIFFICULTY_NORMAL][TRAINER_ROXANNE_2] = { #line 14157 .trainerName = _("ROXANNE"), @@ -35638,7 +35633,7 @@ F_TRAINER_FEMALE | }, }, #line 14198 - [TRAINER_ROXANNE_3] = + [DIFFICULTY_NORMAL][TRAINER_ROXANNE_3] = { #line 14199 .trainerName = _("ROXANNE"), @@ -35757,7 +35752,7 @@ F_TRAINER_FEMALE | }, }, #line 14248 - [TRAINER_ROXANNE_4] = + [DIFFICULTY_NORMAL][TRAINER_ROXANNE_4] = { #line 14249 .trainerName = _("ROXANNE"), @@ -35876,7 +35871,7 @@ F_TRAINER_FEMALE | }, }, #line 14298 - [TRAINER_ROXANNE_5] = + [DIFFICULTY_NORMAL][TRAINER_ROXANNE_5] = { #line 14299 .trainerName = _("ROXANNE"), @@ -36013,7 +36008,7 @@ F_TRAINER_FEMALE | }, }, #line 14356 - [TRAINER_BRAWLY_2] = + [DIFFICULTY_NORMAL][TRAINER_BRAWLY_2] = { #line 14357 .trainerName = _("BRAWLY"), @@ -36112,7 +36107,7 @@ F_TRAINER_FEMALE | }, }, #line 14398 - [TRAINER_BRAWLY_3] = + [DIFFICULTY_NORMAL][TRAINER_BRAWLY_3] = { #line 14399 .trainerName = _("BRAWLY"), @@ -36211,7 +36206,7 @@ F_TRAINER_FEMALE | }, }, #line 14440 - [TRAINER_BRAWLY_4] = + [DIFFICULTY_NORMAL][TRAINER_BRAWLY_4] = { #line 14441 .trainerName = _("BRAWLY"), @@ -36328,7 +36323,7 @@ F_TRAINER_FEMALE | }, }, #line 14490 - [TRAINER_BRAWLY_5] = + [DIFFICULTY_NORMAL][TRAINER_BRAWLY_5] = { #line 14491 .trainerName = _("BRAWLY"), @@ -36463,7 +36458,7 @@ F_TRAINER_FEMALE | }, }, #line 14548 - [TRAINER_WATTSON_2] = + [DIFFICULTY_NORMAL][TRAINER_WATTSON_2] = { #line 14549 .trainerName = _("WATTSON"), @@ -36562,7 +36557,7 @@ F_TRAINER_FEMALE | }, }, #line 14590 - [TRAINER_WATTSON_3] = + [DIFFICULTY_NORMAL][TRAINER_WATTSON_3] = { #line 14591 .trainerName = _("WATTSON"), @@ -36679,7 +36674,7 @@ F_TRAINER_FEMALE | }, }, #line 14640 - [TRAINER_WATTSON_4] = + [DIFFICULTY_NORMAL][TRAINER_WATTSON_4] = { #line 14641 .trainerName = _("WATTSON"), @@ -36796,7 +36791,7 @@ F_TRAINER_FEMALE | }, }, #line 14690 - [TRAINER_WATTSON_5] = + [DIFFICULTY_NORMAL][TRAINER_WATTSON_5] = { #line 14691 .trainerName = _("WATTSON"), @@ -36931,7 +36926,7 @@ F_TRAINER_FEMALE | }, }, #line 14748 - [TRAINER_FLANNERY_2] = + [DIFFICULTY_NORMAL][TRAINER_FLANNERY_2] = { #line 14749 .trainerName = _("FLANNERY"), @@ -37034,7 +37029,7 @@ F_TRAINER_FEMALE | }, }, #line 14790 - [TRAINER_FLANNERY_3] = + [DIFFICULTY_NORMAL][TRAINER_FLANNERY_3] = { #line 14791 .trainerName = _("FLANNERY"), @@ -37155,7 +37150,7 @@ F_TRAINER_FEMALE | }, }, #line 14840 - [TRAINER_FLANNERY_4] = + [DIFFICULTY_NORMAL][TRAINER_FLANNERY_4] = { #line 14841 .trainerName = _("FLANNERY"), @@ -37294,7 +37289,7 @@ F_TRAINER_FEMALE | }, }, #line 14898 - [TRAINER_FLANNERY_5] = + [DIFFICULTY_NORMAL][TRAINER_FLANNERY_5] = { #line 14899 .trainerName = _("FLANNERY"), @@ -37433,7 +37428,7 @@ F_TRAINER_FEMALE | }, }, #line 14956 - [TRAINER_NORMAN_2] = + [DIFFICULTY_NORMAL][TRAINER_NORMAN_2] = { #line 14957 .trainerName = _("NORMAN"), @@ -37532,7 +37527,7 @@ F_TRAINER_FEMALE | }, }, #line 14998 - [TRAINER_NORMAN_3] = + [DIFFICULTY_NORMAL][TRAINER_NORMAN_3] = { #line 14999 .trainerName = _("NORMAN"), @@ -37649,7 +37644,7 @@ F_TRAINER_FEMALE | }, }, #line 15048 - [TRAINER_NORMAN_4] = + [DIFFICULTY_NORMAL][TRAINER_NORMAN_4] = { #line 15049 .trainerName = _("NORMAN"), @@ -37766,7 +37761,7 @@ F_TRAINER_FEMALE | }, }, #line 15098 - [TRAINER_NORMAN_5] = + [DIFFICULTY_NORMAL][TRAINER_NORMAN_5] = { #line 15099 .trainerName = _("NORMAN"), @@ -37901,7 +37896,7 @@ F_TRAINER_FEMALE | }, }, #line 15156 - [TRAINER_WINONA_2] = + [DIFFICULTY_NORMAL][TRAINER_WINONA_2] = { #line 15157 .trainerName = _("WINONA"), @@ -38020,7 +38015,7 @@ F_TRAINER_FEMALE | }, }, #line 15206 - [TRAINER_WINONA_3] = + [DIFFICULTY_NORMAL][TRAINER_WINONA_3] = { #line 15207 .trainerName = _("WINONA"), @@ -38157,7 +38152,7 @@ F_TRAINER_FEMALE | }, }, #line 15264 - [TRAINER_WINONA_4] = + [DIFFICULTY_NORMAL][TRAINER_WINONA_4] = { #line 15265 .trainerName = _("WINONA"), @@ -38294,7 +38289,7 @@ F_TRAINER_FEMALE | }, }, #line 15322 - [TRAINER_WINONA_5] = + [DIFFICULTY_NORMAL][TRAINER_WINONA_5] = { #line 15323 .trainerName = _("WINONA"), @@ -38431,7 +38426,7 @@ F_TRAINER_FEMALE | }, }, #line 15380 - [TRAINER_TATE_AND_LIZA_2] = + [DIFFICULTY_NORMAL][TRAINER_TATE_AND_LIZA_2] = { #line 15381 .trainerName = _("TATE&LIZA"), @@ -38550,7 +38545,7 @@ F_TRAINER_FEMALE | }, }, #line 15430 - [TRAINER_TATE_AND_LIZA_3] = + [DIFFICULTY_NORMAL][TRAINER_TATE_AND_LIZA_3] = { #line 15431 .trainerName = _("TATE&LIZA"), @@ -38687,7 +38682,7 @@ F_TRAINER_FEMALE | }, }, #line 15488 - [TRAINER_TATE_AND_LIZA_4] = + [DIFFICULTY_NORMAL][TRAINER_TATE_AND_LIZA_4] = { #line 15489 .trainerName = _("TATE&LIZA"), @@ -38824,7 +38819,7 @@ F_TRAINER_FEMALE | }, }, #line 15546 - [TRAINER_TATE_AND_LIZA_5] = + [DIFFICULTY_NORMAL][TRAINER_TATE_AND_LIZA_5] = { #line 15547 .trainerName = _("TATE&LIZA"), @@ -38961,7 +38956,7 @@ F_TRAINER_FEMALE | }, }, #line 15604 - [TRAINER_JUAN_2] = + [DIFFICULTY_NORMAL][TRAINER_JUAN_2] = { #line 15605 .trainerName = _("JUAN"), @@ -39078,7 +39073,7 @@ F_TRAINER_FEMALE | }, }, #line 15654 - [TRAINER_JUAN_3] = + [DIFFICULTY_NORMAL][TRAINER_JUAN_3] = { #line 15655 .trainerName = _("JUAN"), @@ -39195,7 +39190,7 @@ F_TRAINER_FEMALE | }, }, #line 15704 - [TRAINER_JUAN_4] = + [DIFFICULTY_NORMAL][TRAINER_JUAN_4] = { #line 15705 .trainerName = _("JUAN"), @@ -39330,7 +39325,7 @@ F_TRAINER_FEMALE | }, }, #line 15762 - [TRAINER_JUAN_5] = + [DIFFICULTY_NORMAL][TRAINER_JUAN_5] = { #line 15763 .trainerName = _("JUAN"), @@ -39465,7 +39460,7 @@ F_TRAINER_FEMALE | }, }, #line 15820 - [TRAINER_ANGELO] = + [DIFFICULTY_NORMAL][TRAINER_ANGELO] = { #line 15821 .trainerName = _("ANGELO"), @@ -39520,7 +39515,7 @@ F_TRAINER_FEMALE | }, }, #line 15843 - [TRAINER_DARIUS] = + [DIFFICULTY_NORMAL][TRAINER_DARIUS] = { #line 15844 .trainerName = _("DARIUS"), @@ -39552,7 +39547,7 @@ F_TRAINER_FEMALE | }, }, #line 15856 - [TRAINER_STEVEN] = + [DIFFICULTY_NORMAL][TRAINER_STEVEN] = { #line 15857 .trainerName = _("STEVEN"), @@ -39685,7 +39680,7 @@ F_TRAINER_FEMALE | }, }, #line 15914 - [TRAINER_ANABEL] = + [DIFFICULTY_NORMAL][TRAINER_ANABEL] = { #line 15915 .trainerName = _("ANABEL"), @@ -39719,7 +39714,7 @@ F_TRAINER_FEMALE | }, }, #line 15927 - [TRAINER_TUCKER] = + [DIFFICULTY_NORMAL][TRAINER_TUCKER] = { #line 15928 .trainerName = _("TUCKER"), @@ -39751,7 +39746,7 @@ F_TRAINER_FEMALE | }, }, #line 15940 - [TRAINER_SPENSER] = + [DIFFICULTY_NORMAL][TRAINER_SPENSER] = { #line 15941 .trainerName = _("SPENSER"), @@ -39783,7 +39778,7 @@ F_TRAINER_FEMALE | }, }, #line 15953 - [TRAINER_GRETA] = + [DIFFICULTY_NORMAL][TRAINER_GRETA] = { #line 15954 .trainerName = _("GRETA"), @@ -39817,7 +39812,7 @@ F_TRAINER_FEMALE | }, }, #line 15966 - [TRAINER_NOLAND] = + [DIFFICULTY_NORMAL][TRAINER_NOLAND] = { #line 15967 .trainerName = _("NOLAND"), @@ -39849,7 +39844,7 @@ F_TRAINER_FEMALE | }, }, #line 15979 - [TRAINER_LUCY] = + [DIFFICULTY_NORMAL][TRAINER_LUCY] = { #line 15980 .trainerName = _("LUCY"), @@ -39883,7 +39878,7 @@ F_TRAINER_FEMALE | }, }, #line 15992 - [TRAINER_BRANDON] = + [DIFFICULTY_NORMAL][TRAINER_BRANDON] = { #line 15993 .trainerName = _("BRANDON"), @@ -39915,7 +39910,7 @@ F_TRAINER_FEMALE | }, }, #line 16005 - [TRAINER_ANDRES_2] = + [DIFFICULTY_NORMAL][TRAINER_ANDRES_2] = { #line 16006 .trainerName = _("ANDRES"), @@ -39958,7 +39953,7 @@ F_TRAINER_FEMALE | }, }, #line 16022 - [TRAINER_ANDRES_3] = + [DIFFICULTY_NORMAL][TRAINER_ANDRES_3] = { #line 16023 .trainerName = _("ANDRES"), @@ -40012,7 +40007,7 @@ F_TRAINER_FEMALE | }, }, #line 16043 - [TRAINER_ANDRES_4] = + [DIFFICULTY_NORMAL][TRAINER_ANDRES_4] = { #line 16044 .trainerName = _("ANDRES"), @@ -40066,7 +40061,7 @@ F_TRAINER_FEMALE | }, }, #line 16064 - [TRAINER_ANDRES_5] = + [DIFFICULTY_NORMAL][TRAINER_ANDRES_5] = { #line 16065 .trainerName = _("ANDRES"), @@ -40120,7 +40115,7 @@ F_TRAINER_FEMALE | }, }, #line 16085 - [TRAINER_CORY_2] = + [DIFFICULTY_NORMAL][TRAINER_CORY_2] = { #line 16086 .trainerName = _("CORY"), @@ -40174,7 +40169,7 @@ F_TRAINER_FEMALE | }, }, #line 16106 - [TRAINER_CORY_3] = + [DIFFICULTY_NORMAL][TRAINER_CORY_3] = { #line 16107 .trainerName = _("CORY"), @@ -40228,7 +40223,7 @@ F_TRAINER_FEMALE | }, }, #line 16127 - [TRAINER_CORY_4] = + [DIFFICULTY_NORMAL][TRAINER_CORY_4] = { #line 16128 .trainerName = _("CORY"), @@ -40282,7 +40277,7 @@ F_TRAINER_FEMALE | }, }, #line 16148 - [TRAINER_CORY_5] = + [DIFFICULTY_NORMAL][TRAINER_CORY_5] = { #line 16149 .trainerName = _("CORY"), @@ -40336,7 +40331,7 @@ F_TRAINER_FEMALE | }, }, #line 16169 - [TRAINER_PABLO_2] = + [DIFFICULTY_NORMAL][TRAINER_PABLO_2] = { #line 16170 .trainerName = _("PABLO"), @@ -40379,7 +40374,7 @@ F_TRAINER_FEMALE | }, }, #line 16186 - [TRAINER_PABLO_3] = + [DIFFICULTY_NORMAL][TRAINER_PABLO_3] = { #line 16187 .trainerName = _("PABLO"), @@ -40433,7 +40428,7 @@ F_TRAINER_FEMALE | }, }, #line 16207 - [TRAINER_PABLO_4] = + [DIFFICULTY_NORMAL][TRAINER_PABLO_4] = { #line 16208 .trainerName = _("PABLO"), @@ -40487,7 +40482,7 @@ F_TRAINER_FEMALE | }, }, #line 16228 - [TRAINER_PABLO_5] = + [DIFFICULTY_NORMAL][TRAINER_PABLO_5] = { #line 16229 .trainerName = _("PABLO"), @@ -40541,7 +40536,7 @@ F_TRAINER_FEMALE | }, }, #line 16249 - [TRAINER_KOJI_2] = + [DIFFICULTY_NORMAL][TRAINER_KOJI_2] = { #line 16250 .trainerName = _("KOJI"), @@ -40584,7 +40579,7 @@ F_TRAINER_FEMALE | }, }, #line 16266 - [TRAINER_KOJI_3] = + [DIFFICULTY_NORMAL][TRAINER_KOJI_3] = { #line 16267 .trainerName = _("KOJI"), @@ -40638,7 +40633,7 @@ F_TRAINER_FEMALE | }, }, #line 16287 - [TRAINER_KOJI_4] = + [DIFFICULTY_NORMAL][TRAINER_KOJI_4] = { #line 16288 .trainerName = _("KOJI"), @@ -40692,7 +40687,7 @@ F_TRAINER_FEMALE | }, }, #line 16308 - [TRAINER_KOJI_5] = + [DIFFICULTY_NORMAL][TRAINER_KOJI_5] = { #line 16309 .trainerName = _("KOJI"), @@ -40746,7 +40741,7 @@ F_TRAINER_FEMALE | }, }, #line 16329 - [TRAINER_CRISTIN_2] = + [DIFFICULTY_NORMAL][TRAINER_CRISTIN_2] = { #line 16330 .trainerName = _("CRISTIN"), @@ -40793,7 +40788,7 @@ F_TRAINER_FEMALE | }, }, #line 16347 - [TRAINER_CRISTIN_3] = + [DIFFICULTY_NORMAL][TRAINER_CRISTIN_3] = { #line 16348 .trainerName = _("CRISTIN"), @@ -40851,7 +40846,7 @@ F_TRAINER_FEMALE | }, }, #line 16369 - [TRAINER_CRISTIN_4] = + [DIFFICULTY_NORMAL][TRAINER_CRISTIN_4] = { #line 16370 .trainerName = _("CRISTIN"), @@ -40909,7 +40904,7 @@ F_TRAINER_FEMALE | }, }, #line 16391 - [TRAINER_CRISTIN_5] = + [DIFFICULTY_NORMAL][TRAINER_CRISTIN_5] = { #line 16392 .trainerName = _("CRISTIN"), @@ -40967,7 +40962,7 @@ F_TRAINER_FEMALE | }, }, #line 16413 - [TRAINER_FERNANDO_2] = + [DIFFICULTY_NORMAL][TRAINER_FERNANDO_2] = { #line 16414 .trainerName = _("FERNANDO"), @@ -41021,7 +41016,7 @@ F_TRAINER_FEMALE | }, }, #line 16434 - [TRAINER_FERNANDO_3] = + [DIFFICULTY_NORMAL][TRAINER_FERNANDO_3] = { #line 16435 .trainerName = _("FERNANDO"), @@ -41075,7 +41070,7 @@ F_TRAINER_FEMALE | }, }, #line 16455 - [TRAINER_FERNANDO_4] = + [DIFFICULTY_NORMAL][TRAINER_FERNANDO_4] = { #line 16456 .trainerName = _("FERNANDO"), @@ -41129,7 +41124,7 @@ F_TRAINER_FEMALE | }, }, #line 16476 - [TRAINER_FERNANDO_5] = + [DIFFICULTY_NORMAL][TRAINER_FERNANDO_5] = { #line 16477 .trainerName = _("FERNANDO"), @@ -41183,7 +41178,7 @@ F_TRAINER_FEMALE | }, }, #line 16497 - [TRAINER_SAWYER_2] = + [DIFFICULTY_NORMAL][TRAINER_SAWYER_2] = { #line 16498 .trainerName = _("SAWYER"), @@ -41226,7 +41221,7 @@ F_TRAINER_FEMALE | }, }, #line 16514 - [TRAINER_SAWYER_3] = + [DIFFICULTY_NORMAL][TRAINER_SAWYER_3] = { #line 16515 .trainerName = _("SAWYER"), @@ -41280,7 +41275,7 @@ F_TRAINER_FEMALE | }, }, #line 16535 - [TRAINER_SAWYER_4] = + [DIFFICULTY_NORMAL][TRAINER_SAWYER_4] = { #line 16536 .trainerName = _("SAWYER"), @@ -41334,7 +41329,7 @@ F_TRAINER_FEMALE | }, }, #line 16556 - [TRAINER_SAWYER_5] = + [DIFFICULTY_NORMAL][TRAINER_SAWYER_5] = { #line 16557 .trainerName = _("SAWYER"), @@ -41388,7 +41383,7 @@ F_TRAINER_FEMALE | }, }, #line 16577 - [TRAINER_GABRIELLE_2] = + [DIFFICULTY_NORMAL][TRAINER_GABRIELLE_2] = { #line 16578 .trainerName = _("GABRIELLE"), @@ -41477,7 +41472,7 @@ F_TRAINER_FEMALE | }, }, #line 16610 - [TRAINER_GABRIELLE_3] = + [DIFFICULTY_NORMAL][TRAINER_GABRIELLE_3] = { #line 16611 .trainerName = _("GABRIELLE"), @@ -41566,7 +41561,7 @@ F_TRAINER_FEMALE | }, }, #line 16643 - [TRAINER_GABRIELLE_4] = + [DIFFICULTY_NORMAL][TRAINER_GABRIELLE_4] = { #line 16644 .trainerName = _("GABRIELLE"), @@ -41655,7 +41650,7 @@ F_TRAINER_FEMALE | }, }, #line 16676 - [TRAINER_GABRIELLE_5] = + [DIFFICULTY_NORMAL][TRAINER_GABRIELLE_5] = { #line 16677 .trainerName = _("GABRIELLE"), @@ -41744,7 +41739,7 @@ F_TRAINER_FEMALE | }, }, #line 16709 - [TRAINER_THALIA_2] = + [DIFFICULTY_NORMAL][TRAINER_THALIA_2] = { #line 16710 .trainerName = _("THALIA"), @@ -41789,7 +41784,7 @@ F_TRAINER_FEMALE | }, }, #line 16726 - [TRAINER_THALIA_3] = + [DIFFICULTY_NORMAL][TRAINER_THALIA_3] = { #line 16727 .trainerName = _("THALIA"), @@ -41845,7 +41840,7 @@ F_TRAINER_FEMALE | }, }, #line 16747 - [TRAINER_THALIA_4] = + [DIFFICULTY_NORMAL][TRAINER_THALIA_4] = { #line 16748 .trainerName = _("THALIA"), @@ -41901,7 +41896,7 @@ F_TRAINER_FEMALE | }, }, #line 16768 - [TRAINER_THALIA_5] = + [DIFFICULTY_NORMAL][TRAINER_THALIA_5] = { #line 16769 .trainerName = _("THALIA"), @@ -41957,7 +41952,7 @@ F_TRAINER_FEMALE | }, }, #line 16789 - [TRAINER_MARIELA] = + [DIFFICULTY_NORMAL][TRAINER_MARIELA] = { #line 16790 .trainerName = _("MARIELA"), @@ -41989,7 +41984,7 @@ F_TRAINER_FEMALE | }, }, #line 16801 - [TRAINER_ALVARO] = + [DIFFICULTY_NORMAL][TRAINER_ALVARO] = { #line 16802 .trainerName = _("ALVARO"), @@ -42030,7 +42025,7 @@ F_TRAINER_FEMALE | }, }, #line 16817 - [TRAINER_EVERETT] = + [DIFFICULTY_NORMAL][TRAINER_EVERETT] = { #line 16818 .trainerName = _("EVERETT"), @@ -42060,7 +42055,7 @@ F_TRAINER_FEMALE | }, }, #line 16829 - [TRAINER_RED] = + [DIFFICULTY_NORMAL][TRAINER_RED] = { #line 16830 .trainerName = _("RED"), @@ -42090,7 +42085,7 @@ F_TRAINER_FEMALE | }, }, #line 16841 - [TRAINER_LEAF] = + [DIFFICULTY_NORMAL][TRAINER_LEAF] = { #line 16842 .trainerName = _("LEAF"), @@ -42122,7 +42117,7 @@ F_TRAINER_FEMALE | }, }, #line 16853 - [TRAINER_BRENDAN_PLACEHOLDER] = + [DIFFICULTY_NORMAL][TRAINER_BRENDAN_PLACEHOLDER] = { #line 16854 .trainerName = _("BRENDAN"), @@ -42152,7 +42147,7 @@ F_TRAINER_FEMALE | }, }, #line 16865 - [TRAINER_MAY_PLACEHOLDER] = + [DIFFICULTY_NORMAL][TRAINER_MAY_PLACEHOLDER] = { #line 16866 .trainerName = _("MAY"), diff --git a/src/data/types_info.h b/src/data/types_info.h index d14012ed5c55..ea962b4a44f5 100644 --- a/src/data/types_info.h +++ b/src/data/types_info.h @@ -40,10 +40,12 @@ const uq4_12_t gTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] #undef ______ #undef X -// .generic is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT. -// In this array there's commented-out data such as references to type-resist berries that would otherwise would go unused. -// However, we figured this information would be useful for users that want to add their own types as a reminder of -// what data would they need to add in order to have their new types be fully fledged like official types. +// Notes regarding custom data: +// - The "generic" field is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT. +// - In this array there's commented-out data such as references to type-resist berries that would otherwise would go unused. +// However, we figured this information would be useful for users that want to add their own types as a reminder of +// what data would they need to add in order to have their new types be fully fledged like official types. +// - Changing "isHiddenPowerType" for any type will change the distribution of all Hidden Power types from vanilla. const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = { [TYPE_NONE] = @@ -56,6 +58,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_NormalTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = TRUE, + .isHiddenPowerType = FALSE, }, [TYPE_NORMAL] = { @@ -69,6 +72,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_NormalTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = FALSE, //.enhanceItem = ITEM_SILK_SCARF, //.berry = ITEM_CHILAN_BERRY, //.gem = ITEM_NORMAL_GEM, @@ -88,6 +92,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_FightingTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_BLACK_BELT, //.berry = ITEM_CHOPLE_BERRY, //.gem = ITEM_FIGHTING_GEM, @@ -109,6 +114,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_FlyingTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_SHARP_BEAK, //.berry = ITEM_COBA_BERRY, //.gem = ITEM_FLYING_GEM, @@ -130,6 +136,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_PoisonTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_POISON_BARB, //.berry = ITEM_KEBIA_BERRY, //.gem = ITEM_POISON_GEM, @@ -151,6 +158,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_GroundTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_SOFT_SAND, //.berry = ITEM_SHUCA_BERRY, //.gem = ITEM_GROUND_GEM, @@ -172,6 +180,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_RockTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_HARD_STONE, //.berry = ITEM_CHARTI_BERRY, //.gem = ITEM_ROCK_GEM, @@ -193,6 +202,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_BugTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_SILVER_POWDER, //.berry = ITEM_TANGA_BERRY, //.gem = ITEM_BUG_GEM, @@ -214,6 +224,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_GhostTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_SPELL_TAG, //.berry = ITEM_KASIB_BERRY, //.gem = ITEM_GHOST_GEM, @@ -235,6 +246,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_SteelTMHM, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_METAL_COAT, //.berry = ITEM_BABIRI_BERRY, //.gem = ITEM_STEEL_GEM, @@ -253,6 +265,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .damageCategory = DAMAGE_CATEGORY_SPECIAL, .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = TRUE, + .isHiddenPowerType = FALSE, }, [TYPE_FIRE] = { @@ -266,6 +279,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_FireTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_CHARCOAL, //.berry = ITEM_OCCA_BERRY, //.gem = ITEM_FIRE_GEM, @@ -287,6 +301,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_WaterTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_MYSTIC_WATER, //.berry = ITEM_PASSHO_BERRY, //.gem = ITEM_WATER_GEM, @@ -308,6 +323,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_GrassTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_MIRACLE_SEED, //.berry = ITEM_RINDO_BERRY, //.gem = ITEM_GRASS_GEM, @@ -329,6 +345,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_ElectricTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_MAGNET, //.berry = ITEM_WACAN_BERRY, //.gem = ITEM_ELECTRIC_GEM, @@ -350,6 +367,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_PsychicTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_TWISTED_SPOON, //.berry = ITEM_PAYAPA_BERRY, //.gem = ITEM_PSYCHIC_GEM, @@ -371,6 +389,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_IceTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_NEVER_MELT_ICE, //.berry = ITEM_YACHE_BERRY, //.gem = ITEM_ICE_GEM, @@ -392,6 +411,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_DragonTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_DRAGON_FANG, //.berry = ITEM_HABAN_BERRY, //.gem = ITEM_DRAGON_GEM, @@ -413,6 +433,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_DarkTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = TRUE, //.enhanceItem = ITEM_BLACK_GLASSES, //.berry = ITEM_COLBUR_BERRY, //.gem = ITEM_DARK_GEM, @@ -434,6 +455,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_FairyTMHM, .useSecondTypeIconPalette = TRUE, .isSpecialCaseType = FALSE, + .isHiddenPowerType = FALSE, //.enhanceItem = ITEM_FAIRY_FEATHER, //.berry = ITEM_ROSELI_BERRY, //.gem = ITEM_FAIRY_GEM, @@ -454,6 +476,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe .useSecondTypeIconPalette = FALSE, .isSpecialCaseType = TRUE, + .isHiddenPowerType = FALSE, // .teraShard = ITEM_STELLAR_TERA_SHARD, }, }; diff --git a/src/data/wild_encounters.json.txt b/src/data/wild_encounters.json.txt index bf848249f018..20ac1c788958 100755 --- a/src/data/wild_encounters.json.txt +++ b/src/data/wild_encounters.json.txt @@ -64,8 +64,19 @@ const struct WildPokemon {{ encounter.base_label }}_FishingMons[] = const struct WildPokemonInfo {{ encounter.base_label }}_FishingMonsInfo = { {{encounter.fishing_mons.encounter_rate}}, {{ encounter.base_label }}_FishingMons }; {% endif %} + +{% if existsIn(encounter, "hidden_mons") %} +const struct WildPokemon {{ encounter.base_label }}_HiddenMons[] = +{ +## for wild_mon in encounter.hidden_mons.mons + { {{ wild_mon.min_level }}, {{ wild_mon.max_level }}, {{ wild_mon.species }} }, ## endfor +}; +const struct WildPokemonInfo {{ encounter.base_label }}_HiddenMonsInfo = { {{encounter.hidden_mons.encounter_rate}}, {{ encounter.base_label }}_HiddenMons }; +{% endif %} + +## endfor const struct WildPokemonHeader {{ wild_encounter_group.label }}[] = { ## for encounter in wild_encounter_group.encounters @@ -76,6 +87,7 @@ const struct WildPokemonHeader {{ wild_encounter_group.label }}[] = .waterMonsInfo = {% if existsIn(encounter, "water_mons") %}&{{ encounter.base_label }}_WaterMonsInfo{% else %}NULL{% endif %}, .rockSmashMonsInfo = {% if existsIn(encounter, "rock_smash_mons") %}&{{ encounter.base_label }}_RockSmashMonsInfo{% else %}NULL{% endif %}, .fishingMonsInfo = {% if existsIn(encounter, "fishing_mons") %}&{{ encounter.base_label }}_FishingMonsInfo{% else %}NULL{% endif %}, + .hiddenMonsInfo = {% if existsIn(encounter, "hidden_mons") %}&{{ encounter.base_label }}_HiddenMonsInfo{% else %}NULL{% endif %}, }, ## endfor { @@ -85,6 +97,7 @@ const struct WildPokemonHeader {{ wild_encounter_group.label }}[] = .waterMonsInfo = NULL, .rockSmashMonsInfo = NULL, .fishingMonsInfo = NULL, + .hiddenMonsInfo = NULL, }, }; ## endfor diff --git a/src/daycare.c b/src/daycare.c index 4997f4efe913..26b86ec1e257 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -33,7 +33,6 @@ static void ClearDaycareMonMail(struct DaycareMail *mail); static void SetInitialEggData(struct Pokemon *mon, u16 species, struct DayCare *daycare); static void DaycarePrintMonInfo(u8 windowId, u32 daycareSlotId, u8 y); static u8 ModifyBreedingScoreForOvalCharm(u8 score); -static u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves); static u16 GetEggSpecies(u16 species); // RAM buffers used to assist with BuildEggMoveset() @@ -331,8 +330,8 @@ static void ApplyDaycareExperience(struct Pokemon *mon) static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon) { - u16 species; - u16 newSpecies; + u32 species; + u32 newSpecies; u32 experience; struct Pokemon pokemon; @@ -341,7 +340,7 @@ static u16 TakeSelectedPokemonFromDaycare(struct DaycareMon *daycareMon) BoxMonToMon(&daycareMon->mon, &pokemon); newSpecies = GetFormChangeTargetSpecies(&pokemon, FORM_CHANGE_WITHDRAW, 0); - if (newSpecies != SPECIES_NONE) + if (newSpecies != species) { SetMonData(&pokemon, MON_DATA_SPECIES, &newSpecies); CalculateMonStats(&pokemon); @@ -751,7 +750,7 @@ static void InheritAbility(struct Pokemon *egg, struct BoxPokemon *father, struc // Counts the number of egg moves a Pokémon learns and stores the moves in // the given array. -static u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves) +u8 GetEggMoves(struct Pokemon *pokemon, u16 *eggMoves) { u16 numEggMoves; u16 species; diff --git a/src/debug.c b/src/debug.c index 3615ef1997f5..267c5d5ab970 100644 --- a/src/debug.c +++ b/src/debug.c @@ -158,6 +158,7 @@ enum FlagsVarsDebugMenu DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_RUN_SHOES, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_LOCATIONS, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BADGES_ALL, + DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_GAME_CLEAR, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_FRONTIER_PASS, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_COLLISION, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_ENCOUNTER, @@ -292,6 +293,9 @@ struct DebugMonData u8 mon_ev_speed; u8 mon_ev_satk; u8 mon_ev_sdef; + u8 teraType; + u8 dynamaxLevel:7; + u8 gmaxFactor:1; }; struct DebugMenuListData @@ -412,6 +416,7 @@ static void DebugAction_FlagsVars_SwitchPokeNav(u8 taskId); static void DebugAction_FlagsVars_SwitchMatchCall(u8 taskId); static void DebugAction_FlagsVars_ToggleFlyFlags(u8 taskId); static void DebugAction_FlagsVars_ToggleBadgeFlags(u8 taskId); +static void DebugAction_FlagsVars_ToggleGameClear(u8 taskId); static void DebugAction_FlagsVars_ToggleFrontierPass(u8 taskId); static void DebugAction_FlagsVars_CollisionOnOff(u8 taskId); static void DebugAction_FlagsVars_EncounterOnOff(u8 taskId); @@ -432,6 +437,9 @@ static void DebugAction_Give_Pokemon_SelectLevel(u8 taskId); static void DebugAction_Give_Pokemon_SelectShiny(u8 taskId); static void DebugAction_Give_Pokemon_SelectNature(u8 taskId); static void DebugAction_Give_Pokemon_SelectAbility(u8 taskId); +static void DebugAction_Give_Pokemon_SelectTeraType(u8 taskId); +static void DebugAction_Give_Pokemon_SelectDynamaxLevel(u8 taskId); +static void DebugAction_Give_Pokemon_SelectGigantamaxFactor(u8 taskId); static void DebugAction_Give_Pokemon_SelectIVs(u8 taskId); static void DebugAction_Give_Pokemon_SelectEVs(u8 taskId); static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId); @@ -577,6 +585,7 @@ static const u8 sDebugText_FlagsVars_SwitchMatchCall[] = _("Toggle {STR_VAR_ static const u8 sDebugText_FlagsVars_RunningShoes[] = _("Toggle {STR_VAR_1}Running Shoes"); static const u8 sDebugText_FlagsVars_ToggleFlyFlags[] = _("Toggle {STR_VAR_1}Fly Flags"); static const u8 sDebugText_FlagsVars_ToggleAllBadges[] = _("Toggle {STR_VAR_1}All badges"); +static const u8 sDebugText_FlagsVars_ToggleGameClear[] = _("Toggle {STR_VAR_1}Game clear"); static const u8 sDebugText_FlagsVars_ToggleFrontierPass[] = _("Toggle {STR_VAR_1}Frontier Pass"); static const u8 sDebugText_FlagsVars_SwitchCollision[] = _("Toggle {STR_VAR_1}Collision OFF"); static const u8 sDebugText_FlagsVars_SwitchEncounter[] = _("Toggle {STR_VAR_1}Encounter OFF"); @@ -628,6 +637,9 @@ static const u8 sDebugText_PokemonLevel[] = _("Level:{CLEAR_TO 90}\n static const u8 sDebugText_PokemonShiny[] = _("Shiny:{CLEAR_TO 90}\n {STR_VAR_2}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{CLEAR_TO 90}"); static const u8 sDebugText_PokemonNature[] = _("Nature ID: {STR_VAR_3}{CLEAR_TO 90}\n{STR_VAR_1}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); static const u8 sDebugText_PokemonAbility[] = _("Ability Num: {STR_VAR_3}{CLEAR_TO 90}\n{STR_VAR_1}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); +static const u8 sDebugText_PokemonTeraType[] = _("Tera Type: {STR_VAR_3}{CLEAR_TO 90}\n{STR_VAR_1}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); +static const u8 sDebugText_PokemonDynamaxLevel[] = _("Dmax Lvl:{CLEAR_TO 90}\n{STR_VAR_1}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); +static const u8 sDebugText_PokemonGmaxFactor[] = _("Gmax Factor:{CLEAR_TO 90}\n {STR_VAR_2}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{CLEAR_TO 90}"); static const u8 sDebugText_PokemonIVs[] = _("All IVs:{CLEAR_TO 90}\n {STR_VAR_3}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); static const u8 sDebugText_PokemonEVs[] = _("All EVs:{CLEAR_TO 90}\n {STR_VAR_3}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); static const u8 sDebugText_IV_HP[] = _("IV HP:{CLEAR_TO 90}\n {STR_VAR_3}{CLEAR_TO 90}\n{CLEAR_TO 90}\n{STR_VAR_2}{CLEAR_TO 90}"); @@ -787,6 +799,7 @@ static const struct ListMenuItem sDebugMenu_Items_FlagsVars[] = [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_RUN_SHOES] = {sDebugText_FlagsVars_RunningShoes, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_RUN_SHOES}, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_LOCATIONS] = {sDebugText_FlagsVars_ToggleFlyFlags, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_LOCATIONS}, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BADGES_ALL] = {sDebugText_FlagsVars_ToggleAllBadges, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BADGES_ALL}, + [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_GAME_CLEAR] = {sDebugText_FlagsVars_ToggleGameClear, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_GAME_CLEAR}, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_FRONTIER_PASS] = {sDebugText_FlagsVars_ToggleFrontierPass, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_FRONTIER_PASS}, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_COLLISION] = {sDebugText_FlagsVars_SwitchCollision, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_COLLISION}, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_ENCOUNTER] = {sDebugText_FlagsVars_SwitchEncounter, DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_ENCOUNTER}, @@ -958,6 +971,7 @@ static void (*const sDebugMenu_Actions_Flags[])(u8) = [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_RUN_SHOES] = DebugAction_FlagsVars_RunningShoes, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_LOCATIONS] = DebugAction_FlagsVars_ToggleFlyFlags, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_BADGES_ALL] = DebugAction_FlagsVars_ToggleBadgeFlags, + [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_GAME_CLEAR] = DebugAction_FlagsVars_ToggleGameClear, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_FRONTIER_PASS] = DebugAction_FlagsVars_ToggleFrontierPass, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_COLLISION] = DebugAction_FlagsVars_CollisionOnOff, [DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_ENCOUNTER] = DebugAction_FlagsVars_EncounterOnOff, @@ -1237,6 +1251,32 @@ static void Debug_DestroyMenu_Full_Script(u8 taskId, const u8 *script) ScriptContext_SetupScript(script); } +static void Debug_HandleInput_Numeric(u8 taskId, s32 min, s32 max, u32 digits) +{ + if (JOY_NEW(DPAD_UP)) + { + gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; + if (gTasks[taskId].tInput > max) + gTasks[taskId].tInput = max; + } + if (JOY_NEW(DPAD_DOWN)) + { + gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; + if (gTasks[taskId].tInput < min) + gTasks[taskId].tInput = min; + } + if (JOY_NEW(DPAD_LEFT)) + { + if (gTasks[taskId].tDigit > 0) + gTasks[taskId].tDigit -= 1; + } + if (JOY_NEW(DPAD_RIGHT)) + { + if (gTasks[taskId].tDigit < digits - 1) + gTasks[taskId].tDigit += 1; + } +} + static void DebugAction_Cancel(u8 taskId) { Debug_DestroyMenu_Full(taskId); @@ -1308,6 +1348,9 @@ static u8 Debug_CheckToggleFlags(u8 id) FlagGet(FLAG_BADGE07_GET) && FlagGet(FLAG_BADGE08_GET); break; + case DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_GAME_CLEAR: + result = FlagGet(FLAG_SYS_GAME_CLEAR); + break; case DEBUG_FLAGVAR_MENU_ITEM_TOGGLE_FRONTIER_PASS: result = FlagGet(FLAG_SYS_FRONTIER_PASS); break; @@ -1943,28 +1986,7 @@ static void DebugAction_Util_Warp_SelectMapGroup(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > LAST_MAP_GROUP) - gTasks[taskId].tInput = LAST_MAP_GROUP; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 0) - gTasks[taskId].tInput = 0; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 2) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 0, LAST_MAP_GROUP, 3); ConvertIntToDecimalStringN(gStringVar1, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 3); ConvertIntToDecimalStringN(gStringVar2, LAST_MAP_GROUP, STR_CONV_MODE_LEADING_ZEROS, 3); @@ -2004,28 +2026,7 @@ static void DebugAction_Util_Warp_SelectMap(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > max_value - 1) - gTasks[taskId].tInput = max_value - 1; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 0) - gTasks[taskId].tInput = 0; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 2) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 0, max_value - 1, 3); ConvertIntToDecimalStringN(gStringVar1, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, (max_value >= 100) ? 3 : 2); ConvertIntToDecimalStringN(gStringVar2, MAP_GROUP_COUNT[gTasks[taskId].tMapGroup] - 1, STR_CONV_MODE_LEADING_ZEROS, (max_value >= 100) ? 3 : 2); @@ -2249,29 +2250,7 @@ static void DebugAction_Util_Weather_SelectId(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > WEATHER_ROUTE123_CYCLE) - gTasks[taskId].tInput = WEATHER_ROUTE123_CYCLE; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < WEATHER_NONE) - gTasks[taskId].tInput = WEATHER_NONE; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 2) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, WEATHER_NONE, WEATHER_COUNT - 1, 3); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); @@ -2466,34 +2445,8 @@ static void DebugAction_FlagsVars_FlagsSelect(u8 taskId) return; } - if (JOY_NEW(DPAD_UP)) - { - PlaySE(SE_SELECT); - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput >= FLAGS_COUNT) - gTasks[taskId].tInput = FLAGS_COUNT - 1; - } - if (JOY_NEW(DPAD_DOWN)) - { - PlaySE(SE_SELECT); - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 1) - gTasks[taskId].tInput = 1; - } - if (JOY_NEW(DPAD_LEFT)) - { - PlaySE(SE_SELECT); - gTasks[taskId].tDigit -= 1; - if (gTasks[taskId].tDigit < 0) - gTasks[taskId].tDigit = 0; - } - if (JOY_NEW(DPAD_RIGHT)) - { - PlaySE(SE_SELECT); - gTasks[taskId].tDigit += 1; - if (gTasks[taskId].tDigit > DEBUG_NUMBER_DIGITS_FLAGS - 1) - gTasks[taskId].tDigit = DEBUG_NUMBER_DIGITS_FLAGS - 1; - } + PlaySE(SE_SELECT); + Debug_HandleInput_Numeric(taskId, 1, FLAGS_COUNT - 1, DEBUG_NUMBER_DIGITS_FLAGS); if (JOY_NEW(DPAD_ANY) || JOY_NEW(A_BUTTON)) { @@ -2545,30 +2498,7 @@ static void DebugAction_FlagsVars_Vars(u8 taskId) static void DebugAction_FlagsVars_Select(u8 taskId) { - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > VARS_END) - gTasks[taskId].tInput = VARS_END; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < VARS_START) - gTasks[taskId].tInput = VARS_START; - } - if (JOY_NEW(DPAD_LEFT)) - { - gTasks[taskId].tDigit -= 1; - if (gTasks[taskId].tDigit < 0) - gTasks[taskId].tDigit = 0; - } - if (JOY_NEW(DPAD_RIGHT)) - { - gTasks[taskId].tDigit += 1; - if (gTasks[taskId].tDigit > DEBUG_NUMBER_DIGITS_VARIABLES - 1) - gTasks[taskId].tDigit = DEBUG_NUMBER_DIGITS_VARIABLES - 1; - } + Debug_HandleInput_Numeric(taskId, VARS_START, VARS_END, DEBUG_NUMBER_DIGITS_VARIABLES); if (JOY_NEW(DPAD_ANY)) { @@ -2862,6 +2792,16 @@ static void DebugAction_FlagsVars_ToggleBadgeFlags(u8 taskId) } } +static void DebugAction_FlagsVars_ToggleGameClear(u8 taskId) +{ + // Sound effect + if (FlagGet(FLAG_SYS_GAME_CLEAR)) + PlaySE(SE_PC_OFF); + else + PlaySE(SE_PC_LOGIN); + FlagToggle(FLAG_SYS_GAME_CLEAR); +} + static void DebugAction_FlagsVars_ToggleFrontierPass(u8 taskId) { // Sound effect @@ -2981,29 +2921,7 @@ static void DebugAction_Give_Item_SelectId(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput >= ITEMS_COUNT) - gTasks[taskId].tInput = ITEMS_COUNT - 1; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 1) - gTasks[taskId].tInput = 1; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < DEBUG_NUMBER_DIGITS_ITEMS - 1) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 1, ITEMS_COUNT - 1, DEBUG_NUMBER_DIGITS_ITEMS); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); u8* end = CopyItemName(gTasks[taskId].tInput, gStringVar1); @@ -3056,29 +2974,7 @@ static void DebugAction_Give_Item_SelectQuantity(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > MAX_BAG_ITEM_CAPACITY) - gTasks[taskId].tInput = MAX_BAG_ITEM_CAPACITY; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 1) - gTasks[taskId].tInput = 1; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < MAX_ITEM_DIGITS) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 1, MAX_BAG_ITEM_CAPACITY, MAX_ITEM_DIGITS); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); ConvertIntToDecimalStringN(gStringVar1, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, DEBUG_NUMBER_DIGITS_ITEM_QUANTITY); @@ -3121,6 +3017,9 @@ static void ResetMonDataStruct(struct DebugMonData *sDebugMonData) sDebugMonData->isShiny = FALSE; sDebugMonData->nature = 0; sDebugMonData->abilityNum = 0; + sDebugMonData->teraType = TYPE_NONE; + sDebugMonData->dynamaxLevel = 0; + sDebugMonData->gmaxFactor = FALSE; sDebugMonData->mon_iv_hp = 0; sDebugMonData->mon_iv_atk = 0; sDebugMonData->mon_iv_def = 0; @@ -3226,29 +3125,7 @@ static void DebugAction_Give_Pokemon_SelectId(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput >= NUM_SPECIES) - gTasks[taskId].tInput = NUM_SPECIES - 1; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 1) - gTasks[taskId].tInput = 1; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < DEBUG_NUMBER_DIGITS_ITEMS - 1) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 1, NUM_SPECIES - 1, DEBUG_NUMBER_DIGITS_ITEMS); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); u8 *end = StringCopy(gStringVar1, GetSpeciesName(gTasks[taskId].tInput)); //CopyItemName(gTasks[taskId].tInput, gStringVar1); @@ -3294,29 +3171,7 @@ static void DebugAction_Give_Pokemon_SelectLevel(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > MAX_LEVEL) - gTasks[taskId].tInput = MAX_LEVEL; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 1) - gTasks[taskId].tInput = 1; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 2) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 1, MAX_LEVEL, 3); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); ConvertIntToDecimalStringN(gStringVar1, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 3); @@ -3411,8 +3266,8 @@ static void DebugAction_Give_Pokemon_SelectNature(u8 taskId) if (JOY_NEW(DPAD_UP)) { gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > NUM_NATURES-1) - gTasks[taskId].tInput = NUM_NATURES-1; + if (gTasks[taskId].tInput > NUM_NATURES - 1) + gTasks[taskId].tInput = NUM_NATURES - 1; } if (JOY_NEW(DPAD_DOWN)) { @@ -3501,10 +3356,11 @@ static void DebugAction_Give_Pokemon_SelectAbility(u8 taskId) StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 15); - StringExpandPlaceholders(gStringVar4, sDebugText_IV_HP); + StringCopy(gStringVar1, gTypesInfo[0].name); + StringExpandPlaceholders(gStringVar4, sDebugText_PokemonTeraType); AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); - gTasks[taskId].func = DebugAction_Give_Pokemon_SelectIVs; + gTasks[taskId].func = DebugAction_Give_Pokemon_SelectTeraType; } else if (JOY_NEW(B_BUTTON)) { @@ -3514,7 +3370,7 @@ static void DebugAction_Give_Pokemon_SelectAbility(u8 taskId) } } -static void DebugAction_Give_Pokemon_SelectIVs(u8 taskId) +static void DebugAction_Give_Pokemon_SelectTeraType(u8 taskId) { if (JOY_NEW(DPAD_ANY)) { @@ -3523,8 +3379,8 @@ static void DebugAction_Give_Pokemon_SelectIVs(u8 taskId) if (JOY_NEW(DPAD_UP)) { gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > MAX_PER_STAT_IVS) - gTasks[taskId].tInput = MAX_PER_STAT_IVS; + if (gTasks[taskId].tInput > NUMBER_OF_MON_TYPES - 1) + gTasks[taskId].tInput = NUMBER_OF_MON_TYPES - 1; } if (JOY_NEW(DPAD_DOWN)) { @@ -3532,16 +3388,119 @@ static void DebugAction_Give_Pokemon_SelectIVs(u8 taskId) if (gTasks[taskId].tInput < 0) gTasks[taskId].tInput = 0; } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 2) - gTasks[taskId].tDigit += 1; - } + + StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); + ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); + StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 15); + StringCopy(gStringVar1, gTypesInfo[gTasks[taskId].tInput].name); + StringExpandPlaceholders(gStringVar4, sDebugText_PokemonTeraType); + AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); + } + + if (JOY_NEW(A_BUTTON)) + { + sDebugMonData->teraType = gTasks[taskId].tInput; + gTasks[taskId].tInput = 0; + gTasks[taskId].tDigit = 0; + + StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); + ConvertIntToDecimalStringN(gStringVar1, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); + StringCopyPadded(gStringVar1, gStringVar1, CHAR_SPACE, 15); + StringExpandPlaceholders(gStringVar4, sDebugText_PokemonDynamaxLevel); + AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); + + gTasks[taskId].func = DebugAction_Give_Pokemon_SelectDynamaxLevel; + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + Free(sDebugMonData); + DebugAction_DestroyExtraWindow(taskId); + } +} + +static void DebugAction_Give_Pokemon_SelectDynamaxLevel(u8 taskId) +{ + if (JOY_NEW(DPAD_ANY)) + { + PlaySE(SE_SELECT); + Debug_HandleInput_Numeric(taskId, 0, MAX_DYNAMAX_LEVEL, 2); + + StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); + ConvertIntToDecimalStringN(gStringVar1, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); + StringCopyPadded(gStringVar1, gStringVar1, CHAR_SPACE, 15); + StringExpandPlaceholders(gStringVar4, sDebugText_PokemonDynamaxLevel); + AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); + } + + if (JOY_NEW(A_BUTTON)) + { + sDebugMonData->dynamaxLevel = gTasks[taskId].tInput; + gTasks[taskId].tInput = 0; + gTasks[taskId].tDigit = 0; + + ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 0); + StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 15); + StringCopyPadded(gStringVar2, sDebugText_False, CHAR_SPACE, 15); + StringExpandPlaceholders(gStringVar4, sDebugText_PokemonGmaxFactor); + AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); + + gTasks[taskId].func = DebugAction_Give_Pokemon_SelectGigantamaxFactor; + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + Free(sDebugMonData); + FreeMonIconPalettes(); + FreeAndDestroyMonIconSprite(&gSprites[gTasks[taskId].tSpriteId]); + DebugAction_DestroyExtraWindow(taskId); + } +} + +static void DebugAction_Give_Pokemon_SelectGigantamaxFactor(u8 taskId) +{ + static const u8 *txtStr; + + if (JOY_NEW(DPAD_ANY)) + { + PlaySE(SE_SELECT); + gTasks[taskId].tInput ^= JOY_NEW(DPAD_UP | DPAD_DOWN) > 0; + txtStr = (gTasks[taskId].tInput == TRUE) ? sDebugText_True : sDebugText_False; + StringCopyPadded(gStringVar2, txtStr, CHAR_SPACE, 15); + ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 0); + StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 15); + StringExpandPlaceholders(gStringVar4, sDebugText_PokemonGmaxFactor); + AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); + } + + if (JOY_NEW(A_BUTTON)) + { + sDebugMonData->gmaxFactor = gTasks[taskId].tInput; + gTasks[taskId].tInput = 0; + gTasks[taskId].tDigit = 0; + + StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); + ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); + StringCopyPadded(gStringVar3, gStringVar3, CHAR_SPACE, 15); + StringExpandPlaceholders(gStringVar4, sDebugText_IV_HP); + AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); + + gTasks[taskId].func = DebugAction_Give_Pokemon_SelectIVs; + } + else if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_SELECT); + Free(sDebugMonData); + DebugAction_DestroyExtraWindow(taskId); + } +} + +static void DebugAction_Give_Pokemon_SelectIVs(u8 taskId) +{ + if (JOY_NEW(DPAD_ANY)) + { + PlaySE(SE_SELECT); + Debug_HandleInput_Numeric(taskId, 0, MAX_PER_STAT_IVS, 3); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 2); @@ -3669,29 +3628,7 @@ static void DebugAction_Give_Pokemon_SelectEVs(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > MAX_PER_STAT_EVS) - gTasks[taskId].tInput = MAX_PER_STAT_EVS; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 0) - gTasks[taskId].tInput = 0; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 3) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 0, MAX_PER_STAT_EVS, 4); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, 3); @@ -3831,29 +3768,7 @@ static void DebugAction_Give_Pokemon_Move(u8 taskId) if (JOY_NEW(DPAD_ANY)) { PlaySE(SE_SELECT); - - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput >= MOVES_COUNT) - gTasks[taskId].tInput = MOVES_COUNT - 1; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 0) - gTasks[taskId].tInput = 0; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < 3) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 0, MOVES_COUNT - 1, 4); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); u8 *end = StringCopy(gStringVar1, GetMoveName(gTasks[taskId].tInput)); @@ -3965,6 +3880,9 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu bool8 isShiny = sDebugMonData->isShiny; u8 nature = sDebugMonData->nature; u8 abilityNum = sDebugMonData->abilityNum; + u32 teraType = sDebugMonData->teraType; + u32 dmaxLevel = sDebugMonData->dynamaxLevel; + u32 gmaxFactor = sDebugMonData->gmaxFactor; moves[0] = sDebugMonData->mon_move_0; moves[1] = sDebugMonData->mon_move_1; moves[2] = sDebugMonData->mon_move_2; @@ -3985,16 +3903,27 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu //Nature if (nature == NUM_NATURES || nature == 0xFF) nature = Random() % NUM_NATURES; - CreateMonWithNature(&mon, species, level, 32, nature); + CreateMonWithNature(&mon, species, level, USE_RANDOM_IVS, nature); //Shininess SetMonData(&mon, MON_DATA_IS_SHINY, &isShiny); + // Gigantamax factor + SetMonData(&mon, MON_DATA_GIGANTAMAX_FACTOR, &gmaxFactor); + + // Dynamax Level + SetMonData(&mon, MON_DATA_DYNAMAX_LEVEL, &dmaxLevel); + + // tera type + if (teraType >= NUMBER_OF_MON_TYPES) + teraType = TYPE_NONE; + SetMonData(&mon, MON_DATA_TERA_TYPE, &teraType); + //IVs for (i = 0; i < NUM_STATS; i++) { iv_val = IVs[i]; - if (iv_val != 32 && iv_val != 0xFF) + if (iv_val != USE_RANDOM_IVS && iv_val != 0xFF) SetMonData(&mon, MON_DATA_HP_IV + i, &iv_val); } @@ -4009,18 +3938,18 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu //Moves for (i = 0; i < MAX_MON_MOVES; i++) { - if (moves[i] == 0 || moves[i] == 0xFF || moves[i] >= MOVES_COUNT) + if (moves[i] == MOVE_NONE || moves[i] == 0xFF || moves[i] >= MOVES_COUNT) continue; SetMonMoveSlot(&mon, moves[i], i); } //Ability - if (abilityNum == 0xFF || GetAbilityBySpecies(species, abilityNum) == 0) + if (abilityNum == 0xFF || GetAbilityBySpecies(species, abilityNum) == ABILITY_NONE) { do { - abilityNum = Random() % 3; // includes hidden abilities - } while (GetAbilityBySpecies(species, abilityNum) == 0); + abilityNum = Random() % NUM_ABILITY_SLOTS; // includes hidden abilities + } while (GetAbilityBySpecies(species, abilityNum) == ABILITY_NONE); } SetMonData(&mon, MON_DATA_ABILITY_NUM, &abilityNum); @@ -4038,7 +3967,9 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu } if (i >= PARTY_SIZE) + { sentToPc = CopyMonToPC(&mon); + } else { sentToPc = MON_GIVEN_TO_PARTY; @@ -4296,31 +4227,10 @@ static void DebugAction_Sound_SE_SelectId(u8 taskId) { if (JOY_NEW(DPAD_ANY)) { - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > END_SE) - gTasks[taskId].tInput = END_SE; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < 1) - gTasks[taskId].tInput = 1; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < DEBUG_NUMBER_DIGITS_ITEMS - 1) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, 1, END_SE, DEBUG_NUMBER_DIGITS_ITEMS); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); - StringCopyPadded(gStringVar1, sSENames[gTasks[taskId].tInput-1], CHAR_SPACE, 35); + StringCopyPadded(gStringVar1, sSENames[gTasks[taskId].tInput - 1], CHAR_SPACE, 35); ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, DEBUG_NUMBER_DIGITS_ITEMS); StringExpandPlaceholders(gStringVar4, sDebugText_Sound_SFX_ID); AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); @@ -4378,31 +4288,10 @@ static void DebugAction_Sound_MUS_SelectId(u8 taskId) { if (JOY_NEW(DPAD_ANY)) { - if (JOY_NEW(DPAD_UP)) - { - gTasks[taskId].tInput += sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput > END_MUS) - gTasks[taskId].tInput = END_MUS; - } - if (JOY_NEW(DPAD_DOWN)) - { - gTasks[taskId].tInput -= sPowersOfTen[gTasks[taskId].tDigit]; - if (gTasks[taskId].tInput < START_MUS) - gTasks[taskId].tInput = START_MUS; - } - if (JOY_NEW(DPAD_LEFT)) - { - if (gTasks[taskId].tDigit > 0) - gTasks[taskId].tDigit -= 1; - } - if (JOY_NEW(DPAD_RIGHT)) - { - if (gTasks[taskId].tDigit < DEBUG_NUMBER_DIGITS_ITEMS - 1) - gTasks[taskId].tDigit += 1; - } + Debug_HandleInput_Numeric(taskId, START_MUS, END_MUS, DEBUG_NUMBER_DIGITS_ITEMS); StringCopy(gStringVar2, gText_DigitIndicator[gTasks[taskId].tDigit]); - StringCopyPadded(gStringVar1, sBGMNames[gTasks[taskId].tInput-START_MUS], CHAR_SPACE, 35); + StringCopyPadded(gStringVar1, sBGMNames[gTasks[taskId].tInput - START_MUS], CHAR_SPACE, 35); ConvertIntToDecimalStringN(gStringVar3, gTasks[taskId].tInput, STR_CONV_MODE_LEADING_ZEROS, DEBUG_NUMBER_DIGITS_ITEMS); StringExpandPlaceholders(gStringVar4, sDebugText_Sound_Music_ID); AddTextPrinterParameterized(gTasks[taskId].tSubWindowId, DEBUG_MENU_FONT, gStringVar4, 0, 0, 0, NULL); diff --git a/src/decoration.c b/src/decoration.c index d450ad7dfba0..2b8973c8151c 100644 --- a/src/decoration.c +++ b/src/decoration.c @@ -113,7 +113,6 @@ EWRAM_DATA static u16 sDecorationsCursorPos = 0; EWRAM_DATA static u16 sDecorationsScrollOffset = 0; EWRAM_DATA u8 gCurDecorationIndex = 0; EWRAM_DATA static u8 sCurDecorationCategory = DECORCAT_DESK; -EWRAM_DATA static u32 UNUSED sFiller[2] = {}; EWRAM_DATA static struct DecorationPCContext sDecorationContext = {}; EWRAM_DATA static u8 sDecorMenuWindowIds[WINDOW_COUNT] = {}; EWRAM_DATA static struct DecorationItemsMenu *sDecorationItemsMenu = NULL; diff --git a/src/dexnav.c b/src/dexnav.c new file mode 100644 index 000000000000..9247ff77a39d --- /dev/null +++ b/src/dexnav.c @@ -0,0 +1,2689 @@ +#include "global.h" +#include "battle_main.h" +#include "battle_setup.h" +#include "bg.h" +#include "data.h" +#include "daycare.h" +#include "decompress.h" +#include "dexnav.h" +#include "event_data.h" +#include "event_object_movement.h" +#include "event_scripts.h" +#include "field_effect.h" +#include "field_effect_helpers.h" +#include "field_message_box.h" +#include "field_player_avatar.h" +#include "field_screen_effect.h" +#include "fieldmap.h" +#include "gpu_regs.h" +#include "graphics.h" +#include "item.h" +#include "international_string_util.h" +#include "m4a.h" +#include "map_name_popup.h" +#include "main.h" +#include "malloc.h" +#include "menu.h" +#include "menu_helpers.h" +#include "metatile_behavior.h" +#include "move.h" +#include "overworld.h" +#include "palette.h" +#include "party_menu.h" +#include "pokedex.h" +#include "pokemon.h" +#include "pokemon_icon.h" +#include "pokemon_summary_screen.h" +#include "random.h" +#include "region_map.h" +#include "scanline_effect.h" +#include "script.h" +#include "script_pokemon_util.h" +#include "sound.h" +#include "sprite.h" +#include "start_menu.h" +#include "string_util.h" +#include "strings.h" +#include "task.h" +#include "text.h" +#include "text_window.h" +#include "wild_encounter.h" +#include "window.h" +#include "constants/map_types.h" +#include "constants/species.h" +#include "constants/maps.h" +#include "constants/field_effects.h" +#include "constants/items.h" +#include "constants/songs.h" +#include "constants/abilities.h" +#include "constants/rgb.h" +#include "constants/region_map_sections.h" +#include "gba/m4a_internal.h" + +#if DEXNAV_ENABLED +STATIC_ASSERT(FLAG_SYS_DEXNAV_SEARCH != 0, FlagSysDexNavSearch_Must_Not_Be_Zero); +STATIC_ASSERT(FLAG_SYS_DETECTOR_MODE != 0, FlagSysDetectorMode_Must_Not_Be_Zero); +STATIC_ASSERT(VAR_DEXNAV_SPECIES != 0, VarDexNavSpecies_Must_Not_Be_Zero); +STATIC_ASSERT(VAR_DEXNAV_STEP_COUNTER != 0, VarDexNavStepCounter_Must_Not_Be_Zero); +#endif + +// Defines +enum WindowIds +{ + WINDOW_INFO, + WINDOW_REGISTERED, + WINDOW_COUNT, +}; + +enum Statuses +{ + STATUS_INVALID_SEARCH, + STATUS_CHOOSE_MON, + STATUS_LOCKED, + STATUS_NO_DATA, + STATUS_INCORRECT_AREA, +}; + +struct DexNavSearch +{ + u16 species; + u16 moves[MAX_MON_MOVES]; + u16 heldItem; + u8 abilityNum; + u8 potential; + u8 searchLevel; + u8 monLevel; + u8 proximity; + u8 environment; + s16 tileX; + s16 tileY; + u8 fldEffSpriteId; + u8 fldEffId; + u8 movementCount; + u8 windowId; + u8 iconSpriteId; + u8 eyeSpriteId; + u8 itemSpriteId; + u8 starSpriteIds[3]; + u8 ownedIconSpriteId; + u8 exclamationSpriteId; + u8 hiddenSearch:1; + u8 isHiddenMon:1; + u8 unk:6; + u16 palBuffer[16]; +}; + +struct DexNavGUI +{ + MainCallback savedCallback; + u8 state; + u8 cursorSpriteId; + u16 landSpecies[LAND_WILD_COUNT]; + u16 waterSpecies[WATER_WILD_COUNT]; + u16 hiddenSpecies[HIDDEN_WILD_COUNT]; + u8 cursorRow; + u8 cursorCol; + u8 environment; + u8 potential; + u8 typeIconSpriteIds[2]; + u8 starSpriteIds[3]; +}; + +// RAM + +EWRAM_DATA static struct DexNavSearch *sDexNavSearchDataPtr = NULL; +EWRAM_DATA static struct DexNavGUI *sDexNavUiDataPtr = NULL; +EWRAM_DATA static u8 *sBg1TilemapBuffer = NULL; +EWRAM_DATA bool8 gDexNavBattle = FALSE; + +//// Function Declarations +//GUI +static void Task_DexNavWaitFadeIn(u8 taskId); +static void Task_DexNavMain(u8 taskId); +static void PrintCurrentSpeciesInfo(void); +// SEARCH +static bool8 TryStartHiddenMonFieldEffect(u8 environment, u8 xSize, u8 ySize, bool8 smallScan); +static void DexNavGenerateMoveset(u16 species, u8 searchLevel, u8 encounterLevel, u16* moveDst); +static u16 DexNavGenerateHeldItem(u16 species, u8 searchLevel); +static u8 DexNavGetAbilityNum(u16 species, u8 searchLevel); +static u8 DexNavGeneratePotential(u8 searchLevel); +static u8 DexNavTryGenerateMonLevel(u16 species, u8 environment); +static u8 GetEncounterLevelFromMapData(u16 species, u8 environment); +static void CreateDexNavWildMon(u16 species, u8 potential, u8 level, u8 abilityNum, u16 item, u16* moves); +static u8 GetPlayerDistance(s16 x, s16 y); +static u8 DexNavPickTile(u8 environment, u8 xSize, u8 ySize, bool8 smallScan); +static void DexNavProximityUpdate(void); +static void DexNavDrawIcons(void); +static void DexNavUpdateSearchWindow(u8 proximity, u8 searchLevel); +static void Task_DexNavSearch(u8 taskId); +static void EndDexNavSearchSetupScript(const u8 *script, u8 taskId); +// HIDDEN MONS +static void DexNavDrawHiddenIcons(void); +static void DrawHiddenSearchWindow(u8 width); + +//// Const Data +// gui image data +static const u32 sDexNavGuiTiles[] = INCBIN_U32("graphics/dexnav/gui_tiles.4bpp.lz"); +static const u32 sDexNavGuiTilemap[] = INCBIN_U32("graphics/dexnav/gui_tilemap.bin.lz"); +static const u32 sDexNavGuiPal[] = INCBIN_U32("graphics/dexnav/gui.gbapal"); + +static const u32 sSelectionCursorGfx[] = INCBIN_U32("graphics/dexnav/cursor.4bpp.lz"); +static const u16 sSelectionCursorPal[] = INCBIN_U16("graphics/dexnav/cursor.gbapal"); +static const u32 sCapturedAllMonsTiles[] = INCBIN_U32("graphics/dexnav/captured_all.4bpp.lz"); //uses selection cursor pal + +static const u32 sNoDataGfx[] = INCBIN_U32("graphics/dexnav/no_data.4bpp.lz"); + +// searching image data +static const u32 sPotentialStarGfx[] = INCBIN_U32("graphics/dexnav/star.4bpp.lz"); +static const u32 sHiddenSearchIconGfx[] = INCBIN_U32("graphics/dexnav/hidden_search.4bpp.lz"); +static const u32 sOwnedIconGfx[] = INCBIN_U32("graphics/dexnav/owned_icon.4bpp.lz"); +static const u32 sHiddenMonIconGfx[] = INCBIN_U32("graphics/dexnav/hidden.4bpp.lz"); + +// strings +static const u8 sText_DexNav_NoInfo[] = _("--------"); +static const u8 sText_DexNav_CaptureToSee[] = _("Capture first!"); +static const u8 sText_DexNav_PressRToRegister[] = _("R TO REGISTER!"); +static const u8 sText_DexNav_SearchForRegisteredSpecies[] = _("Search {STR_VAR_1}"); +static const u8 sText_DexNav_NotFoundHere[] = _("This Pokémon cannot be found here!"); +static const u8 sText_ThreeQmarks[] = _("???"); +static const u8 sText_SearchLevel[] = _("SEARCH {LV}. {STR_VAR_1}"); +static const u8 sText_MonLevel[] = _("{LV}. {STR_VAR_1}"); +static const u8 sText_EggMove[] = _("MOVE: {STR_VAR_1}"); +static const u8 sText_HeldItem[] = _("{STR_VAR_1}"); +static const u8 sText_StartExit[] = _("{START_BUTTON} EXIT"); +static const u8 sText_DexNavChain[] = _("{NO} {STR_VAR_1}"); +static const u8 sText_DexNavChainLong[] = _("{NO}{STR_VAR_1}"); + +static const u8 sText_ArrowLeft[] = _("{LEFT_ARROW}"); +static const u8 sText_ArrowRight[] = _("{RIGHT_ARROW}"); +static const u8 sText_ArrowUp[] = _("{UP_ARROW}"); +static const u8 sText_ArrowDown[] = _("{DOWN_ARROW}"); + +static const struct WindowTemplate sDexNavGuiWindowTemplates[] = +{ + [WINDOW_INFO] = + { + .bg = 0, + .tilemapLeft = 21, + .tilemapTop = 5, + .width = 9, + .height = 15, + .paletteNum = 15, + .baseBlock = 1, + }, + [WINDOW_REGISTERED] = + { + .bg = 0, + .tilemapLeft = 4, + .tilemapTop = 0, + .width = 26, + .height = 2, + .paletteNum = 15, + .baseBlock = 200, + }, + DUMMY_WIN_TEMPLATE +}; + +//gui font +static const u8 sFontColor_Black[3] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_DARK_GRAY, TEXT_COLOR_LIGHT_GRAY}; +static const u8 sFontColor_White[3] = {TEXT_COLOR_TRANSPARENT, TEXT_COLOR_WHITE, TEXT_COLOR_DARK_GRAY}; +//search window font +static const u8 sSearchFontColor[3] = {0, 15, 13}; + +static const struct OamData sNoDataIconOam = +{ + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .shape = SPRITE_SHAPE(32x32), + .size = SPRITE_SIZE(32x32), + .priority = 1, +}; + +static const struct OamData sHeldItemOam = +{ + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .shape = SPRITE_SHAPE(8x8), + .size = SPRITE_SIZE(8x8), + .priority = 0, + .paletteNum = 13, +}; + +static const struct OamData sCapturedAllOam = +{ + .y = 0, + .affineMode = 1, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = SPRITE_SHAPE(8x8), + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(8x8), + .tileNum = 0, + .priority = 0, //Highest + .paletteNum = 12, + .affineParam = 0, +}; + +static const struct OamData sSearchIconOam = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(32x32), + .tileNum = 0, + .priority = 0, // above BG layers + .paletteNum = 13, + .affineParam = 0 +}; + +static const struct OamData sSelectionCursorOam = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = 0, + .x = 0, + .matrixNum = 0, + .size = SPRITE_SIZE(32x32), + .tileNum = 0, + .priority = 0, // above BG layers + .paletteNum = 12, + .affineParam = 0 +}; + +static const struct OamData sSightOam = +{ + .affineMode = ST_OAM_AFFINE_OFF, + .objMode = ST_OAM_OBJ_NORMAL, + .shape = SPRITE_SHAPE(16x8), + .size = SPRITE_SIZE(16x8), + .priority = 0, +}; +static const union AnimCmd sAnimCmdSight0[] = +{ + ANIMCMD_FRAME(0, 1), + ANIMCMD_END +}; +static const union AnimCmd sAnimCmdSight1[] = +{ + ANIMCMD_FRAME(2, 1), + ANIMCMD_END +}; +static const union AnimCmd sAnimCmdSight2[] = +{ + ANIMCMD_FRAME(4, 1), + ANIMCMD_END +}; +static const union AnimCmd *const sAnimCmdTable_Sight[] = +{ + sAnimCmdSight0, + sAnimCmdSight1, + sAnimCmdSight2, +}; + +// gui sprite templates +static const struct SpriteTemplate sNoDataIconTemplate = +{ + .tileTag = ICON_GFX_TAG, + .paletteTag = ICON_PAL_TAG, + .oam = &sNoDataIconOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct SpriteTemplate sCaptureAllMonsSpriteTemplate = +{ + .tileTag = CAPTURED_ALL_TAG, + .paletteTag = 0xFFFF, + .oam = &sCapturedAllOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct SpriteTemplate sSelectionCursorSpriteTemplate = +{ + .tileTag = SELECTION_CURSOR_TAG, + .paletteTag = 0xFFFF, + .oam = &sSelectionCursorOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +// search window sprite templates +static const struct SpriteTemplate sHeldItemTemplate = +{ + .tileTag = HELD_ITEM_TAG, + .paletteTag = 0xFFFF, + .oam = &sHeldItemOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct SpriteTemplate sPotentialStarTemplate = +{ + .tileTag = LIT_STAR_TILE_TAG, + .paletteTag = 0xFFFF, //held item pal + .oam = &sHeldItemOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct SpriteTemplate sSearchIconSpriteTemplate = +{ + .tileTag = HIDDEN_SEARCH_TAG, + .paletteTag = 0xFFFF, //held item pal + .oam = &sSearchIconOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct SpriteTemplate sOwnedIconTemplate = +{ + .tileTag = OWNED_ICON_TAG, + .paletteTag = 0xFFFF, //held item pal + .oam = &sHeldItemOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +static const struct SpriteTemplate sHiddenMonIconTemplate = +{ + .tileTag = HIDDEN_MON_ICON_TAG, + .paletteTag = 0xFFFF, //held item pal + .oam = &sHeldItemOam, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCallbackDummy, +}; + +// gui sprite sheets +static const struct CompressedSpriteSheet sNoDataIconSpriteSheet = {sNoDataGfx, (32 * 32) / 2, ICON_GFX_TAG}; +static const struct CompressedSpriteSheet sCapturedAllPokemonSpriteSheet = {sCapturedAllMonsTiles, (8 * 8) / 2, CAPTURED_ALL_TAG}; +// search sprite sheets +static const struct CompressedSpriteSheet sPotentialStarSpriteSheet = {sPotentialStarGfx, (8 * 8) / 2, LIT_STAR_TILE_TAG}; +static const struct CompressedSpriteSheet sOwnedIconSpriteSheet = {sOwnedIconGfx, (8 * 8) / 2, OWNED_ICON_TAG}; +static const struct CompressedSpriteSheet sHiddenMonIconSpriteSheet = {sHiddenMonIconGfx, (8 * 8) / 2, HIDDEN_MON_ICON_TAG}; + +//// functions +/////////////////////// +//// DEXNAV SEARCH //// +/////////////////////// +static s16 GetSearchWindowY(void) +{ + return (GetWindowAttribute(sDexNavSearchDataPtr->windowId, WINDOW_TILEMAP_TOP) * 8); +} + +#define SPECIES_ICON_X 28 +static void DrawDexNavSearchMonIcon(u16 species, u8 *dst, bool8 owned) +{ + u8 spriteId; + + LoadMonIconPalette(species); + spriteId = CreateMonIcon(species, SpriteCB_MonIcon, SPECIES_ICON_X - 6, GetSearchWindowY() + 8, 0, 0xFFFFFFFF); + gSprites[spriteId].oam.priority = 0; + *dst = spriteId; + + if (owned) + sDexNavSearchDataPtr->ownedIconSpriteId = CreateSprite(&sOwnedIconTemplate, SPECIES_ICON_X + 6, GetSearchWindowY() + 4, 0); +} + +static void AddSearchWindow(u8 width) +{ + struct WindowTemplate template; + u16 y = 16; + + if (sDexNavSearchDataPtr->tileY > (gSaveBlock1Ptr->pos.y + 7)) + y = 1; //draw at top if chosen tile is below + + LoadDexNavWindowGfx(sDexNavSearchDataPtr->windowId, 0x1d5, 14 * 16); + + SetWindowTemplateFields(&template, 0, 1, y, width, 3, 14, 8); + + sDexNavSearchDataPtr->windowId = AddWindow(&template); + FillWindowPixelBuffer(sDexNavSearchDataPtr->windowId, PIXEL_FILL(1)); + PutWindowTilemap(sDexNavSearchDataPtr->windowId); + CopyWindowToVram(sDexNavSearchDataPtr->windowId, 3); + + DrawStdFrameWithCustomTileAndPalette(sDexNavSearchDataPtr->windowId, TRUE, 0x214, 14); +} + +#define WINDOW_COL_0 (SPECIES_ICON_X + 4) +#define WINDOW_COL_1 (WINDOW_COL_0 + (GetFontAttribute(sDexNavSearchDataPtr->windowId, FONTATTR_MAX_LETTER_WIDTH) * (POKEMON_NAME_LENGTH))) +#define WINDOW_MOVE_NAME_X (WINDOW_COL_1 + (GetFontAttribute(sDexNavSearchDataPtr->windowId, FONTATTR_MAX_LETTER_WIDTH) * 6)) +#define SEARCH_ARROW_X (WINDOW_MOVE_NAME_X + 90) +#define SEARCH_ARROW_Y 0 + +static void AddSearchWindowText(u16 species, u8 proximity, u8 searchLevel, bool8 hidden) +{ + u8 windowId = sDexNavSearchDataPtr->windowId; + + //species name - always present + if (hidden) + { + StringCopy(gStringVar4, sText_ThreeQmarks); + AddTextPrinterParameterized3(sDexNavSearchDataPtr->windowId, 0, WINDOW_COL_0, 0, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar4); + return; + } + else + { + StringCopy(gStringVar1, GetSpeciesName(species)); + AddTextPrinterParameterized3(sDexNavSearchDataPtr->windowId, 0, WINDOW_COL_0, 0, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar1); + } + + //level - always present + ConvertIntToDecimalStringN(gStringVar1, sDexNavSearchDataPtr->monLevel, STR_CONV_MODE_LEFT_ALIGN, 3); + StringExpandPlaceholders(gStringVar4, sText_MonLevel); + AddTextPrinterParameterized3(sDexNavSearchDataPtr->windowId, 0, WINDOW_COL_1, 0, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar4); + + if (proximity <= SNEAKING_PROXIMITY) + { + PlaySE(SE_POKENAV_ON); + // move + if (searchLevel > 1 && sDexNavSearchDataPtr->moves[0]) + { + StringCopy(gStringVar1, GetMoveName(sDexNavSearchDataPtr->moves[0])); + StringExpandPlaceholders(gStringVar4, sText_EggMove); + AddTextPrinterParameterized3(windowId, 0, WINDOW_MOVE_NAME_X, 0, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar4); + } + + if (searchLevel > 2) + { + // ability name + StringCopy(gStringVar1, gAbilitiesInfo[GetAbilityBySpecies(species, sDexNavSearchDataPtr->abilityNum)].name); + AddTextPrinterParameterized3(windowId, 0, WINDOW_COL_1 + 16, 12, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar1); + + // item name + if (sDexNavSearchDataPtr->heldItem) + { + CopyItemName(sDexNavSearchDataPtr->heldItem, gStringVar1); + StringExpandPlaceholders(gStringVar4, sText_HeldItem); + AddTextPrinterParameterized3(windowId, 0, WINDOW_COL_0, 12, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar4); + } + } + } + + //chain level - always present + ConvertIntToDecimalStringN(gStringVar1, gSaveBlock3Ptr->dexNavChain, STR_CONV_MODE_LEFT_ALIGN, 3); + if (gSaveBlock3Ptr->dexNavChain > 99) + StringExpandPlaceholders(gStringVar4, sText_DexNavChainLong); + else + StringExpandPlaceholders(gStringVar4, sText_DexNavChain); + AddTextPrinterParameterized3(windowId, 0, SEARCH_ARROW_X - 16, 12, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar4); + + CopyWindowToVram(sDexNavSearchDataPtr->windowId, 2); +} + +#define SEARCH_WINDOW_WIDTH 28 + +static void DrawSearchWindow(u16 species, u8 potential, bool8 hidden) +{ + u8 searchLevel = sDexNavSearchDataPtr->searchLevel; + + AddSearchWindow(SEARCH_WINDOW_WIDTH); + AddSearchWindowText(species, sDexNavSearchDataPtr->proximity, searchLevel, hidden); +} + +#undef SEARCH_WINDOW_WIDTH + +static void RemoveDexNavWindowAndGfx(void) +{ + u32 i; + + // try remove sprites + if (sDexNavSearchDataPtr->iconSpriteId != MAX_SPRITES) + DestroySprite(&gSprites[sDexNavSearchDataPtr->iconSpriteId]); + if (sDexNavSearchDataPtr->itemSpriteId != MAX_SPRITES) + DestroySprite(&gSprites[sDexNavSearchDataPtr->itemSpriteId]); + if (sDexNavSearchDataPtr->eyeSpriteId != MAX_SPRITES) + DestroySprite(&gSprites[sDexNavSearchDataPtr->eyeSpriteId]); + if (sDexNavSearchDataPtr->ownedIconSpriteId != MAX_SPRITES) + DestroySprite(&gSprites[sDexNavSearchDataPtr->ownedIconSpriteId]); + if (sDexNavSearchDataPtr->exclamationSpriteId != MAX_SPRITES) + DestroySprite(&gSprites[sDexNavSearchDataPtr->exclamationSpriteId]); + + for (i = 0; i < NELEMS(sDexNavSearchDataPtr->starSpriteIds); i++) + { + if (sDexNavSearchDataPtr->starSpriteIds[i] != MAX_SPRITES) + DestroySprite(&gSprites[sDexNavSearchDataPtr->starSpriteIds[i]]); + } + + FreeSpriteTilesByTag(HELD_ITEM_TAG); + FreeSpriteTilesByTag(OWNED_ICON_TAG); + FreeSpriteTilesByTag(HIDDEN_SEARCH_TAG); + FreeSpriteTilesByTag(HIDDEN_MON_ICON_TAG); + FreeSpriteTilesByTag(LIT_STAR_TILE_TAG); + FreeSpritePaletteByTag(HELD_ITEM_TAG); + SafeFreeMonIconPalette(sDexNavSearchDataPtr->species); + + // remove window + ClearStdWindowAndFrameToTransparent(sDexNavSearchDataPtr->windowId, FALSE); + CopyWindowToVram(sDexNavSearchDataPtr->windowId, 3); + RemoveWindow(sDexNavSearchDataPtr->windowId); +} + + +////////////////////// +////DEXNAV SEARCH///// +////////////////////// +static u8 GetPlayerDistance(s16 x, s16 y) +{ + u16 deltaX = abs(x - (gSaveBlock1Ptr->pos.x + 7)); + u16 deltaY = abs(y - (gSaveBlock1Ptr->pos.y + 7)); + return deltaX + deltaY; +} + +static void DexNavProximityUpdate(void) +{ + sDexNavSearchDataPtr->proximity = GetPlayerDistance(sDexNavSearchDataPtr->tileX, sDexNavSearchDataPtr->tileY); +} + +//Pick a specific tile based on environment +static bool8 DexNavPickTile(u8 environment, u8 areaX, u8 areaY, bool8 smallScan) +{ + // area of map to cover starting from camera position {-7, -7} + s16 topX = gSaveBlock1Ptr->pos.x - SCANSTART_X + (smallScan * 5); + s16 topY = gSaveBlock1Ptr->pos.y - SCANSTART_Y + (smallScan * 5); + s16 botX = topX + areaX; + s16 botY = topY + areaY; + u8 i; + bool8 nextIter; + u8 scale = 0; + u8 weight = 0; + u8 currMapType = GetCurrentMapType(); + u8 tileBehaviour; + u8 tileBuffer = 2; + u8 *xPos = AllocZeroed((botX - topX) * (botY - topY) * sizeof(u8)); + u8 *yPos = AllocZeroed((botX - topX) * (botY - topY) * sizeof(u8)); + u32 iter = 0; + bool32 ret = FALSE; + + // loop through every tile in area and evaluate + while (topY < botY) + { + while (topX < botX) + { + tileBehaviour = MapGridGetMetatileBehaviorAt(topX, topY); + //Check for objects + nextIter = FALSE; + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE)) + tileBuffer = SNEAKING_PROXIMITY + 3; + else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH)) + tileBuffer = SNEAKING_PROXIMITY + 1; + + if (GetPlayerDistance(topX, topY) <= tileBuffer) + { + // tile too close to player + topX++; + continue; + } + + for (i = 0; i < OBJECT_EVENTS_COUNT; i++) + { + if (gObjectEvents[i].currentCoords.x == topX && gObjectEvents[i].currentCoords.y == topY) + { + // cannot be on a tile where an object exists + nextIter = TRUE; + break; + } + } + + if (nextIter) + { + topX++; + continue; + } + + weight = 0; // initiliaze weight + switch (environment) + { + case ENCOUNTER_TYPE_LAND: + if (MetatileBehavior_IsLandWildEncounter(tileBehaviour)) + { + if (currMapType == MAP_TYPE_UNDERGROUND) + { + // inside (cave) + if (IsElevationMismatchAt(gObjectEvents[gPlayerAvatar.spriteId].currentElevation, topX, topY)) + break; //occurs at same z coord + + scale = 440 - (smallScan * 200) - (GetPlayerDistance(topX, topY) / 2) - (2 * (topX + topY)); + weight = ((Random() % scale) < 1) && !MapGridGetCollisionAt(topX, topY); + } + else + { + // outdoors: grass + scale = 100 - (GetPlayerDistance(topX, topY) * 2); + weight = (Random() % scale <= 5) && !MapGridGetCollisionAt(topX, topY); + } + } + break; + case ENCOUNTER_TYPE_WATER: + if (MetatileBehavior_IsSurfableWaterOrUnderwater(tileBehaviour)) + { + u8 scale = 320 - (smallScan * 200) - (GetPlayerDistance(topX, topY) / 2); + if (IsElevationMismatchAt(gObjectEvents[gPlayerAvatar.spriteId].currentElevation, topX, topY)) + break; + + weight = (Random() % scale <= 1) && !MapGridGetCollisionAt(topX, topY); + } + break; + default: + break; + } + + if (weight > 0) + { + xPos[iter] = topX; + yPos[iter] = topY; + iter++; + } + + topX++; + } + + topY++; + topX = gSaveBlock1Ptr->pos.x - SCANSTART_X + (smallScan * 5); + } + + if (iter > 0) + { + i = Random() % iter; + sDexNavSearchDataPtr->tileX = xPos[i]; + sDexNavSearchDataPtr->tileY = yPos[i]; + ret = TRUE; + } + + Free(xPos); + Free(yPos); + + return ret; +} + + +static bool8 TryStartHiddenMonFieldEffect(u8 environment, u8 xSize, u8 ySize, bool8 smallScan) +{ + u8 currMapType = GetCurrentMapType(); + u8 fldEffId = 0; + + if (DexNavPickTile(environment, xSize, ySize, smallScan)) + { + u8 metatileBehaviour = MapGridGetMetatileBehaviorAt(sDexNavSearchDataPtr->tileX, sDexNavSearchDataPtr->tileY); + + switch (environment) + { + case ENCOUNTER_TYPE_LAND: + if (currMapType == MAP_TYPE_UNDERGROUND) + { + fldEffId = FLDEFF_CAVE_DUST; + } + else if (IsMapTypeIndoors(currMapType)) + { + if (MetatileBehavior_IsTallGrass(metatileBehaviour)) //Grass in cave + fldEffId = FLDEFF_SHAKING_GRASS; + else if (MetatileBehavior_IsLongGrass(metatileBehaviour)) //Really tall grass + fldEffId = FLDEFF_SHAKING_LONG_GRASS; + else if (MetatileBehavior_IsSandOrDeepSand(metatileBehaviour)) + fldEffId = FLDEFF_SAND_HOLE; + else + fldEffId = FLDEFF_CAVE_DUST; + } + else //outdoor, underwater + { + if (MetatileBehavior_IsTallGrass(metatileBehaviour)) //Regular grass + fldEffId = FLDEFF_SHAKING_GRASS; + else if (MetatileBehavior_IsLongGrass(metatileBehaviour)) //Really tall grass + fldEffId = FLDEFF_SHAKING_LONG_GRASS; + else if (MetatileBehavior_IsSandOrDeepSand(metatileBehaviour)) //Desert Sand + fldEffId = FLDEFF_SAND_HOLE; + else if (MetatileBehavior_IsMountain(metatileBehaviour)) //Rough Terrain + fldEffId = FLDEFF_CAVE_DUST; + else + fldEffId = FLDEFF_BERRY_TREE_GROWTH_SPARKLE; //default + } + break; + case ENCOUNTER_TYPE_WATER: + fldEffId = FLDEFF_WATER_SURFACING; + break; + default: + return FALSE; + } + + if (fldEffId != 0) + { + gFieldEffectArguments[0] = sDexNavSearchDataPtr->tileX; + gFieldEffectArguments[1] = sDexNavSearchDataPtr->tileY; + gFieldEffectArguments[2] = 0xFF; // subpriority + gFieldEffectArguments[3] = 2; //priority + sDexNavSearchDataPtr->fldEffSpriteId = FieldEffectStart(fldEffId); + if (sDexNavSearchDataPtr->fldEffSpriteId == MAX_SPRITES) + return FALSE; + + sDexNavSearchDataPtr->fldEffId = fldEffId; + return TRUE; + } + } + + return FALSE; +} + +static void DrawDexNavSearchHeldItem(u8* dst) +{ + *dst = CreateSprite(&sHeldItemTemplate, SPECIES_ICON_X + 6, GetSearchWindowY() + 18, 0); + if (*dst != MAX_SPRITES) + gSprites[*dst].invisible = TRUE; +} + +static void LoadSearchIconData(void) +{ + // palettes clash with mon icon, so must load manually + LoadSpriteSheet(&gSpriteSheet_HeldItem); + LoadPalette(gHeldItemPalette, 0x100 + (16 * sHeldItemOam.paletteNum), 32); + LoadCompressedSpriteSheetUsingHeap(&sPotentialStarSpriteSheet); + //LoadCompressedSpriteSheetUsingHeap(&sSightSpriteSheet); //eye replaced with arrow + LoadCompressedSpriteSheetUsingHeap(&sOwnedIconSpriteSheet); + LoadCompressedSpriteSheetUsingHeap(&sHiddenMonIconSpriteSheet); +} + +static u8 GetSearchLevel(u16 dexNum) +{ + u8 searchLevel; +#if USE_DEXNAV_SEARCH_LEVELS == TRUE + searchLevel = gSaveBlock3Ptr->dexNavSearchLevels[dexNum]; +#else + searchLevel = 0; +#endif + return searchLevel; +} + +#define tProximity data[0] +#define tFrameCount data[1] +#define tSpecies data[2] +#define tEnvironment data[3] +#define tRevealed data[4] + +static void Task_SetUpDexNavSearch(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + + u16 species = sDexNavSearchDataPtr->species; + u8 searchLevel = GetSearchLevel(SpeciesToNationalPokedexNum(species)); + + // init sprites + sDexNavSearchDataPtr->iconSpriteId = MAX_SPRITES; + sDexNavSearchDataPtr->itemSpriteId = MAX_SPRITES; + sDexNavSearchDataPtr->eyeSpriteId = MAX_SPRITES; + sDexNavSearchDataPtr->starSpriteIds[0] = MAX_SPRITES; + sDexNavSearchDataPtr->starSpriteIds[1] = MAX_SPRITES; + sDexNavSearchDataPtr->starSpriteIds[2] = MAX_SPRITES; + sDexNavSearchDataPtr->ownedIconSpriteId = MAX_SPRITES; + sDexNavSearchDataPtr->exclamationSpriteId = MAX_SPRITES; + sDexNavSearchDataPtr->searchLevel = searchLevel; + + DexNavGenerateMoveset(species, searchLevel, sDexNavSearchDataPtr->monLevel, &sDexNavSearchDataPtr->moves[0]); + sDexNavSearchDataPtr->heldItem = DexNavGenerateHeldItem(species, searchLevel); + sDexNavSearchDataPtr->abilityNum = DexNavGetAbilityNum(species, searchLevel); + sDexNavSearchDataPtr->potential = DexNavGeneratePotential(searchLevel); + DexNavProximityUpdate(); + + LoadSearchIconData(); + if (sDexNavSearchDataPtr->hiddenSearch) + { + DexNavDrawHiddenIcons(); + } + else + { + DexNavDrawIcons(); + DexNavUpdateSearchWindow(sDexNavSearchDataPtr->proximity, searchLevel); + } + + FlagSet(FLAG_SYS_DEXNAV_SEARCH); + gPlayerAvatar.creeping = TRUE; //initialize as true in case mon appears beside you + task->tProximity = gSprites[gPlayerAvatar.spriteId].x; + task->tFrameCount = 0; + task->func = Task_DexNavSearch; + IncrementGameStat(GAME_STAT_DEXNAV_SCANNED); +} + +static void DexNavSearchBail(u8 taskId, const u8 *script) +{ + TRY_FREE_AND_SET_NULL(sDexNavSearchDataPtr); + FreeMonIconPalettes(); + ScriptContext_SetupScript(script); + DestroyTask(taskId); +} + +static void Task_InitDexNavSearch(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + u16 species = task->tSpecies; + u8 environment = task->tEnvironment; + + sDexNavSearchDataPtr = AllocZeroed(sizeof(struct DexNavSearch)); + if (sDexNavSearchDataPtr == NULL) + { + DexNavSearchBail(taskId, EventScript_NotFoundNearby); + return; + } + + // assign non-objects to struct + sDexNavSearchDataPtr->species = species; + sDexNavSearchDataPtr->environment = environment; //updated in DexNavTryGenerateMonLevel if hidden mon + sDexNavSearchDataPtr->isHiddenMon = (environment == ENCOUNTER_TYPE_HIDDEN) ? TRUE : FALSE; + sDexNavSearchDataPtr->monLevel = DexNavTryGenerateMonLevel(species, environment); + + if (GetFlashLevel() > 0) + { + DexNavSearchBail(taskId, EventScript_TooDark); + return; + } + + if (sDexNavSearchDataPtr->monLevel == MON_LEVEL_NONEXISTENT || !TryStartHiddenMonFieldEffect(sDexNavSearchDataPtr->environment, 12, 12, FALSE)) + { + DexNavSearchBail(taskId, EventScript_NotFoundNearby); + return; + } + + sDexNavSearchDataPtr->hiddenSearch = FALSE; + task->tRevealed = TRUE; //search window revealed + task->func = Task_SetUpDexNavSearch; +} + +static void DexNavDrawPotentialStars(u8 potential, u8* dst) +{ + u8 spriteId; + u32 i; + + for (i = 0; i < NELEMS(sDexNavSearchDataPtr->starSpriteIds); i++) + { + spriteId = MAX_SPRITES; + if (potential > i) + spriteId = CreateSprite(&sPotentialStarTemplate, SPECIES_ICON_X - 20, GetSearchWindowY() + 4 + (i * 8), 0); + + dst[i] = spriteId; + if (spriteId != MAX_SPRITES) + gSprites[spriteId].invisible = TRUE; + } +} + +static void DexNavUpdateDirectionArrow(void) +{ + u16 tileX = sDexNavSearchDataPtr->tileX; + u16 tileY = sDexNavSearchDataPtr->tileY; + u16 playerX = gSaveBlock1Ptr->pos.x + 7; + u16 playerY = gSaveBlock1Ptr->pos.y + 7; + u16 deltaX = abs(tileX - playerX); + u16 deltaY = abs(tileY - playerY); + const u8 *str; + u8 windowId = sDexNavSearchDataPtr->windowId; + + FillWindowPixelRect(windowId, PIXEL_FILL(1), SEARCH_ARROW_X, SEARCH_ARROW_Y, 12, 12); + if (deltaX <= 1 && deltaY <= 1) + { + str = gText_EmptyString2; + } + else if (deltaX > deltaY) + { + if (playerX > tileX) + str = sText_ArrowLeft; //player to right + else + str = sText_ArrowRight; //player to left + } + else //greater Y diff + { + if (playerY > tileY) + str = sText_ArrowUp; //player below + else + str = sText_ArrowDown; //player above + } + + AddTextPrinterParameterized3(windowId, 1, SEARCH_ARROW_X, SEARCH_ARROW_Y, sSearchFontColor, TEXT_SKIP_DRAW, str); + CopyWindowToVram(windowId, 2); +} + +static void DexNavDrawIcons(void) +{ + u16 species = sDexNavSearchDataPtr->species; + + DrawSearchWindow(species, sDexNavSearchDataPtr->potential, FALSE); + DrawDexNavSearchMonIcon(species, &sDexNavSearchDataPtr->iconSpriteId, GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)); + DrawDexNavSearchHeldItem(&sDexNavSearchDataPtr->itemSpriteId); + DexNavDrawPotentialStars(sDexNavSearchDataPtr->potential, &sDexNavSearchDataPtr->starSpriteIds[0]); + DexNavUpdateDirectionArrow(); +} + +///////////////////// +//// SEARCH TASK //// +///////////////////// +bool8 TryStartDexNavSearch(void) +{ + u8 taskId; + u16 val = VarGet(VAR_DEXNAV_SPECIES); + + if (FlagGet(FLAG_SYS_DEXNAV_SEARCH) || (val & DEXNAV_MASK_SPECIES) == SPECIES_NONE) + return FALSE; + + HideMapNamePopUpWindow(); + ChangeBgY_ScreenOff(0, 0, 0); + taskId = CreateTask(Task_InitDexNavSearch, 0); + gTasks[taskId].tSpecies = val & DEXNAV_MASK_SPECIES; + gTasks[taskId].tEnvironment = val >> 14; + PlaySE(SE_DEX_SEARCH); + return FALSE; //we dont actually want to enable the script context +} + +void EndDexNavSearch(u8 taskId) +{ + FlagClear(FLAG_SYS_DEXNAV_SEARCH); + DestroyTask(taskId); + RemoveDexNavWindowAndGfx(); + FieldEffectStop(&gSprites[sDexNavSearchDataPtr->fldEffSpriteId], sDexNavSearchDataPtr->fldEffId); + Free(sDexNavSearchDataPtr); +} + +static void EndDexNavSearchSetupScript(const u8 *script, u8 taskId) +{ + gSaveBlock3Ptr->dexNavChain = 0; //reset chain + EndDexNavSearch(taskId); + ScriptContext_SetupScript(script); +} + +static u8 GetMovementProximityBySearchLevel(void) +{ + if (sDexNavSearchDataPtr->searchLevel < 20) + return 2; + else if (sDexNavSearchDataPtr->searchLevel < 50) + return 3; + else + return 4; +} + +static void Task_RevealHiddenMon(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + u16 species = sDexNavSearchDataPtr->species; + + // remove owned icon if it exists + if (sDexNavSearchDataPtr->ownedIconSpriteId != MAX_SPRITES) + { + DestroySprite(&gSprites[sDexNavSearchDataPtr->ownedIconSpriteId]); + sDexNavSearchDataPtr->ownedIconSpriteId = MAX_SPRITES; + } + + // remove exclamation if it exists + if (sDexNavSearchDataPtr->exclamationSpriteId != MAX_SPRITES) + { + DestroySprite(&gSprites[sDexNavSearchDataPtr->exclamationSpriteId]); + sDexNavSearchDataPtr->exclamationSpriteId = MAX_SPRITES; + } + + + if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_SEEN)) + { + u8 index; + + //if not seen, hide name and whiteout mon + DrawSearchWindow(species, sDexNavSearchDataPtr->potential, TRUE); + DrawDexNavSearchMonIcon(species, &sDexNavSearchDataPtr->iconSpriteId, FALSE); + // whiteout icon + index = IndexOfSpritePaletteTag(gSprites[sDexNavSearchDataPtr->iconSpriteId].template->paletteTag); + CpuCopy16(&gPlttBufferUnfaded[0x100 + index * 16], sDexNavSearchDataPtr->palBuffer, 32); + TintPalette_CustomTone(sDexNavSearchDataPtr->palBuffer, 16, 510, 510, 510); + LoadPalette(sDexNavSearchDataPtr->palBuffer, 0x100 + index * 16, 32); + } + else + { + DrawSearchWindow(species, sDexNavSearchDataPtr->potential, FALSE); + DrawDexNavSearchMonIcon(species, &sDexNavSearchDataPtr->iconSpriteId, GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)); + } + + DexNavUpdateDirectionArrow(); + task->func = Task_DexNavSearch; + task->tFrameCount = 0; //restart search clock +} + +static void Task_DexNavSearch(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + + if (sDexNavSearchDataPtr->proximity > MAX_PROXIMITY) + { // out of range + if (sDexNavSearchDataPtr->hiddenSearch && !task->tRevealed) + EndDexNavSearch(taskId); + else + EndDexNavSearchSetupScript(EventScript_LostSignal, taskId); + return; + } + + if (sDexNavSearchDataPtr->proximity <= CREEPING_PROXIMITY && !gPlayerAvatar.creeping && task->tFrameCount > 60) + { //should be creeping but player walks normally + if (sDexNavSearchDataPtr->hiddenSearch && !task->tRevealed) + EndDexNavSearch(taskId); + else + EndDexNavSearchSetupScript(EventScript_MovedTooFast, taskId); + return; + } + + if (sDexNavSearchDataPtr->proximity <= SNEAKING_PROXIMITY && TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_DASH | PLAYER_AVATAR_FLAG_BIKE)) + { // running/biking too close + //always do event script, even if player hasn't revealed a hidden mon. It's assumed they would be creeping towards it + EndDexNavSearchSetupScript(EventScript_MovedTooFast, taskId); + return; + } + + if (ArePlayerFieldControlsLocked() == TRUE) + { // check if script just executed + EndDexNavSearch(taskId); + return; + } + + if (gTasks[taskId].tFrameCount > DEXNAV_TIMEOUT * 60) + { // player took too long + if (sDexNavSearchDataPtr->hiddenSearch && !task->tRevealed) + EndDexNavSearch(taskId); + else + EndDexNavSearchSetupScript(EventScript_PokemonGotAway, taskId); + return; + } + + if (sDexNavSearchDataPtr->proximity < 1) + { + gDexNavBattle = TRUE; + CreateDexNavWildMon(sDexNavSearchDataPtr->species, sDexNavSearchDataPtr->potential, sDexNavSearchDataPtr->monLevel, + sDexNavSearchDataPtr->abilityNum, sDexNavSearchDataPtr->heldItem, sDexNavSearchDataPtr->moves); + + FlagClear(FLAG_SYS_DEXNAV_SEARCH); + ScriptContext_SetupScript(EventScript_StartDexNavBattle); + Free(sDexNavSearchDataPtr); + DestroyTask(taskId); + return; + } + + if (sDexNavSearchDataPtr->hiddenSearch && !task->tRevealed && + (JOY_NEW(R_BUTTON) || (sDexNavSearchDataPtr->proximity < CREEPING_PROXIMITY))) + { + PlaySE(SE_DEX_SEARCH); + ClearStdWindowAndFrameToTransparent(sDexNavSearchDataPtr->windowId, FALSE); + CopyWindowToVram(sDexNavSearchDataPtr->windowId, 3); + RemoveWindow(sDexNavSearchDataPtr->windowId); + DestroySprite(&gSprites[sDexNavSearchDataPtr->iconSpriteId]); + task->tRevealed = TRUE; //regular dexnav search + //sDexNavSearchDataPtr->hiddenSearch = FALSE; //now its a regular dexnav search + task->func = Task_RevealHiddenMon; + return; + } + + //Caves and water the pokemon moves around + if ((sDexNavSearchDataPtr->environment == ENCOUNTER_TYPE_WATER || GetCurrentMapType() == MAP_TYPE_UNDERGROUND) + && sDexNavSearchDataPtr->proximity < GetMovementProximityBySearchLevel() && sDexNavSearchDataPtr->movementCount < 2 + && task->tRevealed) + { + FieldEffectStop(&gSprites[sDexNavSearchDataPtr->fldEffSpriteId], sDexNavSearchDataPtr->fldEffId); + + if (!TryStartHiddenMonFieldEffect(sDexNavSearchDataPtr->environment, 10, 10, TRUE)) + { + EndDexNavSearchSetupScript(EventScript_PokemonGotAway, taskId); + return; + } + + sDexNavSearchDataPtr->movementCount++; + } + + DexNavProximityUpdate(); + if (task->tProximity != sDexNavSearchDataPtr->proximity) + { + //player has moved + if (task->tRevealed) //update search window info only if hidden mon has been revealed (always true for search mode) + DexNavUpdateSearchWindow(sDexNavSearchDataPtr->proximity, sDexNavSearchDataPtr->searchLevel); + + task->tProximity = sDexNavSearchDataPtr->proximity; + } + + task->tFrameCount++; +} + +static void DexNavUpdateSearchWindow(u8 proximity, u8 searchLevel) +{ + bool8 hideName = FALSE; + + if (sDexNavSearchDataPtr->hiddenSearch && !GetSetPokedexFlag(SpeciesToNationalPokedexNum(sDexNavSearchDataPtr->species), FLAG_GET_SEEN)) + hideName = TRUE; //if a detector mode hidden search and player hasn't seen the mon, hide info + + FillWindowPixelBuffer(sDexNavSearchDataPtr->windowId, PIXEL_FILL(1)); //clear window + AddSearchWindowText(sDexNavSearchDataPtr->species, proximity, searchLevel, hideName); + + DexNavUpdateDirectionArrow(); + + //init hidden sprites + if (sDexNavSearchDataPtr->itemSpriteId != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->itemSpriteId].invisible = TRUE; + if (sDexNavSearchDataPtr->starSpriteIds[0] != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->starSpriteIds[0]].invisible = TRUE; + if (sDexNavSearchDataPtr->starSpriteIds[1] != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->starSpriteIds[1]].invisible = TRUE; + if (sDexNavSearchDataPtr->starSpriteIds[2] != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->starSpriteIds[2]].invisible = TRUE; + + if (proximity <= SNEAKING_PROXIMITY) + { + if (searchLevel > 2 && sDexNavSearchDataPtr->heldItem) + { + // toggle item view + if (sDexNavSearchDataPtr->itemSpriteId != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->itemSpriteId].invisible = FALSE; + } + + if (searchLevel > 4) + { + if (sDexNavSearchDataPtr->starSpriteIds[0] != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->starSpriteIds[0]].invisible = FALSE; + + if (sDexNavSearchDataPtr->starSpriteIds[1] != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->starSpriteIds[1]].invisible = FALSE; + + if (sDexNavSearchDataPtr->starSpriteIds[2] != MAX_SPRITES) + gSprites[sDexNavSearchDataPtr->starSpriteIds[2]].invisible = FALSE; + } + } +} + +////////////////////////////// +//// DEXNAV MON GENERATOR //// +////////////////////////////// +static void CreateDexNavWildMon(u16 species, u8 potential, u8 level, u8 abilityNum, u16 item, u16* moves) +{ + struct Pokemon* mon = &gEnemyParty[0]; + u8 iv[3] = {NUM_STATS}; + u8 i; + u8 perfectIv = 31; + + CreateWildMon(species, level); // shiny rate bonus handled in CreateBoxMon + + // Pick random, unique IVs to set to 31. The number of perfect IVs that are assigned is equal to the potential + iv[0] = Random() % NUM_STATS; // choose 1st perfect stat + do { + iv[1] = Random() % NUM_STATS; + iv[2] = Random() % NUM_STATS; + } while ((iv[1] == iv[0]) // unique 2nd perfect stat + || (iv[2] == iv[0] || iv[2] == iv[1])); // unique 3rd perfect stat + + if (potential > 2 && iv[2] != NUM_STATS) + SetMonData(mon, MON_DATA_HP_IV + iv[2], &perfectIv); + if (potential > 1 && iv[1] != NUM_STATS) + SetMonData(mon, MON_DATA_HP_IV + iv[1], &perfectIv); + if (potential > 0 && iv[0] != NUM_STATS) + SetMonData(mon, MON_DATA_HP_IV + iv[0], &perfectIv); + + //Set ability + SetMonData(mon, MON_DATA_ABILITY_NUM, &abilityNum); + + // Set Held Item + if (item) + SetMonData(mon, MON_DATA_HELD_ITEM, &item); + + //Set moves + for (i = 0; i < MAX_MON_MOVES; i++) + SetMonMoveSlot(mon, moves[i], i); + + CalculateMonStats(mon); +} + +// gets a random level of the species based on map data. +//if it was a hidden encounter, updates the environment it is to be found from the wildheader encounterRate +static u8 DexNavTryGenerateMonLevel(u16 species, u8 environment) +{ + u8 levelBase = GetEncounterLevelFromMapData(species, environment); + u8 levelBonus = gSaveBlock3Ptr->dexNavChain / 5; + + if (levelBase == MON_LEVEL_NONEXISTENT) + return MON_LEVEL_NONEXISTENT; //species not found in the area + + if (Random() % 100 < 4) + levelBonus += 10; //4% chance of having a +10 level + + if (levelBase + levelBonus > MAX_LEVEL) + return MAX_LEVEL; + else + return levelBase + levelBonus; +} + +static void DexNavGenerateMoveset(u16 species, u8 searchLevel, u8 encounterLevel, u16* moveDst) +{ + bool8 genMove = FALSE; + u16 randVal = Random() % 100; + u16 i; + u16 eggMoveBuffer[EGG_MOVES_ARRAY_COUNT]; + + // see if first move slot should be an egg move + if (searchLevel < 5) + { + if (SEARCHLEVEL0_MOVECHANCE != 0 && randVal < SEARCHLEVEL0_MOVECHANCE) + genMove = TRUE; + } + else if (searchLevel < 10) + { + if (SEARCHLEVEL5_MOVECHANCE != 0 && randVal < SEARCHLEVEL5_MOVECHANCE) + genMove = TRUE; + } + else if (searchLevel < 25) + { + if (SEARCHLEVEL10_MOVECHANCE != 0 && randVal < SEARCHLEVEL10_MOVECHANCE) + genMove = TRUE; + } + else if (searchLevel < 50) + { + if (SEARCHLEVEL25_MOVECHANCE != 0 && randVal < SEARCHLEVEL25_MOVECHANCE) + genMove = TRUE; + } + else if (searchLevel < 100) + { + if (SEARCHLEVEL50_MOVECHANCE != 0 && randVal < SEARCHLEVEL50_MOVECHANCE) + genMove = TRUE; + } + else + { + if (SEARCHLEVEL100_MOVECHANCE != 0 && randVal < SEARCHLEVEL100_MOVECHANCE) + genMove = TRUE; + } + + // Generate a wild mon just to get the initial moveset (later overwritten by CreateDexNavWildMon) + CreateWildMon(species, encounterLevel); + + // Store generated mon moves into Dex Nav Struct + for (i = 0; i < MAX_MON_MOVES; i++) + moveDst[i] = GetMonData(&gEnemyParty[0], MON_DATA_MOVE1 + i, NULL); + + // set first move slot to a random egg move if search level is good enough + if (genMove) + { + u8 numEggMoves = GetEggMoves(&gEnemyParty[0], eggMoveBuffer); + if (numEggMoves != 0) + moveDst[0] = eggMoveBuffer[Random() % numEggMoves]; + } +} + +static u16 DexNavGenerateHeldItem(u16 species, u8 searchLevel) +{ + u16 randVal = Random() % 100; + u8 searchLevelInfluence = searchLevel >> 1; + u16 item1 = gSpeciesInfo[species].itemCommon; + u16 item2 = gSpeciesInfo[species].itemRare; + + // if both are the same, 100% to hold + if (item1 == item2) + return item1; + + // if no items can be held, then yeah...no items + if (item2 == ITEM_NONE && item1 == ITEM_NONE) + return ITEM_NONE; + + // if only one entry, 50% chance + if (item2 == ITEM_NONE && item1 != ITEM_NONE) + return (randVal < 50) ? item1 : ITEM_NONE; + + // if both are distinct item1 = 50% + srclvl/2; item2 = 5% + srchlvl/2 + if (randVal < (50 + searchLevelInfluence + 5 + searchLevel)) + return (randVal > 5 + searchLevelInfluence) ? item1 : item2; + else + return ITEM_NONE; + + return ITEM_NONE; +} + +static u8 DexNavGetAbilityNum(u16 species, u8 searchLevel) +{ + bool8 genAbility = FALSE; + u16 randVal = Random() % 100; + u8 abilityNum = 0; + + if (searchLevel < 5) + { + #if (SEARCHLEVEL0_ABILITYCHANCE != 0) + if (randVal < SEARCHLEVEL0_ABILITYCHANCE) + genAbility = TRUE; + #endif + } + else if (searchLevel < 10) + { + #if (SEARCHLEVEL5_ABILITYCHANCE != 0) + if (randVal < SEARCHLEVEL5_ABILITYCHANCE) + genAbility = TRUE; + #endif + } + else if (searchLevel < 25) + { + #if (SEARCHLEVEL10_ABILITYCHANCE != 0) + if (randVal < SEARCHLEVEL10_ABILITYCHANCE) + genAbility = TRUE; + #endif + } + else if (searchLevel < 50) + { + #if (SEARCHLEVEL25_ABILITYCHANCE != 0) + if (randVal < SEARCHLEVEL25_ABILITYCHANCE) + genAbility = TRUE; + #endif + } + else if (searchLevel < 100) + { + #if (SEARCHLEVEL50_ABILITYCHANCE != 0) + if (randVal < SEARCHLEVEL50_ABILITYCHANCE) + genAbility = TRUE; + #endif + } + else + { + #if (SEARCHLEVEL100_ABILITYCHANCE != 0) + if (randVal < SEARCHLEVEL100_ABILITYCHANCE) + genAbility = TRUE; + #endif + } + + if (genAbility + && gSpeciesInfo[species].abilities[2] != ABILITY_NONE + && GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + { + //Only give hidden ability if Pokemon has been caught before + abilityNum = 2; + } + else + { + //Pick a normal ability of that Pokemon + if (gSpeciesInfo[species].abilities[1] != ABILITY_NONE) + abilityNum = Random() & 1; + else + abilityNum = 0; + } + + return abilityNum; +} + +static u8 DexNavGeneratePotential(u8 searchLevel) +{ + u8 genChance = 0; + int randVal = Random() % 100; + + if (searchLevel < 5) + { + genChance = SEARCHLEVEL0_ONESTAR + SEARCHLEVEL0_TWOSTAR + SEARCHLEVEL0_THREESTAR; + if (randVal < genChance) + { + // figure out which star it is + if (randVal < SEARCHLEVEL0_ONESTAR) + return 1; + else if (randVal < (SEARCHLEVEL0_ONESTAR + SEARCHLEVEL0_TWOSTAR)) + return 2; + else + return 3; + } + } + else if (searchLevel < 10) + { + genChance = SEARCHLEVEL5_ONESTAR + SEARCHLEVEL5_TWOSTAR + SEARCHLEVEL5_THREESTAR; + if (randVal < genChance) + { + // figure out which star it is + if (randVal < SEARCHLEVEL5_ONESTAR) + return 1; + else if (randVal < (SEARCHLEVEL5_ONESTAR + SEARCHLEVEL5_TWOSTAR)) + return 2; + else + return 3; + } + } + else if (searchLevel < 25) + { + genChance = SEARCHLEVEL10_ONESTAR + SEARCHLEVEL10_TWOSTAR + SEARCHLEVEL10_THREESTAR; + if (randVal < genChance) + { + // figure out which star it is + if (randVal < SEARCHLEVEL10_ONESTAR) + return 1; + else if (randVal < (SEARCHLEVEL10_ONESTAR + SEARCHLEVEL10_TWOSTAR)) + return 2; + else + return 3; + } + } + else if (searchLevel < 50) + { + genChance = SEARCHLEVEL25_ONESTAR + SEARCHLEVEL25_TWOSTAR + SEARCHLEVEL25_THREESTAR; + if (randVal < genChance) + { + // figure out which star it is + if (randVal < SEARCHLEVEL25_ONESTAR) + return 1; + else if (randVal < (SEARCHLEVEL25_ONESTAR + SEARCHLEVEL25_TWOSTAR)) + return 2; + else + return 3; + } + } + else if (searchLevel < 100) + { + genChance = SEARCHLEVEL50_ONESTAR + SEARCHLEVEL50_TWOSTAR + SEARCHLEVEL50_THREESTAR; + if (randVal < genChance) + { + // figure out which star it is + if (randVal < SEARCHLEVEL50_ONESTAR) + return 1; + else if (randVal < (SEARCHLEVEL50_ONESTAR + SEARCHLEVEL50_TWOSTAR)) + return 2; + else + return 3; + } + } + else + { + genChance = SEARCHLEVEL100_ONESTAR + SEARCHLEVEL100_TWOSTAR + SEARCHLEVEL100_THREESTAR; + if (randVal < genChance) + { + // figure out which star it is + if (randVal < SEARCHLEVEL100_ONESTAR) + return 1; + else if (randVal < (SEARCHLEVEL100_ONESTAR + SEARCHLEVEL100_TWOSTAR)) + return 2; + else + return 3; + } + } + + return 0; // No potential +} + +static u8 GetEncounterLevelFromMapData(u16 species, u8 environment) +{ + u16 headerId = GetCurrentMapWildMonHeaderId(); + const struct WildPokemonInfo *landMonsInfo = gWildMonHeaders[headerId].landMonsInfo; + const struct WildPokemonInfo *waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo; + const struct WildPokemonInfo *hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo; + u8 min = 100; + u8 max = 0; + u8 i; + + switch (environment) + { + case ENCOUNTER_TYPE_LAND: // grass + if (landMonsInfo == NULL) + return MON_LEVEL_NONEXISTENT; //Hidden pokemon should only appear on walkable tiles or surf tiles + + for (i = 0; i < LAND_WILD_COUNT; i++) + { + if (landMonsInfo->wildPokemon[i].species == species) + { + min = (min < landMonsInfo->wildPokemon[i].minLevel) ? min : landMonsInfo->wildPokemon[i].minLevel; + max = (max > landMonsInfo->wildPokemon[i].maxLevel) ? max : landMonsInfo->wildPokemon[i].maxLevel; + } + } + break; + case ENCOUNTER_TYPE_WATER: //water + if (waterMonsInfo == NULL) + return MON_LEVEL_NONEXISTENT; //Hidden pokemon should only appear on walkable tiles or surf tiles + + for (i = 0; i < WATER_WILD_COUNT; i++) + { + if (waterMonsInfo->wildPokemon[i].species == species) + { + min = (min < waterMonsInfo->wildPokemon[i].minLevel) ? min : waterMonsInfo->wildPokemon[i].minLevel; + max = (max > waterMonsInfo->wildPokemon[i].maxLevel) ? max : waterMonsInfo->wildPokemon[i].maxLevel; + } + } + break; + case ENCOUNTER_TYPE_HIDDEN: + if (hiddenMonsInfo == NULL) + return MON_LEVEL_NONEXISTENT; + + for (i = 0; i < HIDDEN_WILD_COUNT; i++) + { + if (hiddenMonsInfo->wildPokemon[i].species == species) + { + min = (min < hiddenMonsInfo->wildPokemon[i].minLevel) ? min : hiddenMonsInfo->wildPokemon[i].minLevel; + max = (max > hiddenMonsInfo->wildPokemon[i].maxLevel) ? max : hiddenMonsInfo->wildPokemon[i].maxLevel; + } + } + + // use encounter rate to signify is hidden pokemon are on land or in water + if (hiddenMonsInfo->encounterRate == 1) + sDexNavSearchDataPtr->environment = ENCOUNTER_TYPE_WATER; + else + sDexNavSearchDataPtr->environment = ENCOUNTER_TYPE_LAND; + break; + default: + return MON_LEVEL_NONEXISTENT; + } + + if (max == 0) + return MON_LEVEL_NONEXISTENT; + + return RandomUniform(RNG_DEXNAV_ENCOUNTER_LEVEL, min, max); +} + + +/////////// +/// GUI /// +/////////// +static const struct BgTemplate sDexNavMenuBgTemplates[2] = +{ + { + .bg = 0, + .charBaseIndex = 0, + .mapBaseIndex = 31, + .priority = 0 + }, + { + .bg = 1, + .charBaseIndex = 3, + .mapBaseIndex = 30, + .priority = 1 + } +}; + +static void DexNav_VBlankCB(void) +{ + LoadOam(); + ProcessSpriteCopyRequests(); + TransferPlttBuffer(); +} + +static void DexNav_MainCB(void) +{ + RunTasks(); + AnimateSprites(); + BuildOamBuffer(); + DoScheduledBgTilemapCopiesToVram(); + UpdatePaletteFade(); +} + +static bool8 DexNav_InitBgs(void) +{ + ResetVramOamAndBgCntRegs(); + ResetAllBgsCoordinates(); + sBg1TilemapBuffer = Alloc(0x800); + if (sBg1TilemapBuffer == NULL) + return FALSE; + + memset(sBg1TilemapBuffer, 0, 0x800); + ResetBgsAndClearDma3BusyFlags(0); + InitBgsFromTemplates(0, sDexNavMenuBgTemplates, NELEMS(sDexNavMenuBgTemplates)); + SetBgTilemapBuffer(1, sBg1TilemapBuffer); + ScheduleBgCopyTilemapToVram(1); + SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_1D_MAP | DISPCNT_OBJ_ON); + SetGpuReg(REG_OFFSET_BLDCNT , 0); + ShowBg(0); + ShowBg(1); + return TRUE; +} + +static bool8 DexNav_LoadGraphics(void) +{ + switch (sDexNavUiDataPtr->state) + { + case 0: + ResetTempTileDataBuffers(); + DecompressAndCopyTileDataToVram(1, sDexNavGuiTiles, 0, 0, 0); + sDexNavUiDataPtr->state++; + break; + case 1: + if (FreeTempTileDataBuffersIfPossible() != TRUE) + { + LZDecompressWram(sDexNavGuiTilemap, sBg1TilemapBuffer); + sDexNavUiDataPtr->state++; + } + break; + case 2: + LoadPalette(sDexNavGuiPal, 0, 32); + sDexNavUiDataPtr->state++; + break; + default: + sDexNavUiDataPtr->state = 0; + return TRUE; + } + + return FALSE; +} + +static void UpdateCursorPosition(void) +{ + u16 x, y; + + switch (sDexNavUiDataPtr->cursorRow) + { + case ROW_WATER: + x = ROW_WATER_ICON_X + (24 * sDexNavUiDataPtr->cursorCol); + y = ROW_WATER_ICON_Y; + sDexNavUiDataPtr->environment = ENCOUNTER_TYPE_WATER; + break; + case ROW_LAND_TOP: //land 1 + x = ROW_LAND_ICON_X + (24 * sDexNavUiDataPtr->cursorCol); + y = ROW_LAND_TOP_ICON_Y; + sDexNavUiDataPtr->environment = ENCOUNTER_TYPE_LAND; + break; + case ROW_LAND_BOT: //land 2 + x = ROW_LAND_ICON_X + (24 * sDexNavUiDataPtr->cursorCol); + y = ROW_LAND_BOT_ICON_Y; + sDexNavUiDataPtr->environment = ENCOUNTER_TYPE_LAND; + break; + case ROW_HIDDEN: + x = ROW_HIDDEN_ICON_X + (24 * sDexNavUiDataPtr->cursorCol); + y = ROW_HIDDEN_ICON_Y; + sDexNavUiDataPtr->environment = ENCOUNTER_TYPE_HIDDEN; + break; + default: + return; + } + + gSprites[sDexNavUiDataPtr->cursorSpriteId].x = x; + gSprites[sDexNavUiDataPtr->cursorSpriteId].y = y; + + PrintCurrentSpeciesInfo(); +} + +static void CreateSelectionCursor(void) +{ + u8 spriteId; + struct CompressedSpriteSheet spriteSheet; + + spriteSheet.data = sSelectionCursorGfx; + spriteSheet.size = 0x200; + spriteSheet.tag = SELECTION_CURSOR_TAG; + LoadCompressedSpriteSheet(&spriteSheet); + + LoadPalette(sSelectionCursorPal, (16 * sSelectionCursorOam.paletteNum) + 0x100, 32); + + spriteId = CreateSprite(&sSelectionCursorSpriteTemplate, 12, 32, 0); + //gSprites[spriteId].data[1] = -1; + + sDexNavUiDataPtr->cursorSpriteId = spriteId; + UpdateCursorPosition(); +} + +static void CreateNoDataIcon(s16 x, s16 y) +{ + CreateSprite(&sNoDataIconTemplate, x, y, 0); +} + +static bool8 CapturedAllLandMons(u16 headerId) +{ + u16 i, species; + int count = 0; + const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].landMonsInfo; + + if (landMonsInfo != NULL) + { + for (i = 0; i < LAND_WILD_COUNT; ++i) + { + species = landMonsInfo->wildPokemon[i].species; + if (species != SPECIES_NONE) + { + if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + break; + + count++; + } + } + + if (i >= LAND_WILD_COUNT && count > 0) //All land mons caught + return TRUE; + } + else + { + return TRUE; //technically, no mon data means you caught them all + } + + return FALSE; +} + +//Checks if all Pokemon that can be encountered while surfing have been capture +static bool8 CapturedAllWaterMons(u16 headerId) +{ + u32 i; + u16 species; + u8 count = 0; + const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo; + + if (waterMonsInfo != NULL) + { + for (i = 0; i < WATER_WILD_COUNT; ++i) + { + species = waterMonsInfo->wildPokemon[i].species; + if (species != SPECIES_NONE) + { + count++; + if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + break; + } + } + + if (i >= WATER_WILD_COUNT && count > 0) + return TRUE; + } + else + { + return TRUE; //technically, no mon data means you caught them all + } + + return FALSE; +} + +static bool8 CapturedAllHiddenMons(u16 headerId) +{ + u32 i; + u16 species; + u8 count = 0; + const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo; + + if (hiddenMonsInfo != NULL) + { + for (i = 0; i < HIDDEN_WILD_COUNT; ++i) + { + species = hiddenMonsInfo->wildPokemon[i].species; + if (species != SPECIES_NONE) + { + count++; + if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + break; + } + } + + if (i >= HIDDEN_WILD_COUNT && count > 0) + return TRUE; + } + else + { + return TRUE; //technically, no mon data means you caught them all + } + + return FALSE; +} + +static void DexNavLoadCapturedAllSymbols(void) +{ + u16 headerId = GetCurrentMapWildMonHeaderId(); + + LoadCompressedSpriteSheetUsingHeap(&sCapturedAllPokemonSpriteSheet); + + if (CapturedAllLandMons(headerId)) + CreateSprite(&sCaptureAllMonsSpriteTemplate, 152, 58, 0); + + if (CapturedAllWaterMons(headerId)) + CreateSprite(&sCaptureAllMonsSpriteTemplate, 139, 17, 0); + + if (CapturedAllHiddenMons(headerId)) + CreateSprite(&sCaptureAllMonsSpriteTemplate, 114, 123, 0); +} + +//#define WIN_DETAILS_TILE 0x3a3 +static void DexNav_InitWindows(void) +{ + InitWindows(sDexNavGuiWindowTemplates); + DeactivateAllTextPrinters(); + ScheduleBgCopyTilemapToVram(0); +} + +static void DexNavGuiFreeResources(void) +{ + Free(sDexNavUiDataPtr); + Free(sBg1TilemapBuffer); + FreeAllWindowBuffers(); +} + +static void CB1_InitDexNavSearch(void) +{ + u8 taskId; + + if (!gPaletteFade.active && !ArePlayerFieldControlsLocked() && gMain.callback2 == CB2_Overworld) + { + SetMainCallback1(CB1_Overworld); + taskId = CreateTask(Task_InitDexNavSearch, 0); + gTasks[taskId].tSpecies = gSpecialVar_0x8000; + gTasks[taskId].tEnvironment = gSpecialVar_0x8001; + } +} + +static void CB1_DexNavSearchCallback(void) +{ + CB1_InitDexNavSearch(); +} + +static void Task_DexNavExitAndSearch(u8 taskId) +{ + DexNavGuiFreeResources(); + DestroyTask(taskId); + SetMainCallback1(CB1_DexNavSearchCallback); + SetMainCallback2(CB2_ReturnToField); +} + +static void Task_DexNavFadeAndExit(u8 taskId) +{ + if (!gPaletteFade.active) + { + SetMainCallback2(sDexNavUiDataPtr->savedCallback); + DexNavGuiFreeResources(); + DestroyTask(taskId); + } +} + +static void DexNavFadeAndExit(void) +{ + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + CreateTask(Task_DexNavFadeAndExit, 0); + SetVBlankCallback(DexNav_VBlankCB); + SetMainCallback2(DexNav_MainCB); +} + +static bool8 SpeciesInArray(u16 species, u8 section) +{ + u32 i; + u16 dexNum = SpeciesToNationalPokedexNum(species); + + switch (section) + { + case 0: //land + for (i = 0; i < LAND_WILD_COUNT; i++) + { + if (SpeciesToNationalPokedexNum(sDexNavUiDataPtr->landSpecies[i]) == dexNum) + return TRUE; + } + break; + case 1: //water + for (i = 0; i < WATER_WILD_COUNT; i++) + { + if (SpeciesToNationalPokedexNum(sDexNavUiDataPtr->waterSpecies[i]) == dexNum) + return TRUE; + } + break; + case 2: //hidden + for (i = 0; i < HIDDEN_WILD_COUNT; i++) + { + if (SpeciesToNationalPokedexNum(sDexNavUiDataPtr->hiddenSpecies[i]) == dexNum) + return TRUE; + } + break; + default: + break; + } + + return FALSE; +} + +// get unique wild encounters on current map +static void DexNavLoadEncounterData(void) +{ + u8 grassIndex = 0; + u8 waterIndex = 0; + u8 hiddenIndex = 0; + u16 species; + u32 i; + u16 headerId = GetCurrentMapWildMonHeaderId(); + const struct WildPokemonInfo* landMonsInfo = gWildMonHeaders[headerId].landMonsInfo; + const struct WildPokemonInfo* waterMonsInfo = gWildMonHeaders[headerId].waterMonsInfo; + const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo; + + // nop struct data + memset(sDexNavUiDataPtr->landSpecies, 0, sizeof(sDexNavUiDataPtr->landSpecies)); + memset(sDexNavUiDataPtr->waterSpecies, 0, sizeof(sDexNavUiDataPtr->waterSpecies)); + memset(sDexNavUiDataPtr->hiddenSpecies, 0, sizeof(sDexNavUiDataPtr->hiddenSpecies)); + + // land mons + if (landMonsInfo != NULL && landMonsInfo->encounterRate != 0) + { + for (i = 0; i < LAND_WILD_COUNT; i++) + { + species = landMonsInfo->wildPokemon[i].species; + if (species != SPECIES_NONE && !SpeciesInArray(species, 0)) + sDexNavUiDataPtr->landSpecies[grassIndex++] = landMonsInfo->wildPokemon[i].species; + } + } + + // water mons + if (waterMonsInfo != NULL && waterMonsInfo->encounterRate != 0) + { + for (i = 0; i < WATER_WILD_COUNT; i++) + { + species = waterMonsInfo->wildPokemon[i].species; + if (species != SPECIES_NONE && !SpeciesInArray(species, 1)) + sDexNavUiDataPtr->waterSpecies[waterIndex++] = waterMonsInfo->wildPokemon[i].species; + } + } + + // hidden mons + if (hiddenMonsInfo != NULL) // no encounter rate check since 0 means land, 1 means water encounters + { + for (i = 0; i < HIDDEN_WILD_COUNT; i++) + { + species = hiddenMonsInfo->wildPokemon[i].species; + if (species != SPECIES_NONE && !SpeciesInArray(species, 2)) + sDexNavUiDataPtr->hiddenSpecies[hiddenIndex++] = hiddenMonsInfo->wildPokemon[i].species; + } + } +} + +static void TryDrawIconInSlot(u16 species, s16 x, s16 y) +{ + if (species == SPECIES_NONE || species > NUM_SPECIES) + CreateNoDataIcon(x, y); //'X' in slot + else if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_SEEN)) + CreateMonIcon(SPECIES_NONE, SpriteCB_MonIcon, x, y, 0, 0xFFFFFFFF); //question mark + else + CreateMonIcon(species, SpriteCB_MonIcon, x, y, 0, 0xFFFFFFFF); +} + +static void DrawSpeciesIcons(void) +{ + s16 x, y; + u32 i; + u16 species; + + LoadCompressedSpriteSheetUsingHeap(&sNoDataIconSpriteSheet); + for (i = 0; i < LAND_WILD_COUNT; i++) + { + species = sDexNavUiDataPtr->landSpecies[i]; + x = 20 + (24 * (i % 6)); + y = ROW_LAND_TOP_ICON_Y + (i > 5 ? 28 : 0); + TryDrawIconInSlot(species, x, y); + } + + for (i = 0; i < WATER_WILD_COUNT; i++) + { + species = sDexNavUiDataPtr->waterSpecies[i]; + x = 30 + 24 * i; + y = ROW_WATER_ICON_Y; + TryDrawIconInSlot(species, x, y); + } + + for (i = 0; i < HIDDEN_WILD_COUNT; i++) + { + species = sDexNavUiDataPtr->hiddenSpecies[i]; + x = ROW_HIDDEN_ICON_X + 24 * i; + y = ROW_HIDDEN_ICON_Y; + if (FlagGet(FLAG_SYS_DETECTOR_MODE)) + TryDrawIconInSlot(species, x, y); + else if (species == SPECIES_NONE || species > NUM_SPECIES) + CreateNoDataIcon(x, y); + else + CreateMonIcon(SPECIES_NONE, SpriteCB_MonIcon, x, y, 0, 0xFFFFFFFF); //question mark if detector mode inactive + } +} + +static u16 DexNavGetSpecies(void) +{ + u16 species; + + switch (sDexNavUiDataPtr->cursorRow) + { + case ROW_WATER: + species = sDexNavUiDataPtr->waterSpecies[sDexNavUiDataPtr->cursorCol]; + break; + case ROW_LAND_TOP: + species = sDexNavUiDataPtr->landSpecies[sDexNavUiDataPtr->cursorCol]; + break; + case ROW_LAND_BOT: + species = sDexNavUiDataPtr->landSpecies[sDexNavUiDataPtr->cursorCol + COL_LAND_COUNT]; + break; + case ROW_HIDDEN: + if (!FlagGet(FLAG_SYS_DETECTOR_MODE)) + species = SPECIES_NONE; + else + species = sDexNavUiDataPtr->hiddenSpecies[sDexNavUiDataPtr->cursorCol]; + break; + default: + return SPECIES_NONE; + } + + if (!GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_SEEN)) + return SPECIES_NONE; + + return species; +} + +static void SetSpriteInvisibility(u8 spriteArrayId, bool8 invisible) +{ + gSprites[sDexNavUiDataPtr->typeIconSpriteIds[spriteArrayId]].invisible = invisible; +} + +// different from pokemon_summary_screen +#define TYPE_ICON_PAL_NUM_0 13 +#define TYPE_ICON_PAL_NUM_1 14 +#define TYPE_ICON_PAL_NUM_2 15 +static const u8 sMoveTypeToOamPaletteNum[NUMBER_OF_MON_TYPES] = +{ + [TYPE_NORMAL] = TYPE_ICON_PAL_NUM_0, + [TYPE_FIGHTING] = TYPE_ICON_PAL_NUM_0, + [TYPE_FLYING] = TYPE_ICON_PAL_NUM_1, + [TYPE_POISON] = TYPE_ICON_PAL_NUM_1, + [TYPE_GROUND] = TYPE_ICON_PAL_NUM_0, + [TYPE_ROCK] = TYPE_ICON_PAL_NUM_0, + [TYPE_BUG] = TYPE_ICON_PAL_NUM_2, + [TYPE_GHOST] = TYPE_ICON_PAL_NUM_1, + [TYPE_STEEL] = TYPE_ICON_PAL_NUM_0, + [TYPE_MYSTERY] = TYPE_ICON_PAL_NUM_2, + [TYPE_FIRE] = TYPE_ICON_PAL_NUM_0, + [TYPE_WATER] = TYPE_ICON_PAL_NUM_1, + [TYPE_GRASS] = TYPE_ICON_PAL_NUM_2, + [TYPE_ELECTRIC] = TYPE_ICON_PAL_NUM_0, + [TYPE_PSYCHIC] = TYPE_ICON_PAL_NUM_1, + [TYPE_ICE] = TYPE_ICON_PAL_NUM_1, + [TYPE_DRAGON] = TYPE_ICON_PAL_NUM_2, + [TYPE_DARK] = TYPE_ICON_PAL_NUM_0, + [TYPE_FAIRY] = TYPE_ICON_PAL_NUM_1, +}; +static void SetTypeIconPosAndPal(u8 typeId, u8 x, u8 y, u8 spriteArrayId) +{ + struct Sprite *sprite; + + sprite = &gSprites[sDexNavUiDataPtr->typeIconSpriteIds[spriteArrayId]]; + StartSpriteAnim(sprite, typeId); + sprite->oam.paletteNum = sMoveTypeToOamPaletteNum[typeId]; + sprite->x = x + 16; + sprite->y = y + 8; + SetSpriteInvisibility(spriteArrayId, FALSE); +} + +static void PrintCurrentSpeciesInfo(void) +{ + u16 species = DexNavGetSpecies(); + u16 dexNum = SpeciesToNationalPokedexNum(species); + u8 type1, type2; + + if (!GetSetPokedexFlag(dexNum, FLAG_GET_SEEN)) + species = SPECIES_NONE; + + // clear windows + FillWindowPixelBuffer(WINDOW_INFO, PIXEL_FILL(TEXT_COLOR_TRANSPARENT)); + + //species name + if (species == SPECIES_NONE) + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, SPECIES_INFO_Y, sFontColor_Black, 0, sText_DexNav_NoInfo); + else + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, SPECIES_INFO_Y, sFontColor_Black, 0, GetSpeciesName(species)); + + //type icon(s) + type1 = gSpeciesInfo[species].types[0]; + type2 = gSpeciesInfo[species].types[1]; + if (species == SPECIES_NONE) + type1 = type2 = TYPE_MYSTERY; + + if (type1 == type2) + { + SetTypeIconPosAndPal(type1, 186, 69, 0); + SetSpriteInvisibility(1, TRUE); + } + else + { + SetTypeIconPosAndPal(type1, 168, 69, 0); + SetTypeIconPosAndPal(type2, 168 + 33, 69, 1); + } + + //search level + if (species == SPECIES_NONE) + { + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, SEARCH_LEVEL_Y, sFontColor_Black, 0, sText_DexNav_NoInfo); + } + else + { + ConvertIntToDecimalStringN(gStringVar4, GetSearchLevel(dexNum), 0, 4); + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, SEARCH_LEVEL_Y, sFontColor_Black, 0, gStringVar4); + } + + //hidden ability + if (species == SPECIES_NONE) + { + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, HA_INFO_Y, sFontColor_Black, 0, sText_DexNav_NoInfo); + } + else if (GetSetPokedexFlag(dexNum, FLAG_GET_CAUGHT)) + { + if (gSpeciesInfo[species].abilities[2] != ABILITY_NONE) + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, HA_INFO_Y, sFontColor_Black, 0, gAbilitiesInfo[gSpeciesInfo[species].abilities[2]].name); + else + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, HA_INFO_Y, sFontColor_Black, 0, gText_None); + } + else + { + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, HA_INFO_Y, sFontColor_Black, 0, sText_DexNav_CaptureToSee); + } + + //current chain + ConvertIntToDecimalStringN(gStringVar1, gSaveBlock3Ptr->dexNavChain, STR_CONV_MODE_LEFT_ALIGN, 3); + AddTextPrinterParameterized3(WINDOW_INFO, 0, 0, CHAIN_BONUS_Y, sFontColor_Black, 0, gStringVar1); + + CopyWindowToVram(WINDOW_INFO, 3); + PutWindowTilemap(WINDOW_INFO); +} + +static void PrintMapName(void) +{ + GetMapName(gStringVar3, GetCurrentRegionMapSectionId(), 0); + AddTextPrinterParameterized3(WINDOW_REGISTERED, 1, 108 + + GetStringRightAlignXOffset(1, gStringVar3, MAP_NAME_LENGTH * GetFontAttribute(1, FONTATTR_MAX_LETTER_WIDTH)), + 0, sFontColor_White, 0, gStringVar3); + CopyWindowToVram(WINDOW_REGISTERED, 3); +} + +static void PrintSearchableSpecies(u16 species) +{ + FillWindowPixelBuffer(WINDOW_REGISTERED, PIXEL_FILL(TEXT_COLOR_TRANSPARENT)); + PutWindowTilemap(WINDOW_REGISTERED); + if (species == SPECIES_NONE) + { + AddTextPrinterParameterized3(WINDOW_REGISTERED, 1, 0, 0, sFontColor_White, TEXT_SKIP_DRAW, sText_DexNav_PressRToRegister); + } + else + { + StringCopy(gStringVar1, GetSpeciesName(species)); + StringExpandPlaceholders(gStringVar4, sText_DexNav_SearchForRegisteredSpecies); + AddTextPrinterParameterized3(WINDOW_REGISTERED, 1, 0, 0, sFontColor_White, TEXT_SKIP_DRAW, gStringVar4); + } + + PrintMapName(); +} + +static void CreateTypeIconSprites(void) +{ + u8 i; + + LoadCompressedSpriteSheet(&gSpriteSheet_MoveTypes); + LoadCompressedPalette(gMoveTypes_Pal, 0x1D0, 0x60); + for (i = 0; i < 2; i++) + { + if (sDexNavUiDataPtr->typeIconSpriteIds[i] == 0xFF) + sDexNavUiDataPtr->typeIconSpriteIds[i] = CreateSprite(&gSpriteTemplate_MoveTypes, 10, 10, 2); + + SetSpriteInvisibility(i, TRUE); + } +} + +static bool8 DexNav_DoGfxSetup(void) +{ + u8 taskId; + + switch (gMain.state) + { + case 0: + SetVBlankHBlankCallbacksToNull(); + ClearScheduledBgCopiesToVram(); + gMain.state++; + break; + case 1: + ScanlineEffect_Stop(); + gMain.state++; + break; + case 2: + FreeAllSpritePalettes(); + gMain.state++; + break; + case 3: + ResetPaletteFade(); + ResetSpriteData(); + ResetTasks(); + gMain.state++; + break; + case 4: + if (DexNav_InitBgs()) + { + sDexNavUiDataPtr->state = 0; + gMain.state++; + } + else + { + DexNavFadeAndExit(); + return TRUE; + } + break; + case 5: + if (DexNav_LoadGraphics() == TRUE) + gMain.state++; + break; + case 6: + DexNav_InitWindows(); + sDexNavUiDataPtr->cursorRow = ROW_LAND_TOP; + sDexNavUiDataPtr->cursorCol = 0; + sDexNavUiDataPtr->environment = ENCOUNTER_TYPE_LAND; + gMain.state++; + break; + case 7: + PrintSearchableSpecies(VarGet(VAR_DEXNAV_SPECIES) & DEXNAV_MASK_SPECIES); + DexNavLoadEncounterData(); + gMain.state++; + break; + case 8: + taskId = CreateTask(Task_DexNavWaitFadeIn, 0); + gTasks[taskId].tSpecies = 0; + gTasks[taskId].tEnvironment = sDexNavUiDataPtr->environment; + gMain.state++; + break; + case 9: + sDexNavUiDataPtr->typeIconSpriteIds[0] = 0xFF; + sDexNavUiDataPtr->typeIconSpriteIds[1] = 0xFF; + CreateTypeIconSprites(); + gMain.state++; + break; + case 10: + LoadMonIconPalettes(); + DrawSpeciesIcons(); + CreateSelectionCursor(); + DexNavLoadCapturedAllSymbols(); + gMain.state++; + break; + case 11: + BlendPalettes(0xFFFFFFFF, 16, RGB_BLACK); + gMain.state++; + break; + case 12: + BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB_BLACK); + gMain.state++; + break; + default: + SetVBlankCallback(DexNav_VBlankCB); + SetMainCallback2(DexNav_MainCB); + return TRUE; + } + + return FALSE; +} + +static void DexNav_RunSetup(void) +{ + while (!DexNav_DoGfxSetup()) {} +} + +// Entry point for the dexnav GUI +static void DexNavGuiInit(MainCallback callback) +{ + if ((sDexNavUiDataPtr = AllocZeroed(sizeof(struct DexNavGUI))) == NULL) + { + SetMainCallback2(callback); + return; + } + + sDexNavUiDataPtr->state = 0; + sDexNavUiDataPtr->savedCallback = callback; + SetMainCallback2(DexNav_RunSetup); +} + +void Task_OpenDexNavFromStartMenu(u8 taskId) +{ + if (DEXNAV_ENABLED == FALSE) + { // must have it enabled to enter + DebugPrintfLevel(MGBA_LOG_ERROR, "DexNav was opened when DEXNAV_ENABLED config was disabled! Check include/config/dexnav.h"); + DestroyTask(taskId); + } + else if (!gPaletteFade.active) + { + CleanupOverworldWindowsAndTilemaps(); + DexNavGuiInit(CB2_ReturnToFieldWithOpenMenu); + DestroyTask(taskId); + } +} + +static void Task_DexNavWaitFadeIn(u8 taskId) +{ + if (!gPaletteFade.active) + gTasks[taskId].func = Task_DexNavMain; +} + +static void Task_DexNavMain(u8 taskId) +{ + struct Task *task = &gTasks[taskId]; + u16 species; + + if (IsSEPlaying()) + return; + + if (JOY_NEW(B_BUTTON)) + { + PlaySE(SE_POKENAV_OFF); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + task->func = Task_DexNavFadeAndExit; + } + else if (JOY_NEW(DPAD_UP)) + { + if (sDexNavUiDataPtr->cursorRow == ROW_WATER) + { + sDexNavUiDataPtr->cursorRow = ROW_HIDDEN; + if (sDexNavUiDataPtr->cursorCol >= COL_HIDDEN_COUNT) + sDexNavUiDataPtr->cursorCol = COL_HIDDEN_MAX; + } + else + { + if (sDexNavUiDataPtr->cursorRow == ROW_LAND_TOP && sDexNavUiDataPtr->cursorCol == COL_LAND_MAX) + sDexNavUiDataPtr->cursorCol = COL_WATER_MAX; + + sDexNavUiDataPtr->cursorRow--; + } + + PlaySE(SE_RG_BAG_CURSOR); + UpdateCursorPosition(); + } + else if (JOY_NEW(DPAD_DOWN)) + { + if (sDexNavUiDataPtr->cursorRow == ROW_HIDDEN) + { + sDexNavUiDataPtr->cursorRow = ROW_WATER; + } + else if (sDexNavUiDataPtr->cursorRow == ROW_LAND_BOT) + { + if (sDexNavUiDataPtr->cursorCol >= COL_HIDDEN_COUNT) + sDexNavUiDataPtr->cursorCol = COL_HIDDEN_MAX; + + sDexNavUiDataPtr->cursorRow++; + } + else + { + sDexNavUiDataPtr->cursorRow++; + } + + PlaySE(SE_RG_BAG_CURSOR); + UpdateCursorPosition(); + } + else if (JOY_NEW(DPAD_LEFT)) + { + if (sDexNavUiDataPtr->cursorCol == 0) + { + switch (sDexNavUiDataPtr->cursorRow) + { + case ROW_WATER: + sDexNavUiDataPtr->cursorCol = COL_WATER_MAX; + break; + case ROW_HIDDEN: + sDexNavUiDataPtr->cursorCol = COL_HIDDEN_MAX; + break; + default: + sDexNavUiDataPtr->cursorCol = COL_LAND_MAX; + break; + } + } + else + { + sDexNavUiDataPtr->cursorCol--; + } + + PlaySE(SE_RG_BAG_CURSOR); + UpdateCursorPosition(); + } + else if (JOY_NEW(DPAD_RIGHT)) + { + switch (sDexNavUiDataPtr->cursorRow) + { + case ROW_WATER: + if (sDexNavUiDataPtr->cursorCol == COL_WATER_MAX) + sDexNavUiDataPtr->cursorCol = 0; + else + sDexNavUiDataPtr->cursorCol++; + break; + case ROW_HIDDEN: + if (sDexNavUiDataPtr->cursorCol == COL_HIDDEN_MAX) + sDexNavUiDataPtr->cursorCol = 0; + else + sDexNavUiDataPtr->cursorCol++; + break; + default: + if (sDexNavUiDataPtr->cursorCol == COL_LAND_MAX) + sDexNavUiDataPtr->cursorCol = 0; + else + sDexNavUiDataPtr->cursorCol++; + break; + } + + PlaySE(SE_RG_BAG_CURSOR); + UpdateCursorPosition(); + } + else if (JOY_NEW(R_BUTTON)) + { + // check selection is valid. Play sound if invalid + species = DexNavGetSpecies(); + + if (species != SPECIES_NONE) + { + PrintSearchableSpecies(species); + //PlaySE(SE_DEX_SEARCH); + PlayCry_Script(species, 0); + + // create value to store in a var + VarSet(VAR_DEXNAV_SPECIES, ((sDexNavUiDataPtr->environment << 14) | species)); + } + else + { + PlaySE(SE_FAILURE); + } + } + else if (JOY_NEW(A_BUTTON)) + { + species = DexNavGetSpecies(); + if (species == SPECIES_NONE) + { + PlaySE(SE_FAILURE); + } + else + { + gSpecialVar_0x8000 = species; + gSpecialVar_0x8001 = sDexNavUiDataPtr->environment; + gSpecialVar_0x8002 = (sDexNavUiDataPtr->cursorRow == ROW_HIDDEN) ? TRUE : FALSE; + PlaySE(SE_DEX_SEARCH); + BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); + task->func = Task_DexNavExitAndSearch; + } + } +} + +///////////////////////// +//// HIDDEN POKEMON ///// +///////////////////////// +bool8 TryFindHiddenPokemon(void) +{ + u16 *stepPtr = GetVarPointer(VAR_DEXNAV_STEP_COUNTER); + + if (DEXNAV_ENABLED == 0 + || !FlagGet(FLAG_SYS_DETECTOR_MODE) + || FlagGet(FLAG_SYS_DEXNAV_SEARCH) + || GetFlashLevel() > 0) + { + if (stepPtr != NULL) + (*stepPtr) = 0; + return FALSE; + } + + (*stepPtr)++; + (*stepPtr) %= HIDDEN_MON_STEP_COUNT; + if ((*stepPtr) == 0 && (Random() % 100 < HIDDEN_MON_SEARCH_RATE)) + { + // hidden pokemon + u16 headerId = GetCurrentMapWildMonHeaderId(); + u8 index; + u16 species; + u8 environment; + u8 taskId; + const struct WildPokemonInfo* hiddenMonsInfo = gWildMonHeaders[headerId].hiddenMonsInfo; + bool8 isHiddenMon = FALSE; + + // while you can still technically find hidden pokemon if there are not hidden-only pokemon on a map, + // this prevents any potential lagging on maps you dont want hidden pokemon to appear on + if (hiddenMonsInfo == NULL) + return FALSE; + + // encounter rate signifies surfing (1) or land mons (0)! + // again, for simplicity + switch (hiddenMonsInfo->encounterRate) + { + case 0: // land + // there are surely better ways to do this, but this allows greatest flexibility + if (Random() % 100 < HIDDEN_MON_PROBABILTY) + { + index = ChooseHiddenMonIndex(); + if (index == 0xFF) + return FALSE;//no hidden info + species = hiddenMonsInfo->wildPokemon[index].species; + isHiddenMon = TRUE; + environment = ENCOUNTER_TYPE_HIDDEN; + } + else + { + species = gWildMonHeaders[headerId].landMonsInfo->wildPokemon[ChooseWildMonIndex_Land()].species; + environment = ENCOUNTER_TYPE_LAND; + } + break; + case 1: // water + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) + { + if (Random() % 100 < HIDDEN_MON_PROBABILTY) + { + index = ChooseHiddenMonIndex(); + if (index == 0xFF) + return FALSE;//no hidden info + species = hiddenMonsInfo->wildPokemon[index].species; + isHiddenMon = TRUE; + environment = ENCOUNTER_TYPE_HIDDEN; + } + else + { + species = gWildMonHeaders[headerId].waterMonsInfo->wildPokemon[ChooseWildMonIndex_WaterRock()].species; + environment = ENCOUNTER_TYPE_WATER; + + } + } + else + { + // not surfing -> cant find hidden water mons + return FALSE; + } + break; + default: + return FALSE; + } + + if (species == SPECIES_NONE) + return FALSE; + + sDexNavSearchDataPtr = AllocZeroed(sizeof(struct DexNavSearch)); + + // init search data + sDexNavSearchDataPtr->isHiddenMon = isHiddenMon; + sDexNavSearchDataPtr->species = species; + sDexNavSearchDataPtr->hiddenSearch = TRUE; + sDexNavSearchDataPtr->environment = environment; // updated in DexNavTryGenerateMonLevel if hidden mon + sDexNavSearchDataPtr->monLevel = DexNavTryGenerateMonLevel(species, environment); + if (sDexNavSearchDataPtr->monLevel == MON_LEVEL_NONEXISTENT) + { + Free(sDexNavSearchDataPtr); + return FALSE; + } + + // find tile for hidden mon and start effect if possible + if (!TryStartHiddenMonFieldEffect(sDexNavSearchDataPtr->environment, 8, 8, TRUE)) + return FALSE; + + // exclamation mark over player + gFieldEffectArguments[0] = gSaveBlock1Ptr->pos.x; + gFieldEffectArguments[1] = gSaveBlock1Ptr->pos.y; + gFieldEffectArguments[2] = gSprites[gPlayerAvatar.spriteId].subpriority - 1; + gFieldEffectArguments[3] = 2; + ObjectEventGetLocalIdAndMap(&gObjectEvents[gPlayerAvatar.objectEventId], &gFieldEffectArguments[0], &gFieldEffectArguments[1], &gFieldEffectArguments[2]); + FieldEffectStart(FLDEFF_EXCLAMATION_MARK_ICON); + + PlayCry_Script(species, 0); + taskId = CreateTask(Task_SetUpDexNavSearch, 0); + gTasks[taskId].tSpecies = sDexNavSearchDataPtr->species; + gTasks[taskId].tEnvironment = sDexNavSearchDataPtr->environment; + gTasks[taskId].tRevealed = FALSE; + HideMapNamePopUpWindow(); + ChangeBgY_ScreenOff(0, 0, 0); + return FALSE; // we dont actually want to enable the script context or the game will freeze + } + + return FALSE; +} + +static void DrawSearchIcon(void) +{ + struct CompressedSpriteSheet spriteSheet; + + spriteSheet.data = sHiddenSearchIconGfx; + spriteSheet.size = 0x200; + spriteSheet.tag = SELECTION_CURSOR_TAG; + LoadCompressedSpriteSheet(&spriteSheet); + sDexNavSearchDataPtr->iconSpriteId = CreateSprite(&sSearchIconSpriteTemplate, 18, GetSearchWindowY() + 12, 0); +} + +// the initial hidden icon window ONLY shows search icon, ??? instead of name, and the search level (and pokeball icon if owned) +// if the player presses R or moves close enough, the full search window will be created +// this way, if the player is not interested in hidden pokemon it will not be too intrusive +static void DrawHiddenSearchWindow(u8 width) +{ + AddSearchWindow(width); + AddTextPrinterParameterized3(sDexNavSearchDataPtr->windowId, 0, SPECIES_ICON_X + 4, 0, sSearchFontColor, TEXT_SKIP_DRAW, sText_ThreeQmarks); + + ConvertIntToDecimalStringN(gStringVar1, sDexNavSearchDataPtr->searchLevel, STR_CONV_MODE_LEFT_ALIGN, 2); + StringExpandPlaceholders(gStringVar4, sText_SearchLevel); + AddTextPrinterParameterized3(sDexNavSearchDataPtr->windowId, 0, SPECIES_ICON_X + 4, 12, sSearchFontColor, TEXT_SKIP_DRAW, gStringVar4); + CopyWindowToVram(sDexNavSearchDataPtr->windowId, 2); +} + +static void DexNavDrawHiddenIcons(void) +{ + u16 species = sDexNavSearchDataPtr->species; + + DrawHiddenSearchWindow(12); + DrawSearchIcon(); + + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + sDexNavSearchDataPtr->ownedIconSpriteId = CreateSprite(&sOwnedIconTemplate, SPECIES_ICON_X + 6, GetSearchWindowY() + 2, 0); + + if (sDexNavSearchDataPtr->isHiddenMon) + sDexNavSearchDataPtr->exclamationSpriteId = CreateSprite(&sHiddenMonIconTemplate, SPECIES_ICON_X + 34, GetSearchWindowY() + 8, 0); +} + +///////////////////////// +//// GENERAL UTILITY //// +///////////////////////// +u32 CalculateDexNavShinyRolls(void) +{ + u32 chainBonus, rndBonus; + u8 chain = gSaveBlock3Ptr->dexNavChain; + + chainBonus = (chain >= 100) ? 10 : (chain >= 50) ? 5 : 0; + rndBonus = (Random() % 100 < 4) ? 4 : 0; + return chainBonus + rndBonus; +} + +void TryIncrementSpeciesSearchLevel(u16 dexNum) +{ +#if USE_DEXNAV_SEARCH_LEVELS == TRUE + if (gMapHeader.regionMapSectionId != MAPSEC_BATTLE_FRONTIER && gSaveBlock3Ptr->dexNavSearchLevels[dexNum] < 255) + gSaveBlock3Ptr->dexNavSearchLevels[dexNum]++; +#endif +} + +void ResetDexNavSearch(void) +{ + gSaveBlock3Ptr->dexNavChain = 0; //reset dex nav chaining on new map + VarSet(VAR_DEXNAV_STEP_COUNTER, 0); //reset hidden pokemon step counter + if (FlagGet(FLAG_SYS_DEXNAV_SEARCH)) + EndDexNavSearch(FindTaskIdByFunc(Task_DexNavSearch)); //moving to new map ends dexnav search +} + +void IncrementDexNavChain(void) +{ + if (gSaveBlock3Ptr->dexNavChain < DEXNAV_CHAIN_MAX) + gSaveBlock3Ptr->dexNavChain++; +} diff --git a/src/difficulty.c b/src/difficulty.c new file mode 100644 index 000000000000..470c7fb3fd69 --- /dev/null +++ b/src/difficulty.c @@ -0,0 +1,105 @@ +#include "global.h" +#include "data.h" +#include "event_data.h" +#include "script.h" +#include "constants/battle.h" + +enum DifficultyLevel GetCurrentDifficultyLevel(void) +{ + if (!B_VAR_DIFFICULTY) + return DIFFICULTY_NORMAL; + + return VarGet(B_VAR_DIFFICULTY); +} + +void SetCurrentDifficultyLevel(enum DifficultyLevel desiredDifficulty) +{ + if (!B_VAR_DIFFICULTY) + return; + + if (desiredDifficulty > DIFFICULTY_MAX) + desiredDifficulty = DIFFICULTY_MAX; + + VarSet(B_VAR_DIFFICULTY, desiredDifficulty); +} + +enum DifficultyLevel GetBattlePartnerDifficultyLevel(u16 partnerId) +{ + enum DifficultyLevel difficulty = GetCurrentDifficultyLevel(); + + if (partnerId > TRAINER_PARTNER(PARTNER_NONE)) + partnerId -= TRAINER_PARTNER(PARTNER_NONE); + + if (difficulty == DIFFICULTY_NORMAL) + return DIFFICULTY_NORMAL; + + if (gBattlePartners[difficulty][partnerId].party == NULL) + return DIFFICULTY_NORMAL; + + return difficulty; +} + +enum DifficultyLevel GetTrainerDifficultyLevel(u16 trainerId) +{ + enum DifficultyLevel difficulty = GetCurrentDifficultyLevel(); + + if (difficulty == DIFFICULTY_NORMAL) + return DIFFICULTY_NORMAL; + + if (gTrainers[difficulty][trainerId].party == NULL) + return DIFFICULTY_NORMAL; + + return difficulty; +} + +void Script_IncreaseDifficulty(void) +{ + enum DifficultyLevel currentDifficulty; + + if (!B_VAR_DIFFICULTY) + return; + + currentDifficulty = GetCurrentDifficultyLevel(); + + if (currentDifficulty++ > DIFFICULTY_MAX) + return; + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(B_VAR_DIFFICULTY); + + SetCurrentDifficultyLevel(currentDifficulty); +} + +void Script_DecreaseDifficulty(void) +{ + enum DifficultyLevel currentDifficulty; + + if (!B_VAR_DIFFICULTY) + return; + + currentDifficulty = GetCurrentDifficultyLevel(); + + if (!currentDifficulty) + return; + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(B_VAR_DIFFICULTY); + + SetCurrentDifficultyLevel(--currentDifficulty); +} + +void Script_GetDifficulty(void) +{ + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = GetCurrentDifficultyLevel(); +} + +void Script_SetDifficulty(struct ScriptContext *ctx) +{ + enum DifficultyLevel desiredDifficulty = ScriptReadByte(ctx); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(B_VAR_DIFFICULTY); + + SetCurrentDifficultyLevel(desiredDifficulty); +} diff --git a/src/digit_obj_util.c b/src/digit_obj_util.c index f66dc80cb709..f9e3ed1c01d1 100644 --- a/src/digit_obj_util.c +++ b/src/digit_obj_util.c @@ -239,9 +239,9 @@ static void DrawNumObjsLeadingZeros(struct DigitPrinter *objWork, s32 num, bool3 static void DrawNumObjsMinusInFront(struct DigitPrinter *objWork, s32 num, bool32 sign) { u32 pow10 = objWork->pow10; - static int oamId; - static int curDigit; - static int firstDigit; + int oamId; + int curDigit; + int firstDigit; oamId = objWork->firstOamId; curDigit = 0; diff --git a/src/easy_chat.c b/src/easy_chat.c index ce3b4fe907ce..aa8405be759e 100644 --- a/src/easy_chat.c +++ b/src/easy_chat.c @@ -17,6 +17,7 @@ #include "main.h" #include "mystery_gift.h" #include "menu.h" +#include "move.h" #include "overworld.h" #include "palette.h" #include "pokedex.h" diff --git a/src/ereader_screen.c b/src/ereader_screen.c old mode 100755 new mode 100644 index 556acf8e3c59..ef1f45d49a0b --- a/src/ereader_screen.c +++ b/src/ereader_screen.c @@ -40,9 +40,6 @@ struct EReaderData static void Task_EReader(u8); -// This belongs in COMMON somewhere between party_menu and ereader_screen, but it's unused so it's unclear where. -COMMON_DATA UNUSED u8 gUnknownSpace[64] = {0}; - COMMON_DATA struct EReaderData gEReaderData = {0}; extern const u8 gMultiBootProgram_EReader_Start[]; diff --git a/src/event_object_movement.c b/src/event_object_movement.c index 47640b8f4ed1..581cd946204c 100644 --- a/src/event_object_movement.c +++ b/src/event_object_movement.c @@ -200,7 +200,6 @@ static bool8 GetFollowerInfo(u16 *species, u8 *form, u8 *shiny); static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny); static const struct ObjectEventGraphicsInfo *SpeciesToGraphicsInfo(u16 species, u8 form); static bool8 NpcTakeStep(struct Sprite *); -static bool8 IsElevationMismatchAt(u8, s16, s16); static bool8 AreElevationsCompatible(u8, u8); static void CopyObjectGraphicsInfoToSpriteTemplate_WithMovementType(u16 graphicsId, u16 movementType, struct SpriteTemplate *spriteTemplate, const struct SubspriteTable **subspriteTables); @@ -2520,7 +2519,7 @@ void GetFollowerAction(struct ScriptContext *ctx) // Essentially a big switch fo } if (multi < NUMBER_OF_MON_TYPES) { - multi = GetTypeEffectiveness(mon, multi); + multi = GetOverworldTypeEffectiveness(mon, multi); if (multi <= UQ_4_12(0.5)) condEmotes[condCount++] = (struct SpecialEmote) {.emotion = FOLLOWER_EMOTION_HAPPY, .index = 32}; else if (multi >= UQ_4_12(2.0)) @@ -6013,9 +6012,15 @@ u8 GetDirectionToFace(s16 x, s16 y, s16 targetX, s16 targetY) // Uses the above, but script accessible, and uses localIds void GetDirectionToFaceScript(struct ScriptContext *ctx) { - u16 *var = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); u8 sourceId = GetObjectEventIdByLocalId(ScriptReadByte(ctx)); u8 targetId = GetObjectEventIdByLocalId(ScriptReadByte(ctx)); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + + u16 *var = GetVarPointer(varId); + if (var == NULL) return; if (sourceId >= OBJECT_EVENTS_COUNT || targetId >= OBJECT_EVENTS_COUNT) @@ -6031,7 +6036,12 @@ void GetDirectionToFaceScript(struct ScriptContext *ctx) // Intended to be called before the field effect itself void IsFollowerFieldMoveUser(struct ScriptContext *ctx) { - u16 *var = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + + u16 *var = GetVarPointer(varId); u16 userIndex = gFieldEffectArguments[0]; // field move user index struct Pokemon *follower = GetFirstLiveMon(); struct ObjectEvent *obj = GetFollowerObject(); @@ -9580,7 +9590,7 @@ static void SetObjectEventSpriteOamTableForLongGrass(struct ObjectEvent *objEven sprite->subspriteTableNum = 5; } -static bool8 IsElevationMismatchAt(u8 elevation, s16 x, s16 y) +bool8 IsElevationMismatchAt(u8 elevation, s16 x, s16 y) { u8 mapElevation; @@ -10996,6 +11006,13 @@ void GetDaycareGraphics(struct ScriptContext *ctx) u8 form; u8 shiny; s32 i; + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varGfx[0]); + Script_RequestWriteVar(varGfx[1]); + Script_RequestWriteVar(varForm[0]); + Script_RequestWriteVar(varForm[1]); + for (i = 0; i < 2; i++) { GetMonInfo((struct Pokemon *) &gSaveBlock1Ptr->daycare.mons[i].mon, &specGfx, &form, &shiny); diff --git a/src/fake_rtc.c b/src/fake_rtc.c index f3f3b74c3960..4dbf7837baba 100644 --- a/src/fake_rtc.c +++ b/src/fake_rtc.c @@ -5,6 +5,7 @@ #include "rtc.h" #include "fake_rtc.h" #include "event_data.h" +#include "script.h" struct Time *FakeRtc_GetCurrentTime(void) { @@ -90,15 +91,21 @@ STATIC_ASSERT((OW_FLAG_PAUSE_TIME == 0 || OW_USE_FAKE_RTC == TRUE), FakeRtcMustB void Script_PauseFakeRtc(void) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + FlagSet(OW_FLAG_PAUSE_TIME); } void Script_ResumeFakeRtc(void) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + FlagClear(OW_FLAG_PAUSE_TIME); } void Script_ToggleFakeRtc(void) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + FlagToggle(OW_FLAG_PAUSE_TIME); } diff --git a/src/field_camera.c b/src/field_camera.c index e76ba3d855cd..89f73ccbec90 100644 --- a/src/field_camera.c +++ b/src/field_camera.c @@ -12,7 +12,7 @@ #include "sprite.h" #include "text.h" -EWRAM_DATA bool8 gUnusedBikeCameraAheadPanback = FALSE; +//EWRAM_DATA bool8 gUnusedBikeCameraAheadPanback = FALSE; // Old EWRAM variable that was never set to anything other than false struct FieldCameraOffset { @@ -464,6 +464,11 @@ void UpdateCameraPanning(void) static void CameraPanningCB_PanAhead(void) { + InstallCameraPanAheadCallback(); + // Old code kept for archival purposes + // The else condition could never run since gUnusedBikeCameraAheadPanback was never set to TRUE + // So the behavior should not change + /* u8 var; if (gUnusedBikeCameraAheadPanback == FALSE) @@ -504,4 +509,5 @@ static void CameraPanningCB_PanAhead(void) sVerticalCameraPan -= 2; } } + */ } diff --git a/src/field_control_avatar.c b/src/field_control_avatar.c index 05da7d2041d9..d87c7ca010c9 100644 --- a/src/field_control_avatar.c +++ b/src/field_control_avatar.c @@ -4,6 +4,7 @@ #include "coord_event_weather.h" #include "daycare.h" #include "debug.h" +#include "dexnav.h" #include "faraway_island.h" #include "event_data.h" #include "event_object_movement.h" @@ -91,7 +92,7 @@ void FieldClearPlayerInput(struct FieldInput *input) input->heldDirection2 = FALSE; input->tookStep = FALSE; input->pressedBButton = FALSE; - input->input_field_1_0 = FALSE; + input->pressedRButton = FALSE; input->input_field_1_1 = FALSE; input->input_field_1_2 = FALSE; input->input_field_1_3 = FALSE; @@ -116,6 +117,8 @@ void FieldGetPlayerInput(struct FieldInput *input, u16 newKeys, u16 heldKeys) input->pressedAButton = TRUE; if (newKeys & B_BUTTON) input->pressedBButton = TRUE; + if (newKeys & R_BUTTON && !FlagGet(FLAG_SYS_DEXNAV_SEARCH)) + input->pressedRButton = TRUE; } if (heldKeys & (DPAD_UP | DPAD_DOWN | DPAD_LEFT | DPAD_RIGHT)) @@ -222,8 +225,15 @@ int ProcessPlayerFieldInput(struct FieldInput *input) ShowStartMenu(); return TRUE; } + + if (input->tookStep && TryFindHiddenPokemon()) + return TRUE; + if (input->pressedSelectButton && UseRegisteredKeyItemOnField() == TRUE) return TRUE; + + if (input->pressedRButton && TryStartDexNavSearch()) + return TRUE; if(input->input_field_1_2 && DEBUG_OVERWORLD_MENU && !DEBUG_OVERWORLD_IN_MENU) { @@ -265,7 +275,7 @@ static u16 GetPlayerCurMetatileBehavior(int runningState) static bool8 TryStartInteractionScript(struct MapPosition *position, u16 metatileBehavior, u8 direction) { const u8 *script = GetInteractionScript(position, metatileBehavior, direction); - if (script == NULL) + if (script == NULL || Script_HasNoEffect(script)) return FALSE; // Don't play interaction sound for certain scripts. @@ -580,7 +590,12 @@ static bool8 TryStartCoordEventScript(struct MapPosition *position) if (script == NULL) return FALSE; - ScriptContext_SetupScript(script); + + struct ScriptContext ctx; + if (!RunScriptImmediatelyUntilEffect(SCREFF_V1 | SCREFF_HARDWARE, script, &ctx)) + return FALSE; + + ScriptContext_ContinueScript(&ctx); return TRUE; } diff --git a/src/field_effect.c b/src/field_effect.c index 501a249ee481..45631be6a348 100644 --- a/src/field_effect.c +++ b/src/field_effect.c @@ -1,6 +1,7 @@ #include "global.h" #include "data.h" #include "decompress.h" +#include "event_data.h" #include "event_object_movement.h" #include "field_camera.h" #include "field_control_avatar.h" @@ -28,9 +29,10 @@ #include "trainer_pokemon_sprites.h" #include "trig.h" #include "util.h" -#include "constants/field_effects.h" #include "constants/event_objects.h" #include "constants/event_object_movement.h" +#include "constants/field_effects.h" +#include "constants/flags.h" #include "constants/metatile_behaviors.h" #include "constants/rgb.h" #include "constants/songs.h" @@ -39,6 +41,7 @@ #define subsprite_table(ptr) {.subsprites = ptr, .subspriteCount = (sizeof ptr) / (sizeof(struct Subsprite))} EWRAM_DATA s32 gFieldEffectArguments[8] = {0}; +EWRAM_DATA bool8 gSkipShowMonAnim = FALSE; // Static type declarations @@ -3231,7 +3234,8 @@ static void FlyOutFieldEffect_ShowMon(struct Task *task) { task->tState++; gFieldEffectArguments[0] = task->tMonId; - FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON_INIT); + if (!gSkipShowMonAnim) + FieldEffectStart(FLDEFF_FIELD_MOVE_SHOW_MON_INIT); } } @@ -3480,6 +3484,7 @@ static void StartFlyBirdReturnToBall(u8 spriteId) u8 FldEff_FlyIn(void) { CreateTask(Task_FlyIn, 254); + gSkipShowMonAnim = FALSE; // Clears this variable so flying via the party menu keeps the show mon animation return 0; } @@ -3932,6 +3937,21 @@ static void Task_MoveDeoxysRock(u8 taskId) } } +u8 FldEff_CaveDust(void) +{ + u8 spriteId; + + SetSpritePosToOffsetMapCoords((s16 *)&gFieldEffectArguments[0], (s16 *)&gFieldEffectArguments[1], 8, 8); + spriteId = CreateSpriteAtEnd(gFieldEffectObjectTemplatePointers[FLDEFFOBJ_CAVE_DUST], gFieldEffectArguments[0], gFieldEffectArguments[1], 0xFF); + if (spriteId != MAX_SPRITES) + { + gSprites[spriteId].coordOffsetEnabled = TRUE; + gSprites[spriteId].data[0] = 22; + } + + return spriteId; +} + #undef tState #undef tSpriteId #undef tTargetX diff --git a/src/field_effect_helpers.c b/src/field_effect_helpers.c index 1991892a5088..c17803d0f243 100755 --- a/src/field_effect_helpers.c +++ b/src/field_effect_helpers.c @@ -1015,7 +1015,7 @@ void UpdateHotSpringsWaterFieldEffect(struct Sprite *sprite) #undef sPrevX #undef sPrevY -u32 FldEff_UnusedGrass(void) +u32 FldEff_ShakingGrass(void) { u8 spriteId; @@ -1026,12 +1026,13 @@ u32 FldEff_UnusedGrass(void) struct Sprite *sprite = &gSprites[spriteId]; sprite->coordOffsetEnabled = TRUE; sprite->oam.priority = gFieldEffectArguments[3]; - sprite->sWaitFldEff = FLDEFF_UNUSED_GRASS; + sprite->sWaitFldEff = FLDEFF_SHAKING_GRASS; } - return 0; + + return spriteId; } -u32 FldEff_UnusedGrass2(void) +u32 FldEff_ShakingGrass2(void) { u8 spriteId; @@ -1042,9 +1043,10 @@ u32 FldEff_UnusedGrass2(void) struct Sprite *sprite = &gSprites[spriteId]; sprite->coordOffsetEnabled = TRUE; sprite->oam.priority = gFieldEffectArguments[3]; - sprite->sWaitFldEff = FLDEFF_UNUSED_GRASS_2; + sprite->sWaitFldEff = FLDEFF_SHAKING_LONG_GRASS; } - return 0; + + return spriteId; } u32 FldEff_UnusedSand(void) @@ -1058,9 +1060,9 @@ u32 FldEff_UnusedSand(void) struct Sprite *sprite = &gSprites[spriteId]; sprite->coordOffsetEnabled = TRUE; sprite->oam.priority = gFieldEffectArguments[3]; - sprite->sWaitFldEff = FLDEFF_UNUSED_SAND; + sprite->sWaitFldEff = FLDEFF_SAND_HOLE; } - return 0; + return spriteId; } u32 FldEff_WaterSurfacing(void) @@ -1076,7 +1078,8 @@ u32 FldEff_WaterSurfacing(void) sprite->oam.priority = gFieldEffectArguments[3]; sprite->sWaitFldEff = FLDEFF_WATER_SURFACING; } - return 0; + + return spriteId; } // Sprite data for FLDEFF_ASH @@ -1474,7 +1477,7 @@ u32 FldEff_BerryTreeGrowthSparkle(void) UpdateSpritePaletteByTemplate(gFieldEffectObjectTemplatePointers[FLDEFFOBJ_SPARKLE], sprite); sprite->sWaitFldEff = FLDEFF_BERRY_TREE_GROWTH_SPARKLE; } - return 0; + return spriteId; } // Sprite data for FLDEFF_TREE_DISGUISE / FLDEFF_MOUNTAIN_DISGUISE / FLDEFF_SAND_DISGUISE @@ -1602,7 +1605,7 @@ u32 FldEff_Sparkle(void) gSprites[spriteId].oam.priority = gFieldEffectArguments[2]; gSprites[spriteId].coordOffsetEnabled = TRUE; } - return 0; + return spriteId; } void UpdateSparkleFieldEffect(struct Sprite *sprite) @@ -1866,27 +1869,3 @@ static void UpdateGrassFieldEffectSubpriority(struct Sprite *sprite, u8 elevatio } } -// Unused, duplicates of data in event_object_movement.c -static const s8 sFigure8XOffsets[FIGURE_8_LENGTH] = { - 1, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 2, 2, 1, 2, - 2, 1, 2, 2, 1, 2, 1, 1, - 2, 1, 1, 2, 1, 1, 2, 1, - 1, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 0, - 1, 0, 1, 0, 1, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, -}; - -static const s8 sFigure8YOffsets[FIGURE_8_LENGTH] = { - 0, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 1, 1, 0, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 1, - 0, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, -1, 0, 0, -1, 0, 0, - -1, 0, -1, -1, 0, -1, -1, 0, - -1, -1, -1, -1, -1, -1, -1, -2, -}; diff --git a/src/field_player_avatar.c b/src/field_player_avatar.c index ebf61bdaa3c5..2aed46627cf9 100644 --- a/src/field_player_avatar.c +++ b/src/field_player_avatar.c @@ -665,11 +665,20 @@ static void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys) return; } } - + + gPlayerAvatar.creeping = FALSE; if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_SURFING) { - // same speed as running - PlayerWalkFast(direction); + if (FlagGet(FLAG_SYS_DEXNAV_SEARCH) && (heldKeys & A_BUTTON)) + { + gPlayerAvatar.creeping = TRUE; + PlayerWalkSlow(direction); + } + else + { + // speed 2 is fast, same speed as running + PlayerWalkFast(direction); + } return; } @@ -684,6 +693,11 @@ static void PlayerNotOnBikeMoving(u8 direction, u16 heldKeys) gPlayerAvatar.flags |= PLAYER_AVATAR_FLAG_DASH; return; } + else if (FlagGet(FLAG_SYS_DEXNAV_SEARCH) && (heldKeys & A_BUTTON)) + { + gPlayerAvatar.creeping = TRUE; + PlayerWalkSlow(direction); + } else { if (ObjectMovingOnRockStairs(&gObjectEvents[gPlayerAvatar.objectEventId], direction)) @@ -1222,6 +1236,8 @@ u8 player_get_pos_including_state_based_drift(s16 *x, s16 *y) u8 GetPlayerFacingDirection(void) { + Script_RequestEffects(SCREFF_V1); + return gObjectEvents[gPlayerAvatar.objectEventId].facingDirection; } diff --git a/src/field_region_map.c b/src/field_region_map.c index 73fc14582b0d..966d2d1327e9 100644 --- a/src/field_region_map.c +++ b/src/field_region_map.c @@ -1,17 +1,22 @@ #include "global.h" #include "bg.h" +#include "event_data.h" +#include "field_effect.h" #include "gpu_regs.h" #include "international_string_util.h" #include "main.h" #include "malloc.h" #include "menu.h" +#include "overworld.h" #include "palette.h" #include "region_map.h" +#include "sound.h" #include "strings.h" #include "text.h" #include "text_window.h" #include "window.h" #include "constants/rgb.h" +#include "constants/songs.h" /* * This is the type of map shown when interacting with the metatiles for @@ -44,7 +49,8 @@ static void MCB2_InitRegionMapRegisters(void); static void VBCB_FieldUpdateRegionMap(void); static void MCB2_FieldUpdateRegionMap(void); static void FieldUpdateRegionMap(void); -static void PrintRegionMapSecName(void); +static void PrintRegionMapSecName(); +static void PrintTitleWindowText(); static const struct BgTemplate sFieldRegionMapBgTemplates[] = { { @@ -139,8 +145,6 @@ static void MCB2_FieldUpdateRegionMap(void) static void FieldUpdateRegionMap(void) { - u8 offset; - switch (sFieldRegionMapHandler->state) { case 0: @@ -151,8 +155,8 @@ static void FieldUpdateRegionMap(void) break; case 1: DrawStdFrameWithCustomTileAndPalette(WIN_TITLE, FALSE, 0x27, 0xd); - offset = GetStringCenterAlignXOffset(FONT_NORMAL, gText_Hoenn, 0x38); - AddTextPrinterParameterized(WIN_TITLE, FONT_NORMAL, gText_Hoenn, offset, 1, 0, NULL); + FillWindowPixelBuffer(WIN_TITLE, PIXEL_FILL(1)); + PrintTitleWindowText(); ScheduleBgCopyTilemapToVram(0); DrawStdFrameWithCustomTileAndPalette(WIN_MAPSEC_NAME, FALSE, 0x27, 0xd); PrintRegionMapSecName(); @@ -176,11 +180,21 @@ static void FieldUpdateRegionMap(void) { case MAP_INPUT_MOVE_END: PrintRegionMapSecName(); + PrintTitleWindowText(); break; case MAP_INPUT_A_BUTTON: case MAP_INPUT_B_BUTTON: sFieldRegionMapHandler->state++; break; + case MAP_INPUT_R_BUTTON: + if (sFieldRegionMapHandler->regionMap.mapSecType == MAPSECTYPE_CITY_CANFLY + && FlagGet(OW_FLAG_POKE_RIDER) && Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE) + { + PlaySE(SE_SELECT); + SetFlyDestination(&sFieldRegionMapHandler->regionMap); + gSkipShowMonAnim = TRUE; + ReturnToFieldFromFlyMapSelect(); + } } break; case 5: @@ -213,3 +227,24 @@ static void PrintRegionMapSecName(void) CopyWindowToVram(WIN_MAPSEC_NAME, COPYWIN_FULL); } } + +static void PrintTitleWindowText(void) +{ + static const u8 FlyPromptText[] = _("{R_BUTTON} FLY"); + u32 hoennOffset = GetStringCenterAlignXOffset(FONT_NORMAL, gText_Hoenn, 0x38); + u32 flyOffset = GetStringCenterAlignXOffset(FONT_NORMAL, FlyPromptText, 0x38); + + FillWindowPixelBuffer(WIN_TITLE, PIXEL_FILL(1)); + + if (sFieldRegionMapHandler->regionMap.mapSecType == MAPSECTYPE_CITY_CANFLY + && FlagGet(OW_FLAG_POKE_RIDER) && Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE) + { + AddTextPrinterParameterized(WIN_TITLE, FONT_NORMAL, FlyPromptText, flyOffset, 1, 0, NULL); + ScheduleBgCopyTilemapToVram(WIN_TITLE); + } + else + { + AddTextPrinterParameterized(WIN_TITLE, FONT_NORMAL, gText_Hoenn, hoennOffset, 1, 0, NULL); + CopyWindowToVram(WIN_TITLE, COPYWIN_FULL); + } +} diff --git a/src/field_weather_effect.c b/src/field_weather_effect.c index cf31e862c3c7..234c9c56d3d9 100644 --- a/src/field_weather_effect.c +++ b/src/field_weather_effect.c @@ -15,7 +15,6 @@ #include "gpu_regs.h" EWRAM_DATA static u8 sCurrentAbnormalWeather = 0; -EWRAM_DATA static u16 sUnusedWeatherRelated = 0; const u16 gCloudsWeatherPalette[] = INCBIN_U16("graphics/weather/cloud.gbapal"); const u16 gSandstormWeatherPalette[] = INCBIN_U16("graphics/weather/sandstorm.gbapal"); @@ -2407,12 +2406,6 @@ static void UpdateBubbleSprite(struct Sprite *sprite) //------------------------------------------------------------------------------ -static void UNUSED UnusedSetCurrentAbnormalWeather(u32 weather, u32 unknown) -{ - sCurrentAbnormalWeather = weather; - sUnusedWeatherRelated = unknown; -} - #define tState data[0] #define tWeatherA data[1] #define tWeatherB data[2] diff --git a/src/fieldmap.c b/src/fieldmap.c index 34a654861ae6..84e3c564fc79 100644 --- a/src/fieldmap.c +++ b/src/fieldmap.c @@ -30,7 +30,6 @@ EWRAM_DATA u16 ALIGNED(4) sBackupMapData[MAX_MAP_DATA_SIZE] = {0}; EWRAM_DATA struct MapHeader gMapHeader = {0}; EWRAM_DATA struct Camera gCamera = {0}; EWRAM_DATA static struct ConnectionFlags sMapConnectionFlags = {0}; -EWRAM_DATA static u32 UNUSED sFiller = 0; // without this, the next file won't align properly COMMON_DATA struct BackupMapLayout gBackupMapLayout = {0}; diff --git a/src/fldeff_cut.c b/src/fldeff_cut.c index 230438167343..a7eccf651c58 100644 --- a/src/fldeff_cut.c +++ b/src/fldeff_cut.c @@ -277,8 +277,8 @@ bool8 SetUpFieldMove_Cut(void) static void FieldCallback_CutGrass(void) { - FieldEffectStart(FLDEFF_USE_CUT_ON_GRASS); gFieldEffectArguments[0] = GetCursorSelectionMonId(); + ScriptContext_SetupScript(EventScript_UseCutGrass); } bool8 FldEff_UseCutOnGrass(void) diff --git a/src/frontier_util.c b/src/frontier_util.c index 44246766444b..30c22d4442bc 100644 --- a/src/frontier_util.c +++ b/src/frontier_util.c @@ -2543,7 +2543,7 @@ void CreateFrontierBrainPokemon(void) for (j = 0; j < MAX_MON_MOVES; j++) { SetMonMoveSlot(&gEnemyParty[monPartyId], sFrontierBrainsMons[facility][symbol][i].moves[j], j); - if (gMovesInfo[sFrontierBrainsMons[facility][symbol][i].moves[j]].effect == EFFECT_FRUSTRATION) + if (GetMoveEffect(sFrontierBrainsMons[facility][symbol][i].moves[j]) == EFFECT_FRUSTRATION) friendship = 0; } SetMonData(&gEnemyParty[monPartyId], MON_DATA_FRIENDSHIP, &friendship); diff --git a/src/generational_changes.c b/src/generational_changes.c new file mode 100644 index 000000000000..1ad29aa675e7 --- /dev/null +++ b/src/generational_changes.c @@ -0,0 +1,19 @@ +#include "global.h" +#include "generational_changes.h" +#include "malloc.h" +#include "constants/generational_changes.h" + +#if TESTING +EWRAM_DATA u8 *gGenerationalChangesTestOverride = NULL; + +void TestInitConfigData(void) +{ + gGenerationalChangesTestOverride = Alloc(sizeof(sGenerationalChanges)); + memcpy(gGenerationalChangesTestOverride, sGenerationalChanges, sizeof(sGenerationalChanges)); +} + +void TestFreeConfigData(void) +{ + TRY_FREE_AND_SET_NULL(gGenerationalChangesTestOverride) +} +#endif diff --git a/src/intro.c b/src/intro.c index 5409833733c7..93417bc4a17b 100644 --- a/src/intro.c +++ b/src/intro.c @@ -176,7 +176,6 @@ enum { #define TIMER_START_LEGENDARIES 43 static EWRAM_DATA u16 sIntroCharacterGender = 0; -static EWRAM_DATA u16 UNUSED sUnusedVar = 0; static EWRAM_DATA u16 sFlygonYOffset = 0; COMMON_DATA u32 gIntroFrameCounter = 0; diff --git a/src/item_icon.c b/src/item_icon.c index 14a812b7fa8f..03b56918be2f 100644 --- a/src/item_icon.c +++ b/src/item_icon.c @@ -1,12 +1,13 @@ #include "global.h" +#include "battle_main.h" #include "decompress.h" #include "graphics.h" +#include "item.h" #include "item_icon.h" #include "malloc.h" +#include "move.h" #include "sprite.h" #include "constants/items.h" -#include "item.h" -#include "battle_main.h" // EWRAM vars EWRAM_DATA u8 *gItemIconDecompressionBuffer = NULL; @@ -182,7 +183,7 @@ const void *GetItemIconPalette(u16 itemId) if (itemId >= ITEMS_COUNT) return gItemsInfo[0].iconPalette; if (itemId >= ITEM_TM01 && itemId < ITEM_HM01 + NUM_HIDDEN_MACHINES) - return gTypesInfo[gMovesInfo[gItemsInfo[itemId].secondaryId].type].paletteTMHM; + return gTypesInfo[GetMoveType(gItemsInfo[itemId].secondaryId)].paletteTMHM; return gItemsInfo[itemId].iconPalette; } diff --git a/src/item_menu.c b/src/item_menu.c index 75751cae6f2e..ff5d569f966f 100755 --- a/src/item_menu.c +++ b/src/item_menu.c @@ -2604,34 +2604,36 @@ static void PrintTMHMMoveData(u16 itemId) else { moveId = ItemIdToBattleMoveId(itemId); - BlitMenuInfoIcon(WIN_TMHM_INFO, gMovesInfo[moveId].type + 1, 0, 0); + BlitMenuInfoIcon(WIN_TMHM_INFO, GetMoveType(moveId) + 1, 0, 0); // Print TMHM power - if (gMovesInfo[moveId].power <= 1) + u32 power = GetMovePower(moveId); + if (power <= 1) { text = gText_ThreeDashes; } else { - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[moveId].power, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, power, STR_CONV_MODE_RIGHT_ALIGN, 3); text = gStringVar1; } BagMenu_Print(WIN_TMHM_INFO, FONT_NORMAL, text, 7, 12, 0, 0, TEXT_SKIP_DRAW, COLORID_TMHM_INFO); + u32 accuracy = GetMoveAccuracy(moveId); // Print TMHM accuracy - if (gMovesInfo[moveId].accuracy == 0) + if (accuracy == 0) { text = gText_ThreeDashes; } else { - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[moveId].accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); text = gStringVar1; } BagMenu_Print(WIN_TMHM_INFO, FONT_NORMAL, text, 7, 24, 0, 0, TEXT_SKIP_DRAW, COLORID_TMHM_INFO); // Print TMHM pp - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[moveId].pp, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, GetMovePP(moveId), STR_CONV_MODE_RIGHT_ALIGN, 3); BagMenu_Print(WIN_TMHM_INFO, FONT_NORMAL, gStringVar1, 7, 36, 0, 0, TEXT_SKIP_DRAW, COLORID_TMHM_INFO); CopyWindowToVram(WIN_TMHM_INFO, COPYWIN_GFX); diff --git a/src/link.c b/src/link.c index ef928e8d62b9..501aacad2ca9 100644 --- a/src/link.c +++ b/src/link.c @@ -55,10 +55,7 @@ struct LinkTestBGInfo static struct BlockTransfer sBlockSend; static struct BlockTransfer sBlockRecv[MAX_LINK_PLAYERS]; static u32 sBlockSendDelayCounter; -static bool32 sDummy1; // Never read -static bool8 sDummy2; // Never assigned, read in unused function static u32 sPlayerDataExchangeStatus; -static bool32 sDummy3; // Never read static u8 sLinkTestLastBlockSendPos; static u8 sLinkTestLastBlockRecvPos[MAX_LINK_PLAYERS]; static u8 sNumVBlanksWithoutSerialIntr; @@ -73,15 +70,11 @@ COMMON_DATA u32 gLinkDebugSeed = 0; COMMON_DATA struct LinkPlayerBlock gLocalLinkPlayerBlock = {0}; COMMON_DATA bool8 gLinkErrorOccurred = 0; COMMON_DATA u32 gLinkDebugFlags = 0; -COMMON_DATA u32 gLinkFiller1 = 0; COMMON_DATA bool8 gRemoteLinkPlayersNotReceived[MAX_LINK_PLAYERS] = {0}; COMMON_DATA u8 gBlockReceivedStatus[MAX_LINK_PLAYERS] = {0}; -COMMON_DATA u32 gLinkFiller2 = 0; COMMON_DATA u16 gLinkHeldKeys = 0; COMMON_DATA u16 ALIGNED(4) gRecvCmds[MAX_RFU_PLAYERS][CMD_LENGTH] = {0}; COMMON_DATA u32 gLinkStatus = 0; -COMMON_DATA bool8 gLinkDummy1 = 0; // Never read -COMMON_DATA bool8 gLinkDummy2 = 0; // Never read COMMON_DATA bool8 gReadyToExitStandby[MAX_LINK_PLAYERS] = {0}; COMMON_DATA bool8 gReadyToCloseLink[MAX_LINK_PLAYERS] = {0}; COMMON_DATA u16 gReadyCloseLinkType = 0; // Never read @@ -96,9 +89,6 @@ COMMON_DATA void (*gLinkCallback)(void) = NULL; COMMON_DATA u8 gShouldAdvanceLinkState = 0; COMMON_DATA u16 gLinkTestBlockChecksums[MAX_LINK_PLAYERS] = {0}; COMMON_DATA u8 gBlockRequestType = 0; -COMMON_DATA u32 gLinkFiller3 = 0; -COMMON_DATA u32 gLinkFiller4 = 0; -COMMON_DATA u32 gLinkFiller5 = 0; COMMON_DATA u8 gLastSendQueueCount = 0; COMMON_DATA struct Link gLink = {0}; COMMON_DATA u8 gLastRecvQueueCount = 0; @@ -310,7 +300,6 @@ static void UNUSED LinkTestScreen(void) AnimateSprites(); BuildOamBuffer(); UpdatePaletteFade(); - sDummy3 = FALSE; InitLocalLinkPlayer(); CreateTask(Task_PrintTestData, 0); SetMainCallback2(CB2_LinkTest); @@ -378,9 +367,6 @@ void OpenLink(void) gSuppressLinkErrorMessage = FALSE; ResetBlockReceivedFlags(); ResetBlockSend(); - sDummy1 = FALSE; - gLinkDummy2 = FALSE; - gLinkDummy1 = FALSE; gReadyCloseLinkType = 0; CreateTask(Task_TriggerHandshake, 2); } @@ -552,10 +538,8 @@ static void ProcessRecvCmds(u8 unused) gLinkPartnersHeldKeys[i] = gRecvCmds[i][1]; break; case LINKCMD_DUMMY_1: - gLinkDummy2 = TRUE; break; case LINKCMD_DUMMY_2: - gLinkDummy2 = TRUE; break; case LINKCMD_INIT_BLOCK: { @@ -1376,11 +1360,6 @@ bool8 IsLinkMaster(void) return EXTRACT_MASTER(gLinkStatus); } -static u8 UNUSED GetDummy2(void) -{ - return sDummy2; -} - void SetCloseLinkCallbackAndType(u16 type) { if (gWirelessCommType == TRUE) @@ -1392,7 +1371,6 @@ void SetCloseLinkCallbackAndType(u16 type) if (gLinkCallback == NULL) { gLinkCallback = LinkCB_ReadyCloseLink; - gLinkDummy1 = FALSE; gReadyCloseLinkType = type; } } @@ -1413,7 +1391,6 @@ void SetCloseLinkCallback(void) else { gLinkCallback = LinkCB_ReadyCloseLink; - gLinkDummy1 = FALSE; gReadyCloseLinkType = 0; } } @@ -1449,7 +1426,6 @@ static void LinkCB_WaitCloseLink(void) gLinkVSyncDisabled = TRUE; CloseLink(); gLinkCallback = NULL; - gLinkDummy1 = TRUE; } } @@ -1469,7 +1445,6 @@ void SetCloseLinkCallbackHandleJP(void) else { gLinkCallback = LinkCB_ReadyCloseLinkWithJP; - gLinkDummy1 = FALSE; gReadyCloseLinkType = 0; } } @@ -1511,7 +1486,6 @@ static void LinkCB_WaitCloseLinkWithJP(void) gLinkVSyncDisabled = TRUE; CloseLink(); gLinkCallback = NULL; - gLinkDummy1 = TRUE; } } @@ -1525,8 +1499,6 @@ void SetLinkStandbyCallback(void) { if (gLinkCallback == NULL) gLinkCallback = LinkCB_Standby; - - gLinkDummy1 = FALSE; } } diff --git a/src/m4a.c b/src/m4a.c index e90e9b06f0ac..493577cc23be 100644 --- a/src/m4a.c +++ b/src/m4a.c @@ -6,8 +6,6 @@ extern const u8 gCgb3Vol[]; #define BSS_CODE __attribute__((section(".bss.code"))) -BSS_CODE ALIGNED(4) char SoundMainRAM_Buffer[0x800] = {0}; - COMMON_DATA struct SoundInfo gSoundInfo = {0}; COMMON_DATA struct PokemonCrySong gPokemonCrySongs[MAX_POKEMON_CRIES] = {0}; COMMON_DATA struct MusicPlayerInfo gPokemonCryMusicPlayers[MAX_POKEMON_CRIES] = {0}; @@ -72,8 +70,6 @@ void m4aSoundInit(void) { s32 i; - CpuCopy32((void *)((s32)SoundMainRAM & ~1), SoundMainRAM_Buffer, sizeof(SoundMainRAM_Buffer)); - SoundInit(&gSoundInfo); MPlayExtender(gCgbChans); m4aSoundMode(SOUND_MODE_DA_BIT_8 diff --git a/src/m4a_1.s b/src/m4a_1.s index 20f9197a8dd3..4c0c8f7f897d 100644 --- a/src/m4a_1.s +++ b/src/m4a_1.s @@ -52,11 +52,11 @@ SoundMain_3: cmp r3, 0 beq SoundMain_4 ldr r0, [r0, o_SoundInfo_musicPlayerHead] - bl _081DD25E + bl call_r3 ldr r0, [sp, 0x18] SoundMain_4: ldr r3, [r0, o_SoundInfo_CgbSound] - bl _081DD25E + bl call_r3 ldr r0, [sp, 0x18] ldr r3, [r0, o_SoundInfo_pcmSamplesPerVBlank] mov r8, r3 @@ -73,18 +73,19 @@ SoundMain_4: SoundMain_5: str r5, [sp, 0x8] ldr r6, lt_PCM_DMA_BUF_SIZE - ldr r3, lt_SoundMainRAM_Buffer + ldr r3, lt_SoundMainRAM bx r3 .align 2, 0 lt_SOUND_INFO_PTR: .word SOUND_INFO_PTR lt_ID_NUMBER: .word ID_NUMBER -lt_SoundMainRAM_Buffer: .word SoundMainRAM_Buffer + 1 +lt_SoundMainRAM: .word SoundMainRAM + 1 lt_REG_VCOUNT: .word REG_VCOUNT lt_o_SoundInfo_pcmBuffer: .word o_SoundInfo_pcmBuffer lt_PCM_DMA_BUF_SIZE: .word PCM_DMA_BUF_SIZE thumb_func_end SoundMain + .section .iwram.code thumb_func_start SoundMainRAM SoundMainRAM: ldrb r3, [r0, o_SoundInfo_reverb] @@ -708,6 +709,7 @@ _081DD594: .pool arm_func_end SoundMainRAM_Unk2 + .text thumb_func_start SoundMainBTM SoundMainBTM: mov r12, r4 diff --git a/src/main.c b/src/main.c index 29f02c20e42d..c2758ee227b2 100644 --- a/src/main.c +++ b/src/main.c @@ -69,7 +69,6 @@ COMMON_DATA u16 gKeyRepeatContinueDelay = 0; COMMON_DATA bool8 gSoftResetDisabled = 0; COMMON_DATA IntrFunc gIntrTable[INTR_COUNT] = {0}; COMMON_DATA u8 gLinkVSyncDisabled = 0; -COMMON_DATA u32 IntrMain_Buffer[0x200] = {0}; COMMON_DATA s8 gPcmDmaCounter = 0; COMMON_DATA void *gAgbMainLoop_sp = NULL; @@ -94,7 +93,9 @@ void AgbMain() { *(vu16 *)BG_PLTT = RGB_WHITE; // Set the backdrop to white on startup InitGpuRegManager(); - REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3; + REG_WAITCNT = WAITCNT_PREFETCH_ENABLE + | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3 + | WAITCNT_WS1_S_1 | WAITCNT_WS1_N_3; InitKeys(); InitIntrHandlers(); m4aSoundInit(); @@ -316,9 +317,7 @@ void InitIntrHandlers(void) for (i = 0; i < INTR_COUNT; i++) gIntrTable[i] = gIntrTableTemplate[i]; - DmaCopy32(3, IntrMain, IntrMain_Buffer, sizeof(IntrMain_Buffer)); - - INTR_VECTOR = IntrMain_Buffer; + INTR_VECTOR = IntrMain; SetVBlankCallback(NULL); SetHBlankCallback(NULL); diff --git a/src/menu_specialized.c b/src/menu_specialized.c index 693e9f12bc02..7b6d94b5f23a 100644 --- a/src/menu_specialized.c +++ b/src/menu_specialized.c @@ -10,6 +10,7 @@ #include "international_string_util.h" #include "menu.h" #include "menu_specialized.h" +#include "move.h" #include "move_relearner.h" #include "palette.h" #include "player_pc.h" @@ -752,7 +753,6 @@ u8 LoadMoveRelearnerMovesList(const struct ListMenuItem *items, u16 numChoices) static void MoveRelearnerLoadBattleMoveDescription(u32 chosenMove) { s32 x; - const struct MoveInfo *move; u8 buffer[32]; const u8 *str; @@ -780,49 +780,41 @@ static void MoveRelearnerLoadBattleMoveDescription(u32 chosenMove) CopyWindowToVram(RELEARNERWIN_DESC_BATTLE, COPYWIN_GFX); return; } - move = &gMovesInfo[chosenMove]; - str = gTypesInfo[move->type].name; + str = gTypesInfo[GetMoveType(chosenMove)].name; AddTextPrinterParameterized(RELEARNERWIN_DESC_BATTLE, FONT_NORMAL, str, 4, 25, TEXT_SKIP_DRAW, NULL); x = 4 + GetStringWidth(FONT_NORMAL, gText_MoveRelearnerPP, 0); - ConvertIntToDecimalStringN(buffer, move->pp, STR_CONV_MODE_LEFT_ALIGN, 2); + ConvertIntToDecimalStringN(buffer, GetMovePP(chosenMove), STR_CONV_MODE_LEFT_ALIGN, 2); AddTextPrinterParameterized(RELEARNERWIN_DESC_BATTLE, FONT_NORMAL, buffer, x, 41, TEXT_SKIP_DRAW, NULL); - if (move->power < 2) + if (GetMovePower(chosenMove) < 2) { str = gText_ThreeDashes; } else { - ConvertIntToDecimalStringN(buffer, move->power, STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(buffer, GetMovePower(chosenMove), STR_CONV_MODE_LEFT_ALIGN, 3); str = buffer; } AddTextPrinterParameterized(RELEARNERWIN_DESC_BATTLE, FONT_NORMAL, str, 106, 25, TEXT_SKIP_DRAW, NULL); - if (move->accuracy == 0) + if (GetMoveAccuracy(chosenMove) == 0) { str = gText_ThreeDashes; } else { - ConvertIntToDecimalStringN(buffer, move->accuracy, STR_CONV_MODE_LEFT_ALIGN, 3); + ConvertIntToDecimalStringN(buffer, GetMoveAccuracy(chosenMove), STR_CONV_MODE_LEFT_ALIGN, 3); str = buffer; } AddTextPrinterParameterized(RELEARNERWIN_DESC_BATTLE, FONT_NORMAL, str, 106, 41, TEXT_SKIP_DRAW, NULL); - - if (move->effect != EFFECT_PLACEHOLDER) - str = gMovesInfo[chosenMove].description; - else - str = gNotDoneYetDescription; - - AddTextPrinterParameterized(RELEARNERWIN_DESC_BATTLE, FONT_NARROW, str, 0, 65, 0, NULL); + AddTextPrinterParameterized(RELEARNERWIN_DESC_BATTLE, FONT_NARROW, GetMoveDescription(chosenMove), 0, 65, 0, NULL); } static void MoveRelearnerMenuLoadContestMoveDescription(u32 chosenMove) { s32 x; const u8 *str; - const struct MoveInfo *move; MoveRelearnerShowHideHearts(chosenMove); FillWindowPixelBuffer(RELEARNERWIN_DESC_CONTEST, PIXEL_FILL(1)); @@ -844,11 +836,10 @@ static void MoveRelearnerMenuLoadContestMoveDescription(u32 chosenMove) return; } - move = &gMovesInfo[chosenMove]; - str = gContestMoveTypeTextPointers[move->contestCategory]; + str = gContestMoveTypeTextPointers[GetMoveContestCategory(chosenMove)]; AddTextPrinterParameterized(RELEARNERWIN_DESC_CONTEST, FONT_NORMAL, str, 4, 25, TEXT_SKIP_DRAW, NULL); - str = gContestEffectDescriptionPointers[move->contestEffect]; + str = gContestEffectDescriptionPointers[GetMoveContestEffect(chosenMove)]; AddTextPrinterParameterized(RELEARNERWIN_DESC_CONTEST, FONT_NARROW, str, 0, 65, TEXT_SKIP_DRAW, NULL); CopyWindowToVram(RELEARNERWIN_DESC_CONTEST, COPYWIN_GFX); diff --git a/src/move.c b/src/move.c new file mode 100644 index 000000000000..c77742c30ecb --- /dev/null +++ b/src/move.c @@ -0,0 +1,6 @@ +#include "global.h" +#include "battle.h" +#include "main.h" +#include "move.h" + +#include "data/moves_info.h" diff --git a/src/move_relearner.c b/src/move_relearner.c index 1e6670269501..e312e6256d81 100644 --- a/src/move_relearner.c +++ b/src/move_relearner.c @@ -969,7 +969,7 @@ void MoveRelearnerShowHideHearts(s32 moveId) } else { - numHearts = (u8)(gContestEffects[gMovesInfo[moveId].contestEffect].appeal / 10); + numHearts = (u8)(gContestEffects[GetMoveContestEffect(moveId)].appeal / 10); if (numHearts == 0xFF) numHearts = 0; @@ -983,7 +983,7 @@ void MoveRelearnerShowHideHearts(s32 moveId) gSprites[sMoveRelearnerStruct->heartSpriteIds[i]].invisible = FALSE; } - numHearts = (u8)(gContestEffects[gMovesInfo[moveId].contestEffect].jam / 10); + numHearts = (u8)(gContestEffects[GetMoveContestEffect(moveId)].jam / 10); if (numHearts == 0xFF) numHearts = 0; @@ -1007,7 +1007,6 @@ void MoveRelearnerShowHideCategoryIcon(s32 moveId) DestroySprite(&gSprites[sMoveRelearnerStruct->categoryIconSpriteId]); sMoveRelearnerStruct->categoryIconSpriteId = 0xFF; - gSprites[sMoveRelearnerStruct->categoryIconSpriteId].invisible = TRUE; } else { diff --git a/src/mystery_event_menu.c b/src/mystery_event_menu.c index 79cab2b050a9..67ec7855adef 100644 --- a/src/mystery_event_menu.c +++ b/src/mystery_event_menu.c @@ -28,8 +28,6 @@ enum { static void CB2_MysteryEventMenu(void); static void PrintMysteryMenuText(u8 windowId, const u8 *text, u8 x, u8 y, s32 speed); -static EWRAM_DATA u8 sUnused = 0; // set but unused - static const struct BgTemplate sBgTemplates[] = { { @@ -270,10 +268,7 @@ static void CB2_MysteryEventMenu(void) break; case 13: if (!IsTextPrinterActive(WIN_MSG)) - { gMain.state++; - sUnused = 0; - } break; case 14: if (JOY_NEW(A_BUTTON)) diff --git a/src/new_game.c b/src/new_game.c index 4bce5a5b96a2..bdc020f9dffe 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -44,7 +44,9 @@ #include "berry_powder.h" #include "mystery_gift.h" #include "union_room_chat.h" +#include "constants/map_groups.h" #include "constants/items.h" +#include "difficulty.h" extern const u8 EventScript_ResetAllMapFlags[]; @@ -52,6 +54,7 @@ static void ClearFrontierRecord(void); static void WarpToTruck(void); static void ResetMiniGamesRecords(void); static void ResetItemFlags(void); +static void ResetDexNav(void); EWRAM_DATA bool8 gDifferentSaveFile = FALSE; EWRAM_DATA bool8 gEnableContestDebugging = FALSE; @@ -205,7 +208,9 @@ void NewGameInitData(void) WipeTrainerNameRecords(); ResetTrainerHillResults(); ResetContestLinkResults(); + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); ResetItemFlags(); + ResetDexNav(); } static void ResetMiniGamesRecords(void) @@ -222,3 +227,11 @@ static void ResetItemFlags(void) memset(&gSaveBlock3Ptr->itemFlags, 0, sizeof(gSaveBlock3Ptr->itemFlags)); #endif } + +static void ResetDexNav(void) +{ +#if USE_DEXNAV_SEARCH_LEVELS == TRUE + memset(gSaveBlock3Ptr->dexNavSearchLevels, 0, sizeof(gSaveBlock3Ptr->dexNavSearchLevels)); +#endif + gSaveBlock3Ptr->dexNavChain = 0; +} diff --git a/src/overworld.c b/src/overworld.c index 6bfb49fce90d..05c04d0fbadd 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -6,6 +6,7 @@ #include "bg.h" #include "cable_club.h" #include "clock.h" +#include "dexnav.h" #include "event_data.h" #include "event_object_movement.h" #include "event_scripts.h" @@ -838,6 +839,7 @@ void LoadMapFromCameraTransition(u8 mapGroup, u8 mapNum) LoadObjEventTemplatesFromHeader(); TrySetMapSaveWarpStatus(); ClearTempFieldEventData(); + ResetDexNavSearch(); ResetCyclingRoadChallengeData(); RestartWildEncounterImmunitySteps(); #if FREE_MATCH_CALL == FALSE @@ -902,6 +904,7 @@ static void LoadMapFromWarp(bool32 a1) CheckLeftFriendsSecretBase(); TrySetMapSaveWarpStatus(); ClearTempFieldEventData(); + ResetDexNavSearch(); ResetCyclingRoadChallengeData(); RestartWildEncounterImmunitySteps(); #if FREE_MATCH_CALL == FALSE @@ -3383,6 +3386,9 @@ static u8 ReformatItemDescription(u16 item, u8 *dest) void ScriptShowItemDescription(struct ScriptContext *ctx) { u8 headerType = ScriptReadByte(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + struct WindowTemplate template; u16 item = gSpecialVar_0x8006; u8 textY; @@ -3422,6 +3428,8 @@ void ScriptShowItemDescription(struct ScriptContext *ctx) void ScriptHideItemDescription(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + DestroyItemIconSprite(); if (!GetSetItemObtained(gSpecialVar_0x8006, FLAG_GET_ITEM_OBTAINED)) diff --git a/src/party_menu.c b/src/party_menu.c index 064a0eec16c7..bda62ba3d1fb 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -551,6 +551,9 @@ static void InitPartyMenu(u8 menuType, u8 layout, u8 partyAction, bool8 keepCurs else if (gPartyMenu.slotId > PARTY_SIZE - 1 || GetMonData(&gPlayerParty[gPartyMenu.slotId], MON_DATA_SPECIES) == SPECIES_NONE) gPartyMenu.slotId = 0; + if (gPlayerPartyCount == 0) + gPartyMenu.slotId = PARTY_SIZE + 1; // Cancel + gTextFlags.autoScroll = 0; CalculatePlayerPartyCount(); SetMainCallback2(CB2_InitPartyMenu); @@ -982,7 +985,7 @@ static void RenderPartyMenuBox(u8 slot) PutWindowTilemap(sPartyMenuBoxes[slot].windowId); ScheduleBgCopyTilemapToVram(2); } - else + else if (gPlayerPartyCount != 0) { if (GetMonData(&gPlayerParty[slot], MON_DATA_SPECIES) == SPECIES_NONE) { @@ -1656,7 +1659,7 @@ static u16 PartyMenuButtonHandler(s8 *slotPtr) if (JOY_NEW(START_BUTTON)) return START_BUTTON; - if (movementDir) + if (movementDir && gPlayerPartyCount != 0) { UpdateCurrentPartySelection(slotPtr, movementDir); return 0; @@ -2667,6 +2670,9 @@ void DisplayPartyMenuStdMessage(u32 stringId) stringId = PARTY_MSG_CHOOSE_MON_AND_CONFIRM; else if (!ShouldUseChooseMonText()) stringId = PARTY_MSG_CHOOSE_MON_OR_CANCEL; + + if (gPlayerPartyCount == 0) + stringId = PARTY_MSG_NO_POKEMON; } DrawStdFrameWithCustomTileAndPalette(*windowPtr, FALSE, 0x4F, 13); StringExpandPlaceholders(gStringVar4, sActionStringTable[stringId]); @@ -2735,7 +2741,7 @@ static u8 DisplaySelectionWindow(u8 windowType) const u8 *text; u8 fontColorsId = (sPartyMenuInternal->actions[i] >= MENU_FIELD_MOVES) ? 4 : 3; if (sPartyMenuInternal->actions[i] >= MENU_FIELD_MOVES) - text = gMovesInfo[sFieldMoves[sPartyMenuInternal->actions[i] - MENU_FIELD_MOVES]].name; + text = GetMoveName(sFieldMoves[sPartyMenuInternal->actions[i] - MENU_FIELD_MOVES]); else text = sCursorOptions[sPartyMenuInternal->actions[i]].text; @@ -4259,7 +4265,7 @@ static void ShowOrHideHeldItemSprite(u16 item, struct PartyMenuBox *menuBox) void LoadHeldItemIcons(void) { - LoadSpriteSheet(&sSpriteSheet_HeldItem); + LoadSpriteSheet(&gSpriteSheet_HeldItem); LoadSpritePalette(&sSpritePalette_HeldItem); } @@ -6442,9 +6448,10 @@ static void Task_TryItemUseFormChange(u8 taskId) bool32 TryItemUseFormChange(u8 taskId, TaskFunc task) { struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId]; - u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_ITEM_USE, gSpecialVar_ItemId); + u32 currentSpecies = GetMonData(mon, MON_DATA_SPECIES); + u32 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_ITEM_USE, gSpecialVar_ItemId); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != currentSpecies) { gPartyMenuUseExitCallback = TRUE; SetWordTaskArg(taskId, tNextFunc, (u32)task); @@ -6490,12 +6497,13 @@ void ItemUseCB_RotomCatalog(u8 taskId, TaskFunc task) bool32 TryMultichoiceFormChange(u8 taskId) { struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId]; + u32 currentSpecies = GetMonData(mon, MON_DATA_SPECIES); u32 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_ITEM_USE_MULTICHOICE, gSpecialVar_ItemId); PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[0]); PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != currentSpecies) { gPartyMenuUseExitCallback = TRUE; SetWordTaskArg(taskId, tNextFunc, (u32)Task_ClosePartyMenuAfterText); @@ -6582,8 +6590,9 @@ static void CursorCb_ChangeAbility(u8 taskId) void TryItemHoldFormChange(struct Pokemon *mon) { - u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_ITEM_HOLD, 0); - if (targetSpecies != SPECIES_NONE) + u32 currentSpecies = GetMonData(mon, MON_DATA_SPECIES); + u32 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_ITEM_HOLD, 0); + if (targetSpecies != currentSpecies) { PlayCry_NormalNoDucking(targetSpecies, 0, CRY_VOLUME_RS, CRY_VOLUME_RS); SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); diff --git a/src/pokedex_area_screen.c b/src/pokedex_area_screen.c old mode 100755 new mode 100644 index a3bbafa92632..dd45335afb05 --- a/src/pokedex_area_screen.c +++ b/src/pokedex_area_screen.c @@ -718,11 +718,11 @@ static void ResetPokedexAreaMapBg(void) static void CreateAreaMarkerSprites(void) { u8 spriteId; - static s16 x; - static s16 y; - static s16 i; - static s16 mapSecId; - static s16 numSprites; + s16 x; + s16 y; + s16 i; + s16 mapSecId; + s16 numSprites; LoadSpriteSheet(&sAreaMarkerSpriteSheet); LoadSpritePalette(&sAreaMarkerSpritePalette); diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 8782044769c6..50a00c22b8e6 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -5182,12 +5182,12 @@ static void PrintStatsScreen_Moves_Top(u8 taskId) //Draw move type icon if (gTasks[taskId].data[5] == 0) { - SetTypeIconPosAndPal(gMovesInfo[move].type, moves_x + 146, moves_y + 17, 0); + SetTypeIconPosAndPal(GetMoveType(move), moves_x + 146, moves_y + 17, 0); SetSpriteInvisibility(1, TRUE); } else { - SetTypeIconPosAndPal(NUMBER_OF_MON_TYPES + gMovesInfo[move].contestCategory, moves_x + 146, moves_y + 17, 1); + SetTypeIconPosAndPal(NUMBER_OF_MON_TYPES + GetMoveContestCategory(move), moves_x + 146, moves_y + 17, 1); SetSpriteInvisibility(0, TRUE); } @@ -5243,12 +5243,12 @@ static void PrintStatsScreen_Moves_Description(u8 taskId) //Move description if (gTasks[taskId].data[5] == 0) { - StringCopy(gStringVar4, gMovesInfo[move].description); + StringCopy(gStringVar4, GetMoveDescription(move)); PrintStatsScreenTextSmall(WIN_STATS_MOVES_DESCRIPTION, gStringVar4, moves_x, moves_y); } else { - StringCopy(gStringVar4, gContestEffectDescriptionPointers[gMovesInfo[move].contestEffect]); + StringCopy(gStringVar4, gContestEffectDescriptionPointers[GetMoveContestEffect(move)]); PrintStatsScreenTextSmall(WIN_STATS_MOVES_DESCRIPTION, gStringVar4, moves_x, moves_y); } } @@ -5287,19 +5287,21 @@ static void PrintStatsScreen_Moves_Bottom(u8 taskId) if (gTasks[taskId].data[5] == 0) { //Power - if (gMovesInfo[move].power < 2) + u32 power = GetMovePower(move); + if (power < 2) StringCopy(gStringVar1, gText_ThreeDashes); else - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[move].power, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, power, STR_CONV_MODE_RIGHT_ALIGN, 3); PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar1, moves_x + 45, moves_y); //Physical/Special/Status Category DestroyCategoryIcon(); ShowCategoryIcon(GetBattleMoveCategory(move)); //Accuracy - if (gMovesInfo[move].accuracy == 0) + u32 accuracy = GetMoveAccuracy(move); + if (accuracy == 0) StringCopy(gStringVar1, gText_ThreeDashes); else - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[move].accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar1, moves_x + 114, moves_y); } else //Appeal + Jam @@ -5307,7 +5309,7 @@ static void PrintStatsScreen_Moves_Bottom(u8 taskId) DestroyCategoryIcon(); gSprites[sPokedexView->categoryIconSpriteId].invisible = TRUE; //Appeal - contest_effectValue = gContestEffects[gMovesInfo[move].contestEffect].appeal; + contest_effectValue = gContestEffects[GetMoveContestEffect(move)].appeal; if (contest_effectValue != 0xFF) contest_appeal = contest_effectValue / 10; ConvertIntToDecimalStringN(gStringVar1, contest_appeal, STR_CONV_MODE_RIGHT_ALIGN, 1); @@ -5316,7 +5318,7 @@ static void PrintStatsScreen_Moves_Bottom(u8 taskId) PrintStatsScreenTextSmall(WIN_STATS_MOVES_BOTTOM, gStringVar2, moves_x + 45, moves_y); //Jam - contest_effectValue = gContestEffects[gMovesInfo[move].contestEffect].jam; + contest_effectValue = gContestEffects[GetMoveContestEffect(move)].jam; if (contest_effectValue != 0xFF) contest_jam = contest_effectValue / 10; ConvertIntToDecimalStringN(gStringVar1, contest_jam, STR_CONV_MODE_RIGHT_ALIGN, 1); diff --git a/src/pokemon.c b/src/pokemon.c index 763191d0f08c..3af6c706c99c 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -12,6 +12,7 @@ #include "battle_tower.h" #include "battle_z_move.h" #include "data.h" +#include "dexnav.h" #include "event_data.h" #include "event_object_movement.h" #include "evolution_scene.h" @@ -40,6 +41,7 @@ #include "string_util.h" #include "strings.h" #include "task.h" +#include "test_runner.h" #include "text.h" #include "trainer_hill.h" #include "util.h" @@ -48,6 +50,7 @@ #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" #include "constants/battle_partner.h" +#include "constants/battle_string_ids.h" #include "constants/cries.h" #include "constants/event_objects.h" #include "constants/form_change_types.h" @@ -88,7 +91,6 @@ EWRAM_DATA static struct MonSpritesGfxManager *sMonSpritesGfxManagers[MON_SPR_GF EWRAM_DATA static u8 sTriedEvolving = 0; EWRAM_DATA u16 gFollowerSteps = 0; -#include "data/moves_info.h" #include "data/abilities.h" // Used in an unreferenced function in RS. @@ -1161,6 +1163,8 @@ void CreateBoxMon(struct BoxPokemon *boxMon, u16 species, u8 level, u8 fixedIV, totalRerolls += 1; if (I_FISHING_CHAIN && gIsFishingEncounter) totalRerolls += CalculateChainFishingShinyRolls(); + if (gDexNavBattle) + totalRerolls += CalculateDexNavShinyRolls(); while (GET_SHINY_VALUE(value, personality) >= SHINY_ODDS && totalRerolls > 0) { @@ -1867,8 +1871,9 @@ u16 GiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move) u16 existingMove = GetBoxMonData(boxMon, MON_DATA_MOVE1 + i, NULL); if (existingMove == MOVE_NONE) { + u32 pp = GetMovePP(move); SetBoxMonData(boxMon, MON_DATA_MOVE1 + i, &move); - SetBoxMonData(boxMon, MON_DATA_PP1 + i, &gMovesInfo[move].pp); + SetBoxMonData(boxMon, MON_DATA_PP1 + i, &pp); return move; } if (existingMove == move) @@ -1886,7 +1891,7 @@ u16 GiveMoveToBattleMon(struct BattlePokemon *mon, u16 move) if (mon->moves[i] == MOVE_NONE) { mon->moves[i] = move; - mon->pp[i] = gMovesInfo[move].pp; + mon->pp[i] = GetMovePP(move); return move; } } @@ -1897,7 +1902,8 @@ u16 GiveMoveToBattleMon(struct BattlePokemon *mon, u16 move) void SetMonMoveSlot(struct Pokemon *mon, u16 move, u8 slot) { SetMonData(mon, MON_DATA_MOVE1 + slot, &move); - SetMonData(mon, MON_DATA_PP1 + slot, &gMovesInfo[move].pp); + u32 pp = GetMovePP(move); + SetMonData(mon, MON_DATA_PP1 + slot, &pp); } static void SetMonMoveSlot_KeepPP(struct Pokemon *mon, u16 move, u8 slot) @@ -1914,7 +1920,7 @@ static void SetMonMoveSlot_KeepPP(struct Pokemon *mon, u16 move, u8 slot) void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot) { mon->moves[slot] = move; - mon->pp[slot] = gMovesInfo[move].pp; + mon->pp[slot] = GetMovePP(move); } void GiveMonInitialMoveset(struct Pokemon *mon) @@ -1968,7 +1974,8 @@ void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon) //Credit: AsparagusEdua for (i = 0; i < MAX_MON_MOVES; i++) { SetBoxMonData(boxMon, MON_DATA_MOVE1 + i, &moves[i]); - SetBoxMonData(boxMon, MON_DATA_PP1 + i, &gMovesInfo[moves[i]].pp); + u32 pp = GetMovePP(moves[i]); + SetBoxMonData(boxMon, MON_DATA_PP1 + i, &pp); } } @@ -2021,7 +2028,7 @@ void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move) ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES, NULL); ppBonuses >>= 2; moves[MAX_MON_MOVES - 1] = move; - pp[MAX_MON_MOVES - 1] = gMovesInfo[move].pp; + pp[MAX_MON_MOVES - 1] = GetMovePP(move); for (i = 0; i < MAX_MON_MOVES; i++) { @@ -2048,7 +2055,7 @@ void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move) ppBonuses = GetBoxMonData(boxMon, MON_DATA_PP_BONUSES, NULL); ppBonuses >>= 2; moves[MAX_MON_MOVES - 1] = move; - pp[MAX_MON_MOVES - 1] = gMovesInfo[move].pp; + pp[MAX_MON_MOVES - 1] = GetMovePP(move); for (i = 0; i < MAX_MON_MOVES; i++) { @@ -3067,20 +3074,14 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) SET8(substruct3->metLocation); break; case MON_DATA_MET_LEVEL: - { - u8 metLevel = *data; - substruct3->metLevel = metLevel; + SET8(substruct3->metLevel); break; - } case MON_DATA_MET_GAME: SET8(substruct3->metGame); break; case MON_DATA_POKEBALL: - { - u8 pokeball = *data; - substruct0->pokeball = pokeball; + SET8(substruct0->pokeball); break; - } case MON_DATA_OT_GENDER: SET8(substruct3->otGender); break; @@ -3168,7 +3169,8 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) break; case MON_DATA_IVS: { - u32 ivs = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + u32 ivs; + SET32(ivs); substruct3->hpIV = ivs & MAX_IV_MASK; substruct3->attackIV = (ivs >> 5) & MAX_IV_MASK; substruct3->defenseIV = (ivs >> 10) & MAX_IV_MASK; @@ -3205,12 +3207,8 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) SET8(substruct3->gigantamaxFactor); break; case MON_DATA_TERA_TYPE: - { - u32 teraType; - SET8(teraType); - substruct0->teraType = teraType; + SET8(substruct0->teraType); break; - } case MON_DATA_EVOLUTION_TRACKER: { union EvolutionTracker evoTracker; @@ -3509,7 +3507,8 @@ void CreateSecretBaseEnemyParty(struct SecretBase *secretBaseRecord) for (j = 0; j < MAX_MON_MOVES; j++) { SetMonData(&gEnemyParty[i], MON_DATA_MOVE1 + j, &gBattleResources->secretBase->party.moves[i * MAX_MON_MOVES + j]); - SetMonData(&gEnemyParty[i], MON_DATA_PP1 + j, &gMovesInfo[gBattleResources->secretBase->party.moves[i * MAX_MON_MOVES + j]].pp); + u32 pp = GetMovePP(gBattleResources->secretBase->party.moves[i * MAX_MON_MOVES + j]); + SetMonData(&gEnemyParty[i], MON_DATA_PP1 + j, &pp); } } } @@ -3634,7 +3633,7 @@ const struct FormChange *GetSpeciesFormChanges(u16 species) u8 CalculatePPWithBonus(u16 move, u8 ppBonuses, u8 moveIndex) { - u8 basePP = gMovesInfo[move].pp; + u8 basePP = GetMovePP(move); return basePP + ((basePP * 20 * ((gPPUpGetMask[moveIndex] & ppBonuses) >> (2 * moveIndex))) / 100); } @@ -3706,7 +3705,7 @@ void CopyPartyMonToBattleData(u32 battlerId, u32 partyIndex) PokemonToBattleMon(&party[partyIndex], &gBattleMons[battlerId]); gBattleStruct->hpOnSwitchout[side] = gBattleMons[battlerId].hp; UpdateSentPokesToOpponentValue(battlerId); - ClearTemporarySpeciesSpriteData(battlerId, FALSE); + ClearTemporarySpeciesSpriteData(battlerId, FALSE, FALSE); } bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex) @@ -4012,12 +4011,8 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2)) { dataUnsigned += itemEffect[itemEffectParam]; - moveId = GetMonData(mon, MON_DATA_MOVE1 + temp2, NULL); // Redundant if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2)) - { - moveId = GetMonData(mon, MON_DATA_MOVE1 + temp2, NULL); // Redundant dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), temp2); - } SetMonData(mon, MON_DATA_PP1 + temp2, &dataUnsigned); retVal = FALSE; } @@ -4033,12 +4028,8 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov if (dataUnsigned != CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex)) { dataUnsigned += itemEffect[itemEffectParam++]; - moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); // Redundant if (dataUnsigned > CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex)) - { - moveId = GetMonData(mon, MON_DATA_MOVE1 + moveIndex, NULL); // Redundant dataUnsigned = CalculatePPWithBonus(moveId, GetMonData(mon, MON_DATA_PP_BONUSES, NULL), moveIndex); - } SetMonData(mon, MON_DATA_PP1 + moveIndex, &dataUnsigned); retVal = FALSE; } @@ -4430,7 +4421,7 @@ u8 GetNatureFromPersonality(u32 personality) return personality % NUM_NATURES; } -static u32 GetGMaxTargetSpecies(u32 species) +u32 GetGMaxTargetSpecies(u32 species) { const struct FormChange *formChanges = GetSpeciesFormChanges(species); u32 i; @@ -4439,7 +4430,7 @@ static u32 GetGMaxTargetSpecies(u32 species) if (formChanges[i].method == FORM_CHANGE_BATTLE_GIGANTAMAX) return formChanges[i].targetSpecies; } - return SPECIES_NONE; + return species; } u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 evolutionItem, struct Pokemon *tradePartner) @@ -4617,7 +4608,7 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 { for (j = 0; j < MAX_MON_MOVES; j++) { - if (gMovesInfo[GetMonData(mon, MON_DATA_MOVE1 + j, NULL)].type == evolutions[i].param) + if (GetMoveType(GetMonData(mon, MON_DATA_MOVE1 + j, NULL)) == evolutions[i].param) { targetSpecies = evolutions[i].targetSpecies; break; @@ -4877,8 +4868,8 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 // Gigantamax Factor. We assume that is because their evolutions // do not have a Gigantamax Form. if (GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR, NULL) - && GetGMaxTargetSpecies(species) != SPECIES_NONE - && GetGMaxTargetSpecies(targetSpecies) == SPECIES_NONE) + && GetGMaxTargetSpecies(species) != species + && GetGMaxTargetSpecies(targetSpecies) == targetSpecies) { return SPECIES_NONE; } @@ -5135,12 +5126,15 @@ s32 GetBattlerMultiplayerId(u16 id) u8 GetTrainerEncounterMusicId(u16 trainerOpponentId) { + u32 sanitizedTrainerId = SanitizeTrainerId(trainerOpponentId); + enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); + if (InBattlePyramid()) return GetTrainerEncounterMusicIdInBattlePyramid(trainerOpponentId); else if (InTrainerHillChallenge()) return GetTrainerEncounterMusicIdInTrainerHill(trainerOpponentId); else - return gTrainers[SanitizeTrainerId(trainerOpponentId)].encounterMusic_gender & (F_TRAINER_FEMALE - 1); + return gTrainers[difficulty][sanitizedTrainerId].encounterMusic_gender & (F_TRAINER_FEMALE - 1); } u16 ModifyStatByNature(u8 nature, u16 stat, u8 statIndex) @@ -6080,7 +6074,7 @@ const u8 *GetTrainerPartnerName(void) { if (gPartnerTrainerId == TRAINER_PARTNER(PARTNER_STEVEN)) { - return GetTrainerNameFromId(TRAINER_STEVEN); + return GetTrainerNameFromId(PARTNER_STEVEN); } else { @@ -6301,7 +6295,7 @@ void HandleSetPokedexFlag(u16 nationalNum, u8 caseId, u32 personality) bool8 HasTwoFramesAnimation(u16 species) { - return P_TWO_FRAME_FRONT_SPRITES && species != SPECIES_UNOWN; + return P_TWO_FRAME_FRONT_SPRITES && species != SPECIES_UNOWN && !gTestRunnerHeadless; } static bool8 ShouldSkipFriendshipChange(void) @@ -6518,17 +6512,18 @@ u8 GetFormIdFromFormSpeciesId(u16 formSpeciesId) return targetFormId; } -u16 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg) +// Returns the current species if no form change is possible +u32 GetFormChangeTargetSpecies(struct Pokemon *mon, u16 method, u32 arg) { return GetFormChangeTargetSpeciesBoxMon(&mon->box, method, arg); } -// Returns SPECIES_NONE if no form change is possible -u16 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg) +// Returns the current species if no form change is possible +u32 GetFormChangeTargetSpeciesBoxMon(struct BoxPokemon *boxMon, u16 method, u32 arg) { u32 i; - u16 targetSpecies = SPECIES_NONE; - u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); + u32 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); + u32 targetSpecies = species; const struct FormChange *formChanges = GetSpeciesFormChanges(species); u16 heldItem; u32 ability; @@ -6751,18 +6746,18 @@ bool32 SpeciesHasGenderDifferences(u16 species) bool32 TryFormChange(u32 monId, u32 side, u16 method) { struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; - u16 targetSpecies; if (GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG, 0) == SPECIES_NONE || GetMonData(&party[monId], MON_DATA_SPECIES_OR_EGG, 0) == SPECIES_EGG) return FALSE; - targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); + u32 currentSpecies = GetMonData(&party[monId], MON_DATA_SPECIES); + u32 targetSpecies = GetFormChangeTargetSpecies(&party[monId], method, 0); - if (targetSpecies == SPECIES_NONE && gBattleStruct != NULL) + if (targetSpecies == currentSpecies && gBattleStruct != NULL && gBattleStruct->changedSpecies[side][monId] != SPECIES_NONE) targetSpecies = gBattleStruct->changedSpecies[side][monId]; - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != currentSpecies) { TryToSetBattleFormChangeMoves(&party[monId], method); SetMonData(&party[monId], MON_DATA_SPECIES, &targetSpecies); @@ -6921,7 +6916,7 @@ void HealBoxPokemon(struct BoxPokemon *boxMon) u16 GetCryIdBySpecies(u16 species) { species = SanitizeSpeciesId(species); - if (P_CRIES_ENABLED == FALSE || gSpeciesInfo[species].cryId >= CRY_COUNT) + if (P_CRIES_ENABLED == FALSE || gSpeciesInfo[species].cryId >= CRY_COUNT || gTestRunnerHeadless) return CRY_NONE; return gSpeciesInfo[species].cryId; } @@ -6945,30 +6940,16 @@ u16 GetSpeciesPreEvolution(u16 species) return SPECIES_NONE; } -const u8 *GetMoveName(u16 moveId) -{ - return gMovesInfo[moveId].name; -} - -const u8 *GetMoveAnimationScript(u16 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; -} - void UpdateDaysPassedSinceFormChange(u16 days) { u32 i; for (i = 0; i < PARTY_SIZE; i++) { struct Pokemon *mon = &gPlayerParty[i]; + u32 currentSpecies = GetMonData(mon, MON_DATA_SPECIES); u8 daysSinceFormChange; - if (!GetMonData(mon, MON_DATA_SPECIES, 0)) + if (currentSpecies == SPECIES_NONE) continue; daysSinceFormChange = GetMonData(mon, MON_DATA_DAYS_SINCE_FORM_CHANGE, 0); @@ -6984,9 +6965,9 @@ void UpdateDaysPassedSinceFormChange(u16 days) if (daysSinceFormChange == 0) { - u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_DAYS_PASSED, 0); + u32 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_DAYS_PASSED, 0); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != currentSpecies) { SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); CalculateMonStats(mon); @@ -7000,5 +6981,12 @@ u32 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler) u32 moveType = GetDynamicMoveType(mon, move, battler, NULL); if (moveType != TYPE_NONE) return moveType; - return gMovesInfo[move].type; + return GetMoveType(move); +} + +uq4_12_t GetDynamaxLevelHPMultiplier(u32 dynamaxLevel, bool32 inverseMultiplier) +{ + if (inverseMultiplier) + return UQ_4_12(1.0/(1.5 + 0.05 * dynamaxLevel)); + return UQ_4_12(1.5 + 0.05 * dynamaxLevel); } diff --git a/src/pokemon_animation.c b/src/pokemon_animation.c index d7c0bb343c5e..6bd32ee514b8 100644 --- a/src/pokemon_animation.c +++ b/src/pokemon_animation.c @@ -5,6 +5,7 @@ #include "pokemon_animation.h" #include "sprite.h" #include "task.h" +#include "test_runner.h" #include "trig.h" #include "util.h" #include "data.h" @@ -508,7 +509,10 @@ static void Task_HandleMonAnimation(u8 taskId) for (i = 2; i < ARRAY_COUNT(sprite->data); i++) sprite->data[i] = 0; - sprite->callback = sMonAnimFunctions[gTasks[taskId].tAnimId]; + if (gTestRunnerHeadless) + sprite->callback = WaitAnimEnd; + else + sprite->callback = sMonAnimFunctions[gTasks[taskId].tAnimId]; sIsSummaryAnim = FALSE; gTasks[taskId].tState++; diff --git a/src/pokemon_storage_system.c b/src/pokemon_storage_system.c index e34c4d8e375b..81dff0f435bf 100644 --- a/src/pokemon_storage_system.c +++ b/src/pokemon_storage_system.c @@ -371,35 +371,15 @@ struct StorageMenu int textId; }; -struct UnkUtilData -{ - const u8 *src; - u8 *dest; - u16 size; - u16 unk; - u16 height; - void (*func)(struct UnkUtilData *data); -}; - -struct UnkUtil -{ - struct UnkUtilData *data; - u8 numActive; - u8 max; -}; - struct ChooseBoxMenu { struct Sprite *menuSprite; struct Sprite *menuSideSprites[4]; - u32 unused1[3]; struct Sprite *arrowSprites[2]; - u8 unused2[0x214]; bool32 loadedPalette; u16 tileTag; u16 paletteTag; u8 curBox; - u8 unused3; u8 subpriority; }; @@ -420,12 +400,8 @@ struct PokemonStorageSystemData u8 screenChangeType; bool8 isReopening; u8 taskId; - struct UnkUtil unkUtil; - struct UnkUtilData unkUtilData[8]; u16 partyMenuTilemapBuffer[0x108]; - u16 partyMenuUnused1; // Never read u16 partyMenuY; - u8 partyMenuUnused2; // Unused u8 partyMenuMoveTimer; u8 showPartyMenuState; bool8 closeBoxFlashing; @@ -436,18 +412,8 @@ struct PokemonStorageSystemData s16 scrollSpeed; u16 scrollTimer; u8 wallpaperOffset; - u8 scrollUnused1; // Never read - u8 scrollToBoxIdUnused; // Never read - u16 scrollUnused2; // Never read - s16 scrollDirectionUnused; // Never read. - u16 scrollUnused3; // Never read - u16 scrollUnused4; // Never read - u16 scrollUnused5; // Never read - u16 scrollUnused6; // Never read - u8 filler1[22]; - u8 boxTitleTiles[1024]; + u8 ALIGNED(2) boxTitleTiles[1024]; u8 boxTitleCycleId; - u8 wallpaperLoadState; // Written to, but never read. u8 wallpaperLoadBoxId; s8 wallpaperLoadDir; u16 boxTitlePal[16]; @@ -457,8 +423,6 @@ struct PokemonStorageSystemData struct Sprite *nextBoxTitleSprites[2]; struct Sprite *arrowSprites[2]; u32 wallpaperPalBits; - u8 filler2[80]; // Unused - u16 unkUnused1; // Never read. s16 wallpaperSetId; s16 wallpaperId; u16 wallpaperTilemap[360]; @@ -486,12 +450,10 @@ struct PokemonStorageSystemData u8 iconScrollCurColumn; s8 iconScrollDirection; // Unnecessary duplicate of scrollDirection u8 iconScrollState; - u8 iconScrollToBoxId; // Unused duplicate of scrollToBoxId struct WindowTemplate menuWindow; struct StorageMenu menuItems[7]; u8 menuItemsCount; u8 menuWidth; - u8 menuUnusedField; // Never read. u16 menuWindowId; struct Sprite *cursorSprite; struct Sprite *cursorShadowSprite; @@ -559,7 +521,6 @@ struct PokemonStorageSystemData struct ItemIcon itemIcons[MAX_ITEM_ICONS]; u16 movingItemId; u16 itemInfoWindowOffset; - u8 unkUnused2; // Unused u16 displayMonPalOffset; u16 *displayMonTilePtr; struct Sprite *displayMonSprite; @@ -882,12 +843,6 @@ static void TilemapUtil_Update(u8); static void TilemapUtil_DrawPrev(u8); static void TilemapUtil_Draw(u8); -// Unknown utility -static void UnkUtil_Init(struct UnkUtil *, struct UnkUtilData *, u32); -static void UnkUtil_Run(void); -static void UnkUtil_CpuRun(struct UnkUtilData *); -static void UnkUtil_DmaRun(struct UnkUtilData *); - // Form changing void SetMonFormPSS(struct BoxPokemon *boxMon); void UpdateSpeciesSpritePSS(struct BoxPokemon *boxmon); @@ -2002,7 +1957,6 @@ static void VBlankCB_PokeStorage(void) { LoadOam(); ProcessSpriteCopyRequests(); - UnkUtil_Run(); TransferPlttBuffer(); if (sStorage != NULL) { @@ -2079,7 +2033,6 @@ static void ResetForPokeStorage(void) FreeAllSpritePalettes(); ClearDma3Requests(); gReservedSpriteTileCount = 0x280; - UnkUtil_Init(&sStorage->unkUtil, sStorage->unkUtilData, ARRAY_COUNT(sStorage->unkUtilData)); gKeyRepeatStartDelay = 20; ClearScheduledBgCopiesToVram(); TilemapUtil_Init(TILEMAPID_COUNT); @@ -4116,7 +4069,6 @@ static void InitSupplementalTilemaps(void) static void SetUpShowPartyMenu(void) { - sStorage->partyMenuUnused1 = 20; sStorage->partyMenuY = 2; sStorage->partyMenuMoveTimer = 0; CreatePartyMonsSprites(FALSE); @@ -4127,7 +4079,6 @@ static bool8 ShowPartyMenu(void) if (sStorage->partyMenuMoveTimer == 20) return FALSE; - sStorage->partyMenuUnused1--; sStorage->partyMenuY++; TilemapUtil_Move(TILEMAPID_PARTY_MENU, 3, 1); TilemapUtil_Update(TILEMAPID_PARTY_MENU); @@ -4146,7 +4097,6 @@ static bool8 ShowPartyMenu(void) static void SetUpHidePartyMenu(void) { - sStorage->partyMenuUnused1 = 0; sStorage->partyMenuY = 22; sStorage->partyMenuMoveTimer = 0; if (sStorage->boxOption == OPTION_MOVE_ITEMS) @@ -4157,7 +4107,6 @@ static bool8 HidePartyMenu(void) { if (sStorage->partyMenuMoveTimer != 20) { - sStorage->partyMenuUnused1++; sStorage->partyMenuY--; TilemapUtil_Move(TILEMAPID_PARTY_MENU, 3, -1); TilemapUtil_Update(TILEMAPID_PARTY_MENU); @@ -4465,7 +4414,6 @@ static void InitMonIconFields(void) sStorage->boxMonsSprites[i] = NULL; sStorage->movingMonSprite = NULL; - sStorage->unkUnused1 = 0; } static u8 GetMonIconPriorityByCursorPos(void) @@ -4686,7 +4634,6 @@ static u8 CreateBoxMonIconsInColumn(u8 column, u16 distance, s16 speed) static void InitBoxMonIconScroll(u8 boxId, s8 direction) { sStorage->iconScrollState = 0; - sStorage->iconScrollToBoxId = boxId; sStorage->iconScrollDirection = direction; sStorage->iconScrollDistance = 32; sStorage->iconScrollSpeed = -(6 * direction); @@ -5318,16 +5265,8 @@ static void SetUpScrollToBox(u8 boxId) s8 direction = DetermineBoxScrollDirection(boxId); sStorage->scrollSpeed = (direction > 0) ? 6 : -6; - sStorage->scrollUnused1 = (direction > 0) ? 1 : 2; sStorage->scrollTimer = 32; - sStorage->scrollToBoxIdUnused = boxId; - sStorage->scrollUnused2 = (direction <= 0) ? 5 : 0; - sStorage->scrollDirectionUnused = direction; - - sStorage->scrollUnused3 = (direction > 0) ? 264 : 56; - sStorage->scrollUnused4 = (direction <= 0) ? 5 : 0; - sStorage->scrollUnused5 = 0; - sStorage->scrollUnused6 = 2; + sStorage->scrollToBoxId = boxId; sStorage->scrollDirection = direction; sStorage->scrollState = 0; @@ -5437,7 +5376,6 @@ static void LoadWallpaperGfx(u8 boxId, s8 direction) void *iconGfx; u32 tilesSize, iconSize; - sStorage->wallpaperLoadState = 0; sStorage->wallpaperLoadBoxId = boxId; sStorage->wallpaperLoadDir = direction; if (sStorage->wallpaperLoadDir != 0) @@ -6965,7 +6903,7 @@ static void ReshowDisplayMon(void) void SetMonFormPSS(struct BoxPokemon *boxMon) { u16 targetSpecies = GetFormChangeTargetSpeciesBoxMon(boxMon, FORM_CHANGE_ITEM_HOLD, 0); - if (targetSpecies != SPECIES_NONE) + if (targetSpecies != GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL)) { SetBoxMonData(boxMon, MON_DATA_SPECIES, &targetSpecies); UpdateSpeciesSpritePSS(boxMon); @@ -8133,7 +8071,6 @@ static void AddMenu(void) PrintMenuTable(sStorage->menuWindowId, sStorage->menuItemsCount, (void *)sStorage->menuItems); InitMenuInUpperLeftCornerNormal(sStorage->menuWindowId, sStorage->menuItemsCount, 0); ScheduleBgCopyTilemapToVram(0); - sStorage->menuUnusedField = 0; } // Called after AddMenu to determine whether or not the handler callback should @@ -10103,88 +10040,6 @@ static void TilemapUtil_Draw(u8 id) // so UnkUtil_Run performs no actions. //------------------------------------------------------------------------------ - -EWRAM_DATA static struct UnkUtil *sUnkUtil = NULL; - -static void UnkUtil_Init(struct UnkUtil *util, struct UnkUtilData *data, u32 max) -{ - sUnkUtil = util; - util->data = data; - util->max = max; - util->numActive = 0; -} - -static void UnkUtil_Run(void) -{ - u16 i; - if (sUnkUtil->numActive) - { - for (i = 0; i < sUnkUtil->numActive; i++) - { - struct UnkUtilData *data = &sUnkUtil->data[i]; - data->func(data); - } - sUnkUtil->numActive = 0; - } -} - -static bool8 UNUSED UnkUtil_CpuAdd(u8 *dest, u16 dLeft, u16 dTop, const u8 *src, u16 sLeft, u16 sTop, u16 width, u16 height, u16 unkArg) -{ - struct UnkUtilData *data; - - if (sUnkUtil->numActive >= sUnkUtil->max) - return FALSE; - - data = &sUnkUtil->data[sUnkUtil->numActive++]; - data->size = width * 2; - data->dest = dest + 2 * (dTop * 32 + dLeft); - data->src = src + 2 * (sTop * unkArg + sLeft); - data->height = height; - data->unk = unkArg; - data->func = UnkUtil_CpuRun; - return TRUE; -} - -// Functionally unused -static void UnkUtil_CpuRun(struct UnkUtilData *data) -{ - u16 i; - - for (i = 0; i < data->height; i++) - { - CpuCopy16(data->src, data->dest, data->size); - data->dest += 64; - data->src += data->unk * 2; - } -} - -static bool8 UNUSED UnkUtil_DmaAdd(void *dest, u16 dLeft, u16 dTop, u16 width, u16 height) -{ - struct UnkUtilData *data; - - if (sUnkUtil->numActive >= sUnkUtil->max) - return FALSE; - - data = &sUnkUtil->data[sUnkUtil->numActive++]; - data->size = width * 2; - data->dest = dest + (dTop * 32 + dLeft) * 2; - data->height = height; - data->func = UnkUtil_DmaRun; - return TRUE; -} - -// Functionally unused -static void UnkUtil_DmaRun(struct UnkUtilData *data) -{ - u16 i; - - for (i = 0; i < data->height; i++) - { - Dma3FillLarge16_(0, data->dest, data->size); - data->dest += 64; - } -} - void UpdateSpeciesSpritePSS(struct BoxPokemon *boxMon) { u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES); diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index 4cfc17c707ea..f0c65dc2a753 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -2836,7 +2836,7 @@ static void DrawContestMoveHearts(u16 move) if (move != MOVE_NONE) { // Draw appeal hearts - u8 effectValue = gContestEffects[gMovesInfo[move].contestEffect].appeal; + u8 effectValue = gContestEffects[GetMoveContestEffect(move)].appeal; if (effectValue != 0xFF) effectValue /= 10; @@ -2849,7 +2849,7 @@ static void DrawContestMoveHearts(u16 move) } // Draw jam hearts - effectValue = gContestEffects[gMovesInfo[move].contestEffect].jam; + effectValue = gContestEffects[GetMoveContestEffect(move)].jam; if (effectValue != 0xFF) effectValue /= 10; @@ -3750,29 +3750,31 @@ static void PrintMoveNameAndPP(u8 moveIndex) static void PrintMovePowerAndAccuracy(u16 moveIndex) { const u8 *text; - if (moveIndex != 0) + if (moveIndex != MOVE_NONE) { FillWindowPixelRect(PSS_LABEL_WINDOW_MOVES_POWER_ACC, PIXEL_FILL(0), 53, 0, 19, 32); - if (gMovesInfo[moveIndex].power < 2) + u32 power = GetMovePower(moveIndex); + if (power < 2) { text = gText_ThreeDashes; } else { - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[moveIndex].power, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, power, STR_CONV_MODE_RIGHT_ALIGN, 3); text = gStringVar1; } PrintTextOnWindow(PSS_LABEL_WINDOW_MOVES_POWER_ACC, text, 53, 1, 0, 0); - if (gMovesInfo[moveIndex].accuracy == 0) + u32 accuracy = GetMoveAccuracy(moveIndex); + if (accuracy == 0) { text = gText_ThreeDashes; } else { - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[moveIndex].accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); + ConvertIntToDecimalStringN(gStringVar1, accuracy, STR_CONV_MODE_RIGHT_ALIGN, 3); text = gStringVar1; } @@ -3842,32 +3844,26 @@ static void PrintContestMoveDescription(u8 moveSlot) if (move != MOVE_NONE) { u8 windowId = AddWindowFromTemplateList(sPageMovesTemplate, PSS_DATA_WINDOW_MOVE_DESCRIPTION); - PrintTextOnWindow(windowId, gContestEffectDescriptionPointers[gMovesInfo[move].contestEffect], 6, 1, 0, 0); + PrintTextOnWindow(windowId, gContestEffectDescriptionPointers[GetMoveContestEffect(move)], 6, 1, 0, 0); } } static void PrintMoveDetails(u16 move) { u8 windowId = AddWindowFromTemplateList(sPageMovesTemplate, PSS_DATA_WINDOW_MOVE_DESCRIPTION); - u8 moveEffect; FillWindowPixelBuffer(windowId, PIXEL_FILL(0)); if (move != MOVE_NONE) { if (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES) { - moveEffect = gMovesInfo[move].effect; if (B_SHOW_CATEGORY_ICON == TRUE) ShowCategoryIcon(GetBattleMoveCategory(move)); PrintMovePowerAndAccuracy(move); - - if (moveEffect != EFFECT_PLACEHOLDER) - PrintTextOnWindow(windowId, gMovesInfo[move].description, 6, 1, 0, 0); - else - PrintTextOnWindow(windowId, gNotDoneYetDescription, 6, 1, 0, 0); + PrintTextOnWindow(windowId, GetMoveDescription(move), 6, 1, 0, 0); } else { - PrintTextOnWindow(windowId, gContestEffectDescriptionPointers[gMovesInfo[move].contestEffect], 6, 1, 0, 0); + PrintTextOnWindow(windowId, gContestEffectDescriptionPointers[GetMoveContestEffect(move)], 6, 1, 0, 0); } PutWindowTilemap(windowId); } @@ -3897,7 +3893,7 @@ static void PrintNewMoveDetailsOrCancelText(void) else PrintTextOnWindowToFit(windowId1, GetMoveName(move), 0, 65, 0, 5); - ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[move].pp, STR_CONV_MODE_RIGHT_ALIGN, 2); + ConvertIntToDecimalStringN(gStringVar1, GetMovePP(move), STR_CONV_MODE_RIGHT_ALIGN, 2); DynamicPlaceholderTextUtil_Reset(); DynamicPlaceholderTextUtil_SetPlaceholderPtr(0, gStringVar1); DynamicPlaceholderTextUtil_SetPlaceholderPtr(1, gStringVar1); @@ -4051,7 +4047,7 @@ static void SetMoveTypeIcons(void) { if (summary->moves[i] != MOVE_NONE) { - type = gMovesInfo[summary->moves[i]].type; + type = GetMoveType(summary->moves[i]); if (P_SHOW_DYNAMIC_TYPES) type = CheckDynamicMoveType(mon, summary->moves[i], 0); SetTypeSpritePosAndPal(type, 85, 32 + (i * 16), i + SPRITE_ARR_ID_TYPE); @@ -4070,7 +4066,7 @@ static void SetContestMoveTypeIcons(void) for (i = 0; i < MAX_MON_MOVES; i++) { if (summary->moves[i] != MOVE_NONE) - SetTypeSpritePosAndPal(NUMBER_OF_MON_TYPES + gMovesInfo[summary->moves[i]].contestCategory, 85, 32 + (i * 16), i + SPRITE_ARR_ID_TYPE); + SetTypeSpritePosAndPal(NUMBER_OF_MON_TYPES + GetMoveContestCategory(summary->moves[i]), 85, 32 + (i * 16), i + SPRITE_ARR_ID_TYPE); else SetSpriteInvisibility(i + SPRITE_ARR_ID_TYPE, TRUE); } @@ -4078,7 +4074,7 @@ static void SetContestMoveTypeIcons(void) static void SetNewMoveTypeIcon(void) { - u32 type = gMovesInfo[sMonSummaryScreen->newMove].type; + u32 type = GetMoveType(sMonSummaryScreen->newMove); struct Pokemon *mon = &sMonSummaryScreen->currentMon; if (P_SHOW_DYNAMIC_TYPES) @@ -4096,7 +4092,7 @@ static void SetNewMoveTypeIcon(void) } else { - SetTypeSpritePosAndPal(NUMBER_OF_MON_TYPES + gMovesInfo[sMonSummaryScreen->newMove].contestCategory, 85, 96, SPRITE_ARR_ID_TYPE + 4); + SetTypeSpritePosAndPal(NUMBER_OF_MON_TYPES + GetMoveContestCategory(sMonSummaryScreen->newMove), 85, 96, SPRITE_ARR_ID_TYPE + 4); } } } diff --git a/src/pokenav_main_menu.c b/src/pokenav_main_menu.c index dfd656833de3..4c4777e5d523 100644 --- a/src/pokenav_main_menu.c +++ b/src/pokenav_main_menu.c @@ -86,18 +86,20 @@ static const struct WindowTemplate sHelpBarWindowTemplate[] = static const u8 *const sHelpBarTexts[HELPBAR_COUNT] = { - [HELPBAR_NONE] = COMPOUND_STRING("{CLEAR 0x80}"), - [HELPBAR_MAP_ZOOMED_OUT] = COMPOUND_STRING("{A_BUTTON}ZOOM {B_BUTTON}CANCEL"), - [HELPBAR_MAP_ZOOMED_IN] = COMPOUND_STRING("{A_BUTTON}FULL {B_BUTTON}CANCEL"), - [HELPBAR_CONDITION_MON_LIST] = COMPOUND_STRING("{A_BUTTON}CONDITION {B_BUTTON}CANCEL"), - [HELPBAR_CONDITION_MON_STATUS] = COMPOUND_STRING("{A_BUTTON}MARKINGS {B_BUTTON}CANCEL"), - [HELPBAR_CONDITION_MARKINGS] = COMPOUND_STRING("{A_BUTTON}SELECT MARK {B_BUTTON}CANCEL"), - [HELPBAR_MC_TRAINER_LIST] = COMPOUND_STRING("{A_BUTTON}MENU {B_BUTTON}CANCEL"), - [HELPBAR_MC_CALL_MENU] = COMPOUND_STRING("{A_BUTTON}OK {B_BUTTON}CANCEL"), - [HELPBAR_MC_CHECK_PAGE] = COMPOUND_STRING("{B_BUTTON}CANCEL"), - [HELPBAR_RIBBONS_MON_LIST] = COMPOUND_STRING("{A_BUTTON}RIBBONS {B_BUTTON}CANCEL"), - [HELPBAR_RIBBONS_LIST] = COMPOUND_STRING("{A_BUTTON}CHECK {B_BUTTON}CANCEL"), - [HELPBAR_RIBBONS_CHECK] = COMPOUND_STRING("{B_BUTTON}CANCEL"), + [HELPBAR_NONE] = COMPOUND_STRING("{CLEAR 0x80}"), + [HELPBAR_MAP_ZOOMED_OUT] = COMPOUND_STRING("{A_BUTTON}ZOOM {B_BUTTON}CANCEL"), + [HELPBAR_MAP_ZOOMED_IN] = COMPOUND_STRING("{A_BUTTON}FULL {B_BUTTON}CANCEL"), + [HELPBAR_MAP_ZOOMED_OUT_CANFLY] = COMPOUND_STRING("{A_BUTTON}ZOOM {B_BUTTON}CANCEL {R_BUTTON}FLY"), + [HELPBAR_MAP_ZOOMED_IN_CANFLY] = COMPOUND_STRING("{A_BUTTON}FULL {B_BUTTON}CANCEL {R_BUTTON}FLY"), + [HELPBAR_CONDITION_MON_LIST] = COMPOUND_STRING("{A_BUTTON}CONDITION {B_BUTTON}CANCEL"), + [HELPBAR_CONDITION_MON_STATUS] = COMPOUND_STRING("{A_BUTTON}MARKINGS {B_BUTTON}CANCEL"), + [HELPBAR_CONDITION_MARKINGS] = COMPOUND_STRING("{A_BUTTON}SELECT MARK {B_BUTTON}CANCEL"), + [HELPBAR_MC_TRAINER_LIST] = COMPOUND_STRING("{A_BUTTON}MENU {B_BUTTON}CANCEL"), + [HELPBAR_MC_CALL_MENU] = COMPOUND_STRING("{A_BUTTON}OK {B_BUTTON}CANCEL"), + [HELPBAR_MC_CHECK_PAGE] = COMPOUND_STRING("{B_BUTTON}CANCEL"), + [HELPBAR_RIBBONS_MON_LIST] = COMPOUND_STRING("{A_BUTTON}RIBBONS {B_BUTTON}CANCEL"), + [HELPBAR_RIBBONS_LIST] = COMPOUND_STRING("{A_BUTTON}CHECK {B_BUTTON}CANCEL"), + [HELPBAR_RIBBONS_CHECK] = COMPOUND_STRING("{B_BUTTON}CANCEL"), }; static const u8 sHelpBarTextColors[3] = diff --git a/src/pokenav_region_map.c b/src/pokenav_region_map.c index f81ff4296639..b17689aad8b6 100755 --- a/src/pokenav_region_map.c +++ b/src/pokenav_region_map.c @@ -2,8 +2,11 @@ #include "bg.h" #include "decompress.h" #include "landmark.h" +#include "event_data.h" +#include "field_effect.h" #include "main.h" #include "menu.h" +#include "overworld.h" #include "palette.h" #include "pokenav.h" #include "region_map.h" @@ -73,6 +76,7 @@ static u32 LoopedTask_UpdateInfoAfterCursorMove(s32); static u32 LoopedTask_RegionMapZoomOut(s32); static u32 LoopedTask_RegionMapZoomIn(s32); static u32 LoopedTask_ExitRegionMap(s32); +static u32 LoopedTask_TreatAsPokeNavFlyMap(s32); extern const u16 gRegionMapCityZoomTiles_Pal[]; extern const u32 gRegionMapCityZoomText_Gfx[]; @@ -119,7 +123,8 @@ static const LoopedTask sRegionMapLoopTaskFuncs[] = [POKENAV_MAP_FUNC_CURSOR_MOVED] = LoopedTask_UpdateInfoAfterCursorMove, [POKENAV_MAP_FUNC_ZOOM_OUT] = LoopedTask_RegionMapZoomOut, [POKENAV_MAP_FUNC_ZOOM_IN] = LoopedTask_RegionMapZoomIn, - [POKENAV_MAP_FUNC_EXIT] = LoopedTask_ExitRegionMap + [POKENAV_MAP_FUNC_EXIT] = LoopedTask_ExitRegionMap, + [POKENAV_MAP_FUNC_FLY] = LoopedTask_TreatAsPokeNavFlyMap, }; static const struct CompressedSpriteSheet sCityZoomTextSpriteSheet[1] = @@ -204,6 +209,8 @@ u32 GetRegionMapCallback(void) static u32 HandleRegionMapInput(struct Pokenav_RegionMapMenu *state) { + struct RegionMap* regionMap = GetSubstructPtr(POKENAV_SUBSTRUCT_REGION_MAP); + switch (DoRegionMapInputCallback()) { case MAP_INPUT_MOVE_END: @@ -215,6 +222,10 @@ static u32 HandleRegionMapInput(struct Pokenav_RegionMapMenu *state) case MAP_INPUT_B_BUTTON: state->callback = GetExitRegionMapMenuId; return POKENAV_MAP_FUNC_EXIT; + case MAP_INPUT_R_BUTTON: + if (regionMap->mapSecType == MAPSECTYPE_CITY_CANFLY && FlagGet(OW_FLAG_POKE_RIDER) + && Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE) + return POKENAV_MAP_FUNC_FLY; } return POKENAV_MAP_FUNC_NONE; @@ -365,6 +376,7 @@ static u32 LoopedTask_OpenRegionMap(s32 taskState) else menuGfxId = POKENAV_GFX_MAP_MENU_ZOOMED_IN; + UpdateRegionMapHelpBarText(); LoadLeftHeaderGfxForIndex(menuGfxId); ShowLeftHeaderGfx(menuGfxId, TRUE, TRUE); PokenavFadeScreen(POKENAV_FADE_FROM_BLACK); @@ -385,6 +397,7 @@ static u32 LoopedTask_UpdateInfoAfterCursorMove(s32 taskState) { case 0: UpdateMapSecInfoWindow(state); + UpdateRegionMapHelpBarText(); return LT_INC_AND_PAUSE; case 1: if (IsDma3ManagerBusyWithBgCopy_(state)) @@ -408,7 +421,7 @@ static u32 LoopedTask_RegionMapZoomOut(s32 taskState) if (UpdateRegionMapZoom() || IsChangeBgYForZoomActive()) return LT_PAUSE; - PrintHelpBarText(HELPBAR_MAP_ZOOMED_OUT); + UpdateRegionMapHelpBarText(); return LT_INC_AND_PAUSE; case 2: if (WaitForHelpBar()) @@ -441,7 +454,7 @@ static u32 LoopedTask_RegionMapZoomIn(s32 taskState) if (UpdateRegionMapZoom() || IsChangeBgYForZoomActive()) return LT_PAUSE; - PrintHelpBarText(HELPBAR_MAP_ZOOMED_IN); + UpdateRegionMapHelpBarText(); return LT_INC_AND_PAUSE; case 3: if (WaitForHelpBar()) @@ -482,6 +495,23 @@ static u32 LoopedTask_ExitRegionMap(s32 taskState) return LT_FINISH; } +static u32 LoopedTask_TreatAsPokeNavFlyMap(s32 taskState) +{ + switch (taskState) + { + case 0: + PlaySE(SE_SELECT); + struct RegionMap* regionMap = GetSubstructPtr(POKENAV_SUBSTRUCT_REGION_MAP); + SetFlyDestination(regionMap); + gSkipShowMonAnim = TRUE; + ReturnToFieldFromFlyMapSelect(); + + return LT_FINISH; + } + + return LT_FINISH; +} + static void LoadCityZoomViewGfx(void) { int i; @@ -740,3 +770,24 @@ static void SetCityZoomTextInvisibility(bool32 invisible) for (i = 0; i < (int)ARRAY_COUNT(state->cityZoomTextSprites); i++) state->cityZoomTextSprites[i]->invisible = invisible; } + +void UpdateRegionMapHelpBarText(void) +{ + struct RegionMap* regionMap = GetSubstructPtr(POKENAV_SUBSTRUCT_REGION_MAP); + + if (regionMap->mapSecType == MAPSECTYPE_CITY_CANFLY && FlagGet(OW_FLAG_POKE_RIDER) + && Overworld_MapTypeAllowsTeleportAndFly(gMapHeader.mapType) == TRUE) + { + if (IsRegionMapZoomed()) + PrintHelpBarText(HELPBAR_MAP_ZOOMED_IN_CANFLY); + else + PrintHelpBarText(HELPBAR_MAP_ZOOMED_OUT_CANFLY); + } + else + { + if (IsRegionMapZoomed()) + PrintHelpBarText(HELPBAR_MAP_ZOOMED_IN); + else + PrintHelpBarText(HELPBAR_MAP_ZOOMED_OUT); + } +} diff --git a/src/region_map.c b/src/region_map.c index 92771c822073..aba1162f5b91 100644 --- a/src/region_map.c +++ b/src/region_map.c @@ -680,6 +680,10 @@ static u8 ProcessRegionMapInput_Full(void) { input = MAP_INPUT_B_BUTTON; } + else if (JOY_NEW(R_BUTTON)) + { + input = MAP_INPUT_R_BUTTON; + } if (input == MAP_INPUT_MOVE_START) { sRegionMap->cursorMovementFrameCounter = 4; @@ -759,6 +763,10 @@ static u8 ProcessRegionMapInput_Zoomed(void) { input = MAP_INPUT_B_BUTTON; } + else if (JOY_NEW(R_BUTTON)) + { + input = MAP_INPUT_R_BUTTON; + } if (input == MAP_INPUT_MOVE_START) { sRegionMap->inputCallback = MoveRegionMapCursor_Zoomed; @@ -1992,27 +2000,9 @@ static void CB_ExitFlyMap(void) FreeRegionMapIconResources(); if (sFlyMap->choseFlyLocation) { - switch (sFlyMap->regionMap.mapSecId) - { - case MAPSEC_SOUTHERN_ISLAND: - SetWarpDestinationToHealLocation(HEAL_LOCATION_SOUTHERN_ISLAND_EXTERIOR); - break; - case MAPSEC_BATTLE_FRONTIER: - SetWarpDestinationToHealLocation(HEAL_LOCATION_BATTLE_FRONTIER_OUTSIDE_EAST); - break; - case MAPSEC_LITTLEROOT_TOWN: - SetWarpDestinationToHealLocation(gSaveBlock2Ptr->playerGender == MALE ? HEAL_LOCATION_LITTLEROOT_TOWN_BRENDANS_HOUSE : HEAL_LOCATION_LITTLEROOT_TOWN_MAYS_HOUSE); - break; - case MAPSEC_EVER_GRANDE_CITY: - SetWarpDestinationToHealLocation(FlagGet(FLAG_LANDMARK_POKEMON_LEAGUE) && sFlyMap->regionMap.posWithinMapSec == 0 ? HEAL_LOCATION_EVER_GRANDE_CITY_POKEMON_LEAGUE : HEAL_LOCATION_EVER_GRANDE_CITY); - break; - default: - if (sMapHealLocations[sFlyMap->regionMap.mapSecId][2] != HEAL_LOCATION_NONE) - SetWarpDestinationToHealLocation(sMapHealLocations[sFlyMap->regionMap.mapSecId][2]); - else - SetWarpDestinationToMapWarp(sMapHealLocations[sFlyMap->regionMap.mapSecId][0], sMapHealLocations[sFlyMap->regionMap.mapSecId][1], WARP_ID_NONE); - break; - } + struct RegionMap* tempRegionMap = &sFlyMap->regionMap; + + SetFlyDestination(tempRegionMap); ReturnToFieldFromFlyMapSelect(); } else @@ -2025,3 +2015,33 @@ static void CB_ExitFlyMap(void) break; } } + +u32 FilterFlyDestination(struct RegionMap* regionMap) +{ + switch (regionMap->mapSecId) + { + case MAPSEC_SOUTHERN_ISLAND: + return HEAL_LOCATION_SOUTHERN_ISLAND_EXTERIOR; + case MAPSEC_BATTLE_FRONTIER: + return HEAL_LOCATION_BATTLE_FRONTIER_OUTSIDE_EAST; + case MAPSEC_LITTLEROOT_TOWN: + return (gSaveBlock2Ptr->playerGender == MALE ? HEAL_LOCATION_LITTLEROOT_TOWN_BRENDANS_HOUSE : HEAL_LOCATION_LITTLEROOT_TOWN_MAYS_HOUSE); + case MAPSEC_EVER_GRANDE_CITY: + return (FlagGet(FLAG_LANDMARK_POKEMON_LEAGUE) && regionMap->posWithinMapSec == 0 ? HEAL_LOCATION_EVER_GRANDE_CITY_POKEMON_LEAGUE : HEAL_LOCATION_EVER_GRANDE_CITY); + default: + if (sMapHealLocations[regionMap->mapSecId][2] != HEAL_LOCATION_NONE) + return sMapHealLocations[regionMap->mapSecId][2]; + else + return WARP_ID_NONE; + } +} + +void SetFlyDestination(struct RegionMap* regionMap) +{ + u32 flyDestination = FilterFlyDestination(regionMap); + + if (flyDestination != WARP_ID_NONE) + SetWarpDestinationToHealLocation(flyDestination); + else + SetWarpDestinationToMapWarp(sMapHealLocations[regionMap->mapSecId][0], sMapHealLocations[regionMap->mapSecId][1], WARP_ID_NONE); +} diff --git a/src/rom_header_gf.c b/src/rom_header_gf.c index 1074a86bf883..c55535003c27 100644 --- a/src/rom_header_gf.c +++ b/src/rom_header_gf.c @@ -1,10 +1,11 @@ #include "global.h" +#include "battle_main.h" #include "data.h" -#include "pokemon_icon.h" #include "decoration.h" -#include "battle_main.h" #include "item.h" +#include "move.h" #include "pokeball.h" +#include "pokemon_icon.h" // The purpose of this struct is for outside applications to be // able to access parts of the ROM or its save file, like a public API. diff --git a/src/scanline_effect.c b/src/scanline_effect.c index 684c89546a93..ce9bf190ab4c 100644 --- a/src/scanline_effect.c +++ b/src/scanline_effect.c @@ -38,8 +38,6 @@ void ScanlineEffect_Clear(void) gScanlineEffect.dmaControl = 0; gScanlineEffect.srcBuffer = 0; gScanlineEffect.state = 0; - gScanlineEffect.unused16 = 0; - gScanlineEffect.unused17 = 0; gScanlineEffect.waveTaskId = TASK_NONE; } @@ -65,8 +63,6 @@ void ScanlineEffect_SetParams(struct ScanlineEffectParams params) gScanlineEffect.dmaControl = params.dmaControl; gScanlineEffect.dmaDest = params.dmaDest; gScanlineEffect.state = params.initState; - gScanlineEffect.unused16 = params.unused9; - gScanlineEffect.unused17 = params.unused9; } void ScanlineEffect_InitHBlankDmaTransfer(void) diff --git a/src/scrcmd.c b/src/scrcmd.c index 399562f9a054..cf65ad270d77 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -29,6 +29,7 @@ #include "main.h" #include "menu.h" #include "money.h" +#include "move.h" #include "mystery_event_script.h" #include "palette.h" #include "party_menu.h" @@ -100,16 +101,22 @@ static u8 *const sScriptStringVars[] = bool8 ScrCmd_nop(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + return FALSE; } bool8 ScrCmd_nop1(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + return FALSE; } bool8 ScrCmd_end(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + FlagClear(FLAG_SAFE_FOLLOWER_MOVEMENT); StopScript(ctx); return FALSE; @@ -119,6 +126,9 @@ bool8 ScrCmd_gotonative(struct ScriptContext *ctx) { bool8 (*addr)(void) = (bool8 (*)(void))ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + Script_CheckEffectInstrumentedGotoNative(addr); + SetupNativeScript(ctx, addr); return TRUE; } @@ -127,15 +137,24 @@ bool8 ScrCmd_special(struct ScriptContext *ctx) { u16 index = ScriptReadHalfword(ctx); + Script_RequestEffects(SCREFF_V1); + Script_CheckEffectInstrumentedSpecial(index); + gSpecials[index](); return FALSE; } bool8 ScrCmd_specialvar(struct ScriptContext *ctx) { - u16 *var = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 index = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + Script_CheckEffectInstrumentedSpecial(index); - *var = gSpecials[ScriptReadHalfword(ctx)](); + *ptr = gSpecials[index](); return FALSE; } @@ -143,12 +162,17 @@ bool8 ScrCmd_callnative(struct ScriptContext *ctx) { NativeFunc func = (NativeFunc)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + Script_CheckEffectInstrumentedCallNative(func); + func(ctx); return FALSE; } bool8 ScrCmd_waitstate(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ScriptContext_Stop(); return TRUE; } @@ -157,12 +181,16 @@ bool8 ScrCmd_goto(struct ScriptContext *ctx) { const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + ScriptJump(ctx, ptr); return FALSE; } bool8 ScrCmd_return(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + ScriptReturn(ctx); return FALSE; } @@ -171,6 +199,8 @@ bool8 ScrCmd_call(struct ScriptContext *ctx) { const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + ScriptCall(ctx, ptr); return FALSE; } @@ -180,6 +210,8 @@ bool8 ScrCmd_goto_if(struct ScriptContext *ctx) u8 condition = ScriptReadByte(ctx); const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) ScriptJump(ctx, ptr); return FALSE; @@ -190,6 +222,8 @@ bool8 ScrCmd_call_if(struct ScriptContext *ctx) u8 condition = ScriptReadByte(ctx); const u8 *ptr = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) ScriptCall(ctx, ptr); return FALSE; @@ -200,6 +234,8 @@ bool8 ScrCmd_setvaddress(struct ScriptContext *ctx) u32 addr1 = (u32)ctx->scriptPtr - 1; u32 addr2 = ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + sAddressOffset = addr2 - addr1; return FALSE; } @@ -208,6 +244,8 @@ bool8 ScrCmd_vgoto(struct ScriptContext *ctx) { u32 addr = ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + ScriptJump(ctx, (u8 *)(addr - sAddressOffset)); return FALSE; } @@ -216,6 +254,8 @@ bool8 ScrCmd_vcall(struct ScriptContext *ctx) { u32 addr = ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + ScriptCall(ctx, (u8 *)(addr - sAddressOffset)); return FALSE; } @@ -225,6 +265,8 @@ bool8 ScrCmd_vgoto_if(struct ScriptContext *ctx) u8 condition = ScriptReadByte(ctx); const u8 *ptr = (const u8 *)(ScriptReadWord(ctx) - sAddressOffset); + Script_RequestEffects(SCREFF_V1); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) ScriptJump(ctx, ptr); return FALSE; @@ -235,6 +277,8 @@ bool8 ScrCmd_vcall_if(struct ScriptContext *ctx) u8 condition = ScriptReadByte(ctx); const u8 *ptr = (const u8 *)(ScriptReadWord(ctx) - sAddressOffset); + Script_RequestEffects(SCREFF_V1); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) ScriptCall(ctx, ptr); return FALSE; @@ -245,6 +289,8 @@ bool8 ScrCmd_gotostd(struct ScriptContext *ctx) u8 index = ScriptReadByte(ctx); const u8 **ptr = &gStdScripts[index]; + Script_RequestEffects(SCREFF_V1); + if (ptr < gStdScripts_End) ScriptJump(ctx, *ptr); return FALSE; @@ -255,6 +301,8 @@ bool8 ScrCmd_callstd(struct ScriptContext *ctx) u8 index = ScriptReadByte(ctx); const u8 **ptr = &gStdScripts[index]; + Script_RequestEffects(SCREFF_V1); + if (ptr < gStdScripts_End) ScriptCall(ctx, *ptr); return FALSE; @@ -265,6 +313,8 @@ bool8 ScrCmd_gotostd_if(struct ScriptContext *ctx) u8 condition = ScriptReadByte(ctx); u8 index = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) { const u8 **ptr = &gStdScripts[index]; @@ -279,6 +329,8 @@ bool8 ScrCmd_callstd_if(struct ScriptContext *ctx) u8 condition = ScriptReadByte(ctx); u8 index = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + if (sScriptConditionTable[condition][ctx->comparisonResult] == 1) { const u8 **ptr = &gStdScripts[index]; @@ -290,12 +342,16 @@ bool8 ScrCmd_callstd_if(struct ScriptContext *ctx) bool8 ScrCmd_returnram(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + ScriptJump(ctx, gRamScriptRetAddr); return FALSE; } bool8 ScrCmd_endram(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + FlagClear(FLAG_SAFE_FOLLOWER_MOVEMENT); ClearRamScript(); StopScript(ctx); @@ -306,6 +362,8 @@ bool8 ScrCmd_setmysteryeventstatus(struct ScriptContext *ctx) { u8 status = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + SetMysteryEventScriptStatus(status); return FALSE; } @@ -314,6 +372,8 @@ bool8 ScrCmd_loadword(struct ScriptContext *ctx) { u8 index = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->data[index] = ScriptReadWord(ctx); return FALSE; } @@ -322,6 +382,8 @@ bool8 ScrCmd_loadbytefromptr(struct ScriptContext *ctx) { u8 index = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->data[index] = *(const u8 *)ScriptReadWord(ctx); return FALSE; } @@ -330,6 +392,9 @@ bool8 ScrCmd_setptr(struct ScriptContext *ctx) { u8 value = ScriptReadByte(ctx); + // TODO: Check if 'ptr' is within a save block? + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + *(u8 *)ScriptReadWord(ctx) = value; return FALSE; } @@ -338,6 +403,8 @@ bool8 ScrCmd_loadbyte(struct ScriptContext *ctx) { u8 index = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->data[index] = ScriptReadByte(ctx); return FALSE; } @@ -346,6 +413,9 @@ bool8 ScrCmd_setptrbyte(struct ScriptContext *ctx) { u8 index = ScriptReadByte(ctx); + // TODO: Check if 'ptr' is within a save block? + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + *(u8 *)ScriptReadWord(ctx) = ctx->data[index]; return FALSE; } @@ -355,6 +425,8 @@ bool8 ScrCmd_copylocal(struct ScriptContext *ctx) u8 destIndex = ScriptReadByte(ctx); u8 srcIndex = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->data[destIndex] = ctx->data[srcIndex]; return FALSE; } @@ -362,27 +434,46 @@ bool8 ScrCmd_copylocal(struct ScriptContext *ctx) bool8 ScrCmd_copybyte(struct ScriptContext *ctx) { u8 *ptr = (u8 *)ScriptReadWord(ctx); + + // TODO: Check if 'ptr' is within a save block? + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + *ptr = *(const u8 *)ScriptReadWord(ctx); return FALSE; } bool8 ScrCmd_setvar(struct ScriptContext *ctx) { - u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + *ptr = ScriptReadHalfword(ctx); return FALSE; } bool8 ScrCmd_copyvar(struct ScriptContext *ctx) { - u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + *ptr = *GetVarPointer(ScriptReadHalfword(ctx)); return FALSE; } bool8 ScrCmd_setorcopyvar(struct ScriptContext *ctx) { - u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + *ptr = VarGet(ScriptReadHalfword(ctx)); return FALSE; } @@ -401,6 +492,8 @@ bool8 ScrCmd_compare_local_to_local(struct ScriptContext *ctx) const u8 value1 = ctx->data[ScriptReadByte(ctx)]; const u8 value2 = ctx->data[ScriptReadByte(ctx)]; + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -410,6 +503,8 @@ bool8 ScrCmd_compare_local_to_value(struct ScriptContext *ctx) const u8 value1 = ctx->data[ScriptReadByte(ctx)]; const u8 value2 = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -419,6 +514,8 @@ bool8 ScrCmd_compare_local_to_ptr(struct ScriptContext *ctx) const u8 value1 = ctx->data[ScriptReadByte(ctx)]; const u8 value2 = *(const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -428,6 +525,8 @@ bool8 ScrCmd_compare_ptr_to_local(struct ScriptContext *ctx) const u8 value1 = *(const u8 *)ScriptReadWord(ctx); const u8 value2 = ctx->data[ScriptReadByte(ctx)]; + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -437,6 +536,8 @@ bool8 ScrCmd_compare_ptr_to_value(struct ScriptContext *ctx) const u8 value1 = *(const u8 *)ScriptReadWord(ctx); const u8 value2 = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -446,6 +547,8 @@ bool8 ScrCmd_compare_ptr_to_ptr(struct ScriptContext *ctx) const u8 value1 = *(const u8 *)ScriptReadWord(ctx); const u8 value2 = *(const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -455,6 +558,8 @@ bool8 ScrCmd_compare_var_to_value(struct ScriptContext *ctx) const u16 value1 = *GetVarPointer(ScriptReadHalfword(ctx)); const u16 value2 = ScriptReadHalfword(ctx); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(value1, value2); return FALSE; } @@ -464,6 +569,8 @@ bool8 ScrCmd_compare_var_to_var(struct ScriptContext *ctx) const u16 *ptr1 = GetVarPointer(ScriptReadHalfword(ctx)); const u16 *ptr2 = GetVarPointer(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = Compare(*ptr1, *ptr2); return FALSE; } @@ -473,14 +580,24 @@ bool8 ScrCmd_compare_var_to_var(struct ScriptContext *ctx) // in the contest scripts to `subvar VAR_*, 1`, else contests will break. bool8 ScrCmd_addvar(struct ScriptContext *ctx) { - u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + *ptr += ScriptReadHalfword(ctx); return FALSE; } bool8 ScrCmd_subvar(struct ScriptContext *ctx) { - u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + *ptr -= VarGet(ScriptReadHalfword(ctx)); return FALSE; } @@ -489,6 +606,8 @@ bool8 ScrCmd_random(struct ScriptContext *ctx) { u16 max = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = Random() % max; return FALSE; } @@ -498,6 +617,8 @@ bool8 ScrCmd_additem(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u32 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = AddBagItem(itemId, quantity); return FALSE; } @@ -507,6 +628,8 @@ bool8 ScrCmd_removeitem(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u32 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = RemoveBagItem(itemId, quantity); return FALSE; } @@ -516,6 +639,8 @@ bool8 ScrCmd_checkitemspace(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u32 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = CheckBagHasSpace(itemId, quantity); return FALSE; } @@ -525,6 +650,8 @@ bool8 ScrCmd_checkitem(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u32 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = CheckBagHasItem(itemId, quantity); return FALSE; } @@ -533,6 +660,8 @@ bool8 ScrCmd_checkitemtype(struct ScriptContext *ctx) { u16 itemId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = GetPocketByItemId(itemId); return FALSE; } @@ -542,6 +671,8 @@ bool8 ScrCmd_addpcitem(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u16 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = AddPCItem(itemId, quantity); return FALSE; } @@ -551,6 +682,8 @@ bool8 ScrCmd_checkpcitem(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u16 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = CheckPCHasItem(itemId, quantity); return FALSE; } @@ -559,6 +692,8 @@ bool8 ScrCmd_adddecoration(struct ScriptContext *ctx) { u32 decorId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = DecorationAdd(decorId); return FALSE; } @@ -567,6 +702,8 @@ bool8 ScrCmd_removedecoration(struct ScriptContext *ctx) { u32 decorId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = DecorationRemove(decorId); return FALSE; } @@ -575,6 +712,8 @@ bool8 ScrCmd_checkdecorspace(struct ScriptContext *ctx) { u32 decorId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = DecorationCheckSpace(decorId); return FALSE; } @@ -583,44 +722,68 @@ bool8 ScrCmd_checkdecor(struct ScriptContext *ctx) { u32 decorId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = CheckHasDecoration(decorId); return FALSE; } bool8 ScrCmd_setflag(struct ScriptContext *ctx) { - FlagSet(ScriptReadHalfword(ctx)); + u32 flagId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + + FlagSet(flagId); return FALSE; } bool8 ScrCmd_clearflag(struct ScriptContext *ctx) { - FlagClear(ScriptReadHalfword(ctx)); + u32 flagId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + + FlagClear(flagId); return FALSE; } bool8 ScrCmd_checkflag(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = FlagGet(ScriptReadHalfword(ctx)); return FALSE; } bool8 ScrCmd_incrementgamestat(struct ScriptContext *ctx) { - IncrementGameStat(ScriptReadByte(ctx)); + u32 statId = ScriptReadByte(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + + IncrementGameStat(statId); return FALSE; } bool8 ScrCmd_animateflash(struct ScriptContext *ctx) { - AnimateFlash(ScriptReadByte(ctx)); + u32 level = ScriptReadByte(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + AnimateFlash(level); ScriptContext_Stop(); return TRUE; } bool8 ScrCmd_setflashlevel(struct ScriptContext *ctx) { - SetFlashLevel(VarGet(ScriptReadHalfword(ctx))); + u32 level = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + + SetFlashLevel(level); return FALSE; } @@ -634,7 +797,11 @@ static bool8 IsPaletteNotActive(void) bool8 ScrCmd_fadescreen(struct ScriptContext *ctx) { - FadeScreen(ScriptReadByte(ctx), 0); + u32 mode = ScriptReadByte(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + FadeScreen(mode, 0); SetupNativeScript(ctx, IsPaletteNotActive); return TRUE; } @@ -644,6 +811,8 @@ bool8 ScrCmd_fadescreenspeed(struct ScriptContext *ctx) u8 mode = ScriptReadByte(ctx); u8 speed = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + FadeScreen(mode, speed); SetupNativeScript(ctx, IsPaletteNotActive); return TRUE; @@ -653,6 +822,8 @@ bool8 ScrCmd_fadescreenswapbuffers(struct ScriptContext *ctx) { u8 mode = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + switch (mode) { case FADE_TO_BLACK: @@ -682,7 +853,11 @@ static bool8 RunPauseTimer(void) bool8 ScrCmd_delay(struct ScriptContext *ctx) { - sPauseCounter = ScriptReadHalfword(ctx); + u32 frames = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + sPauseCounter = frames; SetupNativeScript(ctx, RunPauseTimer); return TRUE; } @@ -692,18 +867,24 @@ bool8 ScrCmd_initclock(struct ScriptContext *ctx) u8 hour = VarGet(ScriptReadHalfword(ctx)); u8 minute = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + RtcInitLocalTimeOffset(hour, minute); return FALSE; } bool8 ScrCmd_dotimebasedevents(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + DoTimeBasedEvents(); return FALSE; } bool8 ScrCmd_gettime(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + RtcCalcLocalTime(); gSpecialVar_0x8000 = gLocalTime.hours; gSpecialVar_0x8001 = gLocalTime.minutes; @@ -715,25 +896,35 @@ bool8 ScrCmd_setweather(struct ScriptContext *ctx) { u16 weather = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetSavedWeather(weather); return FALSE; } bool8 ScrCmd_resetweather(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetSavedWeatherFromCurrMapHeader(); return FALSE; } bool8 ScrCmd_doweather(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + DoCurrentWeather(); return FALSE; } bool8 ScrCmd_setstepcallback(struct ScriptContext *ctx) { - ActivatePerStepCallback(ScriptReadByte(ctx)); + u32 callbackId = ScriptReadByte(ctx); + + Script_RequestEffects(SCREFF_V1); + + ActivatePerStepCallback(callbackId); return FALSE; } @@ -741,6 +932,8 @@ bool8 ScrCmd_setmaplayoutindex(struct ScriptContext *ctx) { u16 value = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetCurrentMapLayout(value); return FALSE; } @@ -753,6 +946,8 @@ bool8 ScrCmd_warp(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); DoWarp(); ResetInitialPlayerAvatarState(); @@ -767,6 +962,8 @@ bool8 ScrCmd_warpsilent(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); DoDiveWarp(); ResetInitialPlayerAvatarState(); @@ -781,6 +978,8 @@ bool8 ScrCmd_warpdoor(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); DoDoorWarp(); ResetInitialPlayerAvatarState(); @@ -794,6 +993,8 @@ bool8 ScrCmd_warphole(struct ScriptContext *ctx) s16 x; s16 y; + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + PlayerGetDestCoords(&x, &y); if (mapGroup == MAP_GROUP(UNDEFINED) && mapNum == MAP_NUM(UNDEFINED)) SetWarpDestinationToFixedHoleWarp(x - MAP_OFFSET, y - MAP_OFFSET); @@ -813,6 +1014,8 @@ bool8 ScrCmd_warpteleport(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); DoTeleportTileWarp(); ResetInitialPlayerAvatarState(); @@ -827,6 +1030,8 @@ bool8 ScrCmd_warpmossdeepgym(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); DoMossdeepGymWarp(); ResetInitialPlayerAvatarState(); @@ -841,6 +1046,8 @@ bool8 ScrCmd_setwarp(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); return FALSE; } @@ -853,6 +1060,8 @@ bool8 ScrCmd_setdynamicwarp(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetDynamicWarpWithCoords(0, mapGroup, mapNum, warpId, x, y); return FALSE; } @@ -865,6 +1074,8 @@ bool8 ScrCmd_setdivewarp(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + SetFixedDiveWarp(mapGroup, mapNum, warpId, x, y); return FALSE; } @@ -877,6 +1088,8 @@ bool8 ScrCmd_setholewarp(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + SetFixedHoleWarp(mapGroup, mapNum, warpId, x, y); return FALSE; } @@ -889,14 +1102,22 @@ bool8 ScrCmd_setescapewarp(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetEscapeWarp(mapGroup, mapNum, warpId, x, y); return FALSE; } bool8 ScrCmd_getplayerxy(struct ScriptContext *ctx) { - u16 *pX = GetVarPointer(ScriptReadHalfword(ctx)); - u16 *pY = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varIdX = ScriptReadHalfword(ctx); + u32 varIdY = ScriptReadHalfword(ctx); + u16 *pX = GetVarPointer(varIdX); + u16 *pY = GetVarPointer(varIdY); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varIdX); + Script_RequestWriteVar(varIdY); *pX = gSaveBlock1Ptr->pos.x; *pY = gSaveBlock1Ptr->pos.y; @@ -905,13 +1126,19 @@ bool8 ScrCmd_getplayerxy(struct ScriptContext *ctx) bool8 ScrCmd_getpartysize(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = CalculatePlayerPartyCount(); return FALSE; } bool8 ScrCmd_playse(struct ScriptContext *ctx) { - PlaySE(ScriptReadHalfword(ctx)); + u32 songId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + PlaySE(songId); return FALSE; } @@ -925,13 +1152,19 @@ static bool8 WaitForSoundEffectFinish(void) bool8 ScrCmd_waitse(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetupNativeScript(ctx, WaitForSoundEffectFinish); return TRUE; } bool8 ScrCmd_playfanfare(struct ScriptContext *ctx) { - PlayFanfare(ScriptReadHalfword(ctx)); + u32 songId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + PlayFanfare(songId); return FALSE; } @@ -942,6 +1175,8 @@ static bool8 WaitForFanfareFinish(void) bool8 ScrCmd_waitfanfare(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetupNativeScript(ctx, WaitForFanfareFinish); return TRUE; } @@ -951,6 +1186,8 @@ bool8 ScrCmd_playbgm(struct ScriptContext *ctx) u16 songId = ScriptReadHalfword(ctx); bool8 save = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + if (save == TRUE) Overworld_SetSavedMusic(songId); PlayNewMapMusic(songId); @@ -959,18 +1196,24 @@ bool8 ScrCmd_playbgm(struct ScriptContext *ctx) bool8 ScrCmd_savebgm(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + Overworld_SetSavedMusic(ScriptReadHalfword(ctx)); return FALSE; } bool8 ScrCmd_fadedefaultbgm(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + Overworld_ChangeMusicToDefault(); return FALSE; } bool8 ScrCmd_fadenewbgm(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + Overworld_ChangeMusicTo(ScriptReadHalfword(ctx)); return FALSE; } @@ -979,6 +1222,8 @@ bool8 ScrCmd_fadeoutbgm(struct ScriptContext *ctx) { u8 speed = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + if (speed != 0) FadeOutBGMTemporarily(4 * speed); else @@ -991,6 +1236,8 @@ bool8 ScrCmd_fadeinbgm(struct ScriptContext *ctx) { u8 speed = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + if (speed != 0) FadeInBGM(4 * speed); else @@ -1004,6 +1251,8 @@ bool8 ScrCmd_applymovement(struct ScriptContext *ctx) const u8 *movementScript = (const u8 *)ScriptReadWord(ctx); struct ObjectEvent *objEvent; + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + // When applying script movements to follower, it may have frozen animation that must be cleared if (localId == OBJ_EVENT_ID_FOLLOWER && (objEvent = GetFollowerObject()) && objEvent->frozen) { @@ -1036,6 +1285,8 @@ bool8 ScrCmd_applymovementat(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + gObjectEvents[GetObjectEventIdByLocalId(localId)].directionOverwrite = DIR_NONE; ScriptMovement_StartObjectMovementScript(localId, mapNum, mapGroup, movementScript); sMovingNpcId = localId; @@ -1060,6 +1311,8 @@ bool8 ScrCmd_waitmovement(struct ScriptContext *ctx) { u16 localId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (localId != 0) sMovingNpcId = localId; sMovingNpcMapGroup = gSaveBlock1Ptr->location.mapGroup; @@ -1074,6 +1327,8 @@ bool8 ScrCmd_waitmovementat(struct ScriptContext *ctx) u8 mapGroup; u8 mapNum; + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (localId != 0) sMovingNpcId = localId; mapGroup = ScriptReadByte(ctx); @@ -1088,6 +1343,8 @@ bool8 ScrCmd_removeobject(struct ScriptContext *ctx) { u16 localId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + RemoveObjectEventByLocalIdAndMap(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); return FALSE; } @@ -1098,6 +1355,8 @@ bool8 ScrCmd_removeobjectat(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + RemoveObjectEventByLocalIdAndMap(objectId, mapNum, mapGroup); return FALSE; } @@ -1106,6 +1365,8 @@ bool8 ScrCmd_addobject(struct ScriptContext *ctx) { u16 objectId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + TrySpawnObjectEvent(objectId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); return FALSE; } @@ -1116,6 +1377,8 @@ bool8 ScrCmd_addobjectat(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + TrySpawnObjectEvent(objectId, mapNum, mapGroup); return FALSE; } @@ -1126,6 +1389,8 @@ bool8 ScrCmd_setobjectxy(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + TryMoveObjectEventToMapCoords(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, x, y); return FALSE; } @@ -1136,6 +1401,8 @@ bool8 ScrCmd_setobjectxyperm(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetObjEventTemplateCoords(localId, x, y); return FALSE; } @@ -1144,6 +1411,8 @@ bool8 ScrCmd_copyobjectxytoperm(struct ScriptContext *ctx) { u16 localId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + TryOverrideObjectEventTemplateCoords(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup); return FALSE; } @@ -1154,6 +1423,8 @@ bool8 ScrCmd_showobjectat(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetObjectInvisibility(localId, mapNum, mapGroup, FALSE); return FALSE; } @@ -1164,6 +1435,8 @@ bool8 ScrCmd_hideobjectat(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetObjectInvisibility(localId, mapNum, mapGroup, TRUE); return FALSE; } @@ -1175,6 +1448,8 @@ bool8 ScrCmd_setobjectsubpriority(struct ScriptContext *ctx) u8 mapNum = ScriptReadByte(ctx); u8 priority = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetObjectSubpriority(localId, mapNum, mapGroup, priority + 83); return FALSE; } @@ -1185,12 +1460,16 @@ bool8 ScrCmd_resetobjectsubpriority(struct ScriptContext *ctx) u8 mapGroup = ScriptReadByte(ctx); u8 mapNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ResetObjectSubpriority(localId, mapNum, mapGroup); return FALSE; } bool8 ScrCmd_faceplayer(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (gObjectEvents[gSelectedObjectEvent].active) ObjectEventFaceOppositeDirection(&gObjectEvents[gSelectedObjectEvent], GetPlayerFacingDirection()); return FALSE; @@ -1201,6 +1480,8 @@ bool8 ScrCmd_turnobject(struct ScriptContext *ctx) u16 localId = VarGet(ScriptReadHalfword(ctx)); u8 direction = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ObjectEventTurnByLocalIdAndMap(localId, gSaveBlock1Ptr->location.mapNum, gSaveBlock1Ptr->location.mapGroup, direction); return FALSE; } @@ -1210,6 +1491,8 @@ bool8 ScrCmd_setobjectmovementtype(struct ScriptContext *ctx) u16 localId = VarGet(ScriptReadHalfword(ctx)); u8 movementType = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetObjEventTemplateMovementType(localId, movementType); return FALSE; } @@ -1223,6 +1506,8 @@ bool8 ScrCmd_createvobject(struct ScriptContext *ctx) u8 elevation = ScriptReadByte(ctx); u8 direction = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + CreateVirtualObject(graphicsId, virtualObjId, x, y, elevation, direction); return FALSE; } @@ -1232,6 +1517,8 @@ bool8 ScrCmd_turnvobject(struct ScriptContext *ctx) u8 virtualObjId = ScriptReadByte(ctx); u8 direction = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + TurnVirtualObject(virtualObjId, direction); return FALSE; } @@ -1240,6 +1527,8 @@ bool8 ScrCmd_turnvobject(struct ScriptContext *ctx) // The player is frozen after waiting for their current movement to finish. bool8 ScrCmd_lockall(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (IsOverworldLinkActive()) { return FALSE; @@ -1256,6 +1545,8 @@ bool8 ScrCmd_lockall(struct ScriptContext *ctx) // The player and selected object are frozen after waiting for their current movement to finish. bool8 ScrCmd_lock(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (IsOverworldLinkActive()) { return FALSE; @@ -1284,6 +1575,8 @@ bool8 ScrCmd_lock(struct ScriptContext *ctx) bool8 ScrCmd_releaseall(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + u8 playerObjectId; struct ObjectEvent *followerObject = GetFollowerObject(); // Release follower from movement iff it exists and is in the shadowing state @@ -1301,6 +1594,8 @@ bool8 ScrCmd_releaseall(struct ScriptContext *ctx) bool8 ScrCmd_release(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + u8 playerObjectId; struct ObjectEvent *followerObject = GetFollowerObject(); // Release follower from movement iff it exists and is in the shadowing state @@ -1322,6 +1617,8 @@ bool8 ScrCmd_message(struct ScriptContext *ctx) { const u8 *msg = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (msg == NULL) msg = (const u8 *)ctx->data[0]; ShowFieldMessage(msg); @@ -1332,6 +1629,8 @@ bool8 ScrCmd_pokenavcall(struct ScriptContext *ctx) { const u8 *msg = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (msg == NULL) msg = (const u8 *)ctx->data[0]; ShowPokenavFieldMessage(msg); @@ -1342,6 +1641,8 @@ bool8 ScrCmd_messageautoscroll(struct ScriptContext *ctx) { const u8 *msg = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (msg == NULL) msg = (const u8 *)ctx->data[0]; gTextFlags.autoScroll = TRUE; @@ -1355,6 +1656,8 @@ bool8 ScrCmd_messageinstant(struct ScriptContext *ctx) { const u8 *msg = (const u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (msg == NULL) msg = (const u8 *)ctx->data[0]; LoadMessageBoxAndBorderGfx(); @@ -1365,12 +1668,16 @@ bool8 ScrCmd_messageinstant(struct ScriptContext *ctx) bool8 ScrCmd_waitmessage(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetupNativeScript(ctx, IsFieldMessageBoxHidden); return TRUE; } bool8 ScrCmd_closemessage(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + HideFieldMessageBox(); return FALSE; } @@ -1386,6 +1693,8 @@ static bool8 WaitForAorBPress(void) bool8 ScrCmd_waitbuttonpress(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetupNativeScript(ctx, WaitForAorBPress); return TRUE; } @@ -1395,6 +1704,8 @@ bool8 ScrCmd_yesnobox(struct ScriptContext *ctx) u8 left = ScriptReadByte(ctx); u8 top = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (ScriptMenu_YesNo(left, top) == TRUE) { ScriptContext_Stop(); @@ -1441,6 +1752,8 @@ bool8 ScrCmd_dynmultichoice(struct ScriptContext *ctx) u32 argc = ScriptReadByte(ctx); struct ListMenuItem *items; + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (argc == 0) return FALSE; @@ -1490,9 +1803,12 @@ bool8 ScrCmd_dynmultichoice(struct ScriptContext *ctx) bool8 ScrCmd_dynmultipush(struct ScriptContext *ctx) { - u8 *nameBuffer = Alloc(100); const u8 *name = (const u8*) ScriptReadWord(ctx); u32 id = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + u8 *nameBuffer = Alloc(100); struct ListMenuItem item; StringExpandPlaceholders(nameBuffer, name); item.name = nameBuffer; @@ -1508,6 +1824,8 @@ bool8 ScrCmd_multichoice(struct ScriptContext *ctx) u8 multichoiceId = ScriptReadByte(ctx); bool8 ignoreBPress = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (ScriptMenu_Multichoice(left, top, multichoiceId, ignoreBPress) == TRUE) { ScriptContext_Stop(); @@ -1527,6 +1845,8 @@ bool8 ScrCmd_multichoicedefault(struct ScriptContext *ctx) u8 defaultChoice = ScriptReadByte(ctx); bool8 ignoreBPress = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (ScriptMenu_MultichoiceWithDefault(left, top, multichoiceId, ignoreBPress, defaultChoice) == TRUE) { ScriptContext_Stop(); @@ -1557,6 +1877,8 @@ bool8 ScrCmd_multichoicegrid(struct ScriptContext *ctx) u8 numColumns = ScriptReadByte(ctx); bool8 ignoreBPress = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (ScriptMenu_MultichoiceGrid(left, top, multichoiceId, ignoreBPress, numColumns) == TRUE) { ScriptContext_Stop(); @@ -1600,12 +1922,16 @@ bool8 ScrCmd_showmonpic(struct ScriptContext *ctx) u8 x = ScriptReadByte(ctx); u8 y = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ScriptMenu_ShowPokemonPic(species, x, y); return FALSE; } bool8 ScrCmd_hidemonpic(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + // The hide function returns a pointer to a function // that returns true once the pic is hidden bool8 (*func)(void) = ScriptMenu_HidePokemonPic(); @@ -1620,6 +1946,8 @@ bool8 ScrCmd_showcontestpainting(struct ScriptContext *ctx) { u8 contestWinnerId = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + // Artist's painting is temporary and already has its data loaded if (contestWinnerId != CONTEST_WINNER_ARTIST) SetContestWinnerForPainting(contestWinnerId); @@ -1632,6 +1960,9 @@ bool8 ScrCmd_showcontestpainting(struct ScriptContext *ctx) bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) { u8 *ptr = (u8 *)ScriptReadWord(ctx); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + struct WindowTemplate winTemplate; s32 i; u8 width, height; @@ -1685,6 +2016,8 @@ bool8 ScrCmd_braillemessage(struct ScriptContext *ctx) bool8 ScrCmd_closebraillemessage(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + CloseBrailleWindow(); return FALSE; } @@ -1693,6 +2026,8 @@ bool8 ScrCmd_vmessage(struct ScriptContext *ctx) { u32 msg = ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ShowFieldMessage((u8 *)(msg - sAddressOffset)); return FALSE; } @@ -1702,6 +2037,8 @@ bool8 ScrCmd_bufferspeciesname(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 species = VarGet(ScriptReadHalfword(ctx)) & OBJ_EVENT_GFX_SPECIES_MASK; // ignore possible shiny / form bits + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], GetSpeciesName(species)); return FALSE; } @@ -1710,6 +2047,8 @@ bool8 ScrCmd_bufferleadmonspeciesname(struct ScriptContext *ctx) { u8 stringVarIndex = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + u8 *dest = sScriptStringVars[stringVarIndex]; u8 partyIndex = GetLeadMonIndex(); u32 species = GetMonData(&gPlayerParty[partyIndex], MON_DATA_SPECIES, NULL); @@ -1721,6 +2060,8 @@ void BufferFirstLiveMonNickname(struct ScriptContext *ctx) { u8 stringVarIndex = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + GetMonData(GetFirstLiveMon(), MON_DATA_NICKNAME, sScriptStringVars[stringVarIndex]); StringGet_Nickname(sScriptStringVars[stringVarIndex]); } @@ -1730,6 +2071,8 @@ bool8 ScrCmd_bufferpartymonnick(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + GetMonData(&gPlayerParty[partyIndex], MON_DATA_NICKNAME, sScriptStringVars[stringVarIndex]); StringGet_Nickname(sScriptStringVars[stringVarIndex]); return FALSE; @@ -1740,6 +2083,8 @@ bool8 ScrCmd_bufferitemname(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 itemId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + CopyItemName(itemId, sScriptStringVars[stringVarIndex]); return FALSE; } @@ -1750,6 +2095,8 @@ bool8 ScrCmd_bufferitemnameplural(struct ScriptContext *ctx) u16 itemId = VarGet(ScriptReadHalfword(ctx)); u16 quantity = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + CopyItemNameHandlePlural(itemId, sScriptStringVars[stringVarIndex], quantity); return FALSE; } @@ -1759,6 +2106,8 @@ bool8 ScrCmd_bufferdecorationname(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 decorId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], gDecorations[decorId].name); return FALSE; } @@ -1768,6 +2117,8 @@ bool8 ScrCmd_buffermovename(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 moveId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], GetMoveName(moveId)); return FALSE; } @@ -1778,6 +2129,8 @@ bool8 ScrCmd_buffernumberstring(struct ScriptContext *ctx) u16 num = VarGet(ScriptReadHalfword(ctx)); u8 numDigits = CountDigits(num); + Script_RequestEffects(SCREFF_V1); + ConvertIntToDecimalStringN(sScriptStringVars[stringVarIndex], num, STR_CONV_MODE_LEFT_ALIGN, numDigits); return FALSE; } @@ -1787,6 +2140,8 @@ bool8 ScrCmd_bufferstdstring(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 index = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], gStdStrings[index]); return FALSE; } @@ -1796,6 +2151,8 @@ bool8 ScrCmd_buffercontestname(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 category = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + BufferContestName(sScriptStringVars[stringVarIndex], category); return FALSE; } @@ -1805,6 +2162,8 @@ bool8 ScrCmd_bufferstring(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); const u8 *text = (u8 *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], text); return FALSE; } @@ -1813,6 +2172,8 @@ bool8 ScrCmd_vbuffermessage(struct ScriptContext *ctx) { const u8 *ptr = (u8 *)(ScriptReadWord(ctx) - sAddressOffset); + Script_RequestEffects(SCREFF_V1); + StringExpandPlaceholders(gStringVar4, ptr); return FALSE; } @@ -1822,6 +2183,8 @@ bool8 ScrCmd_vbufferstring(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u32 addr = ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1); + const u8 *src = (u8 *)(addr - sAddressOffset); u8 *dest = sScriptStringVars[stringVarIndex]; StringCopy(dest, src); @@ -1833,6 +2196,8 @@ bool8 ScrCmd_bufferboxname(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 boxId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], GetBoxNamePtr(boxId)); return FALSE; } @@ -1841,6 +2206,8 @@ bool8 ScrCmd_giveegg(struct ScriptContext *ctx) { u16 species = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = ScriptGiveEgg(species); return FALSE; } @@ -1851,6 +2218,8 @@ bool8 ScrCmd_setmonmove(struct ScriptContext *ctx) u8 slot = ScriptReadByte(ctx); u16 move = ScriptReadHalfword(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + ScriptSetMonMoveSlot(partyIndex, move, slot); return FALSE; } @@ -1860,6 +2229,8 @@ bool8 ScrCmd_checkpartymove(struct ScriptContext *ctx) u8 i; u16 moveId = ScriptReadHalfword(ctx); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = PARTY_SIZE; for (i = 0; i < PARTY_SIZE; i++) { @@ -1882,7 +2253,11 @@ bool8 ScrCmd_addmoney(struct ScriptContext *ctx) u8 ignore = ScriptReadByte(ctx); if (!ignore) + { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + AddMoney(&gSaveBlock1Ptr->money, amount); + } return FALSE; } @@ -1892,7 +2267,11 @@ bool8 ScrCmd_removemoney(struct ScriptContext *ctx) u8 ignore = ScriptReadByte(ctx); if (!ignore) + { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + RemoveMoney(&gSaveBlock1Ptr->money, amount); + } return FALSE; } @@ -1902,7 +2281,11 @@ bool8 ScrCmd_checkmoney(struct ScriptContext *ctx) u8 ignore = ScriptReadByte(ctx); if (!ignore) + { + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = IsEnoughMoney(&gSaveBlock1Ptr->money, amount); + } return FALSE; } @@ -1913,12 +2296,18 @@ bool8 ScrCmd_showmoneybox(struct ScriptContext *ctx) u8 ignore = ScriptReadByte(ctx); if (!ignore) + { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + DrawMoneyBox(GetMoney(&gSaveBlock1Ptr->money), x, y); + } return FALSE; } bool8 ScrCmd_hidemoneybox(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + /*u8 x = ScriptReadByte(ctx); u8 y = ScriptReadByte(ctx);*/ @@ -1933,7 +2322,11 @@ bool8 ScrCmd_updatemoneybox(struct ScriptContext *ctx) u8 ignore = ScriptReadByte(ctx); if (!ignore) + { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ChangeAmountInMoneyBox(GetMoney(&gSaveBlock1Ptr->money)); + } return FALSE; } @@ -1942,6 +2335,8 @@ bool8 ScrCmd_showcoinsbox(struct ScriptContext *ctx) u8 x = ScriptReadByte(ctx); u8 y = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ShowCoinsWindow(GetCoins(), x, y); return FALSE; } @@ -1951,6 +2346,8 @@ bool8 ScrCmd_hidecoinsbox(struct ScriptContext *ctx) u8 UNUSED x = ScriptReadByte(ctx); u8 UNUSED y = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + HideCoinsWindow(); return FALSE; } @@ -1960,30 +2357,40 @@ bool8 ScrCmd_updatecoinsbox(struct ScriptContext *ctx) u8 UNUSED x = ScriptReadByte(ctx); u8 UNUSED y = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + PrintCoinsString(GetCoins()); return FALSE; } bool8 ScrCmd_trainerbattle(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_TRAINERBATTLE); + ctx->scriptPtr = BattleSetup_ConfigureTrainerBattle(ctx->scriptPtr); return FALSE; } bool8 ScrCmd_dotrainerbattle(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + BattleSetup_StartTrainerBattle(); return TRUE; } bool8 ScrCmd_gotopostbattlescript(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + ctx->scriptPtr = BattleSetup_GetScriptAddrAfterBattle(); return FALSE; } bool8 ScrCmd_gotobeatenscript(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + ctx->scriptPtr = BattleSetup_GetTrainerPostBattleScript(); return FALSE; } @@ -1992,6 +2399,8 @@ bool8 ScrCmd_checktrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + ctx->comparisonResult = HasTrainerBeenFought(index); return FALSE; } @@ -2000,6 +2409,8 @@ bool8 ScrCmd_settrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetTrainerFlag(index); return FALSE; } @@ -2008,6 +2419,8 @@ bool8 ScrCmd_cleartrainerflag(struct ScriptContext *ctx) { u16 index = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + ClearTrainerFlag(index); return FALSE; } @@ -2021,6 +2434,8 @@ bool8 ScrCmd_setwildbattle(struct ScriptContext *ctx) u8 level2 = ScriptReadByte(ctx); u16 item2 = ScriptReadHalfword(ctx); + Script_RequestEffects(SCREFF_V1); + if(species2 == SPECIES_NONE) { CreateScriptedWildMon(species, level, item); @@ -2037,6 +2452,8 @@ bool8 ScrCmd_setwildbattle(struct ScriptContext *ctx) bool8 ScrCmd_dowildbattle(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (sIsScriptedWildDouble == FALSE) BattleSetup_StartScriptedWildBattle(); else @@ -2051,6 +2468,8 @@ bool8 ScrCmd_pokemart(struct ScriptContext *ctx) { const void *ptr = (void *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + CreatePokemartMenu(ptr); ScriptContext_Stop(); return TRUE; @@ -2060,6 +2479,8 @@ bool8 ScrCmd_pokemartdecoration(struct ScriptContext *ctx) { const void *ptr = (void *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + CreateDecorationShop1Menu(ptr); ScriptContext_Stop(); return TRUE; @@ -2070,6 +2491,8 @@ bool8 ScrCmd_pokemartdecoration2(struct ScriptContext *ctx) { const void *ptr = (void *)ScriptReadWord(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + CreateDecorationShop2Menu(ptr); ScriptContext_Stop(); return TRUE; @@ -2079,6 +2502,8 @@ bool8 ScrCmd_playslotmachine(struct ScriptContext *ctx) { u8 machineId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + PlaySlotMachine(machineId, CB2_ReturnToFieldContinueScriptPlayMapMusic); ScriptContext_Stop(); return TRUE; @@ -2090,6 +2515,8 @@ bool8 ScrCmd_setberrytree(struct ScriptContext *ctx) u8 berry = ScriptReadByte(ctx); u8 growthStage = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (berry == 0) PlantBerryTree(treeId, berry, growthStage, FALSE); else @@ -2101,12 +2528,16 @@ bool8 ScrCmd_getpokenewsactive(struct ScriptContext *ctx) { u16 newsKind = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = IsPokeNewsActive(newsKind); return FALSE; } bool8 ScrCmd_choosecontestmon(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ChooseContestMon(); ScriptContext_Stop(); return TRUE; @@ -2115,6 +2546,8 @@ bool8 ScrCmd_choosecontestmon(struct ScriptContext *ctx) bool8 ScrCmd_startcontest(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + StartContest(); ScriptContext_Stop(); return TRUE; @@ -2122,6 +2555,8 @@ bool8 ScrCmd_startcontest(struct ScriptContext *ctx) bool8 ScrCmd_showcontestresults(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ShowContestResults(); ScriptContext_Stop(); return TRUE; @@ -2129,6 +2564,8 @@ bool8 ScrCmd_showcontestresults(struct ScriptContext *ctx) bool8 ScrCmd_contestlinktransfer(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + ContestLinkTransfer(gSpecialVar_ContestCategory); ScriptContext_Stop(); return TRUE; @@ -2138,6 +2575,8 @@ bool8 ScrCmd_dofieldeffect(struct ScriptContext *ctx) { u16 effectId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + sFieldEffectScriptId = effectId; FieldEffectStart(sFieldEffectScriptId); return FALSE; @@ -2147,6 +2586,8 @@ bool8 ScrCmd_setfieldeffectargument(struct ScriptContext *ctx) { u8 argNum = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1); + gFieldEffectArguments[argNum] = (s16)VarGet(ScriptReadHalfword(ctx)); return FALSE; } @@ -2161,7 +2602,11 @@ static bool8 WaitForFieldEffectFinish(void) bool8 ScrCmd_waitfieldeffect(struct ScriptContext *ctx) { - sFieldEffectScriptId = VarGet(ScriptReadHalfword(ctx)); + u32 scriptId = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + + sFieldEffectScriptId = scriptId; SetupNativeScript(ctx, WaitForFieldEffectFinish); return TRUE; } @@ -2170,12 +2615,16 @@ bool8 ScrCmd_setrespawn(struct ScriptContext *ctx) { u16 healLocationId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetLastHealLocationWarp(healLocationId); return FALSE; } bool8 ScrCmd_checkplayergender(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = gSaveBlock2Ptr->playerGender; return FALSE; } @@ -2185,17 +2634,23 @@ bool8 ScrCmd_playmoncry(struct ScriptContext *ctx) u16 species = VarGet(ScriptReadHalfword(ctx)); u16 mode = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + PlayCry_Script(species, mode); return FALSE; } void PlayFirstMonCry(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + PlayCry_Script(GetMonData(GetFirstLiveMon(), MON_DATA_SPECIES), CRY_MODE_NORMAL); } bool8 ScrCmd_waitmoncry(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetupNativeScript(ctx, IsCryFinished); return TRUE; } @@ -2207,6 +2662,8 @@ bool8 ScrCmd_setmetatile(struct ScriptContext *ctx) u16 metatileId = VarGet(ScriptReadHalfword(ctx)); bool16 isImpassable = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + x += MAP_OFFSET; y += MAP_OFFSET; if (!isImpassable) @@ -2221,6 +2678,8 @@ bool8 ScrCmd_opendoor(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + x += MAP_OFFSET; y += MAP_OFFSET; PlaySE(GetDoorSoundEffect(x, y)); @@ -2233,6 +2692,8 @@ bool8 ScrCmd_closedoor(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + x += MAP_OFFSET; y += MAP_OFFSET; FieldAnimateDoorClose(x, y); @@ -2249,6 +2710,8 @@ static bool8 IsDoorAnimationStopped(void) bool8 ScrCmd_waitdooranim(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + SetupNativeScript(ctx, IsDoorAnimationStopped); return TRUE; } @@ -2258,6 +2721,8 @@ bool8 ScrCmd_setdooropen(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + x += MAP_OFFSET; y += MAP_OFFSET; FieldSetDoorOpened(x, y); @@ -2269,6 +2734,8 @@ bool8 ScrCmd_setdoorclosed(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + x += MAP_OFFSET; y += MAP_OFFSET; FieldSetDoorClosed(x, y); @@ -2297,7 +2764,12 @@ bool8 ScrCmd_showelevmenu(struct ScriptContext *ctx) bool8 ScrCmd_checkcoins(struct ScriptContext *ctx) { - u16 *ptr = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + u16 *ptr = GetVarPointer(varId); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + *ptr = GetCoins(); return FALSE; } @@ -2306,6 +2778,8 @@ bool8 ScrCmd_addcoins(struct ScriptContext *ctx) { u16 coins = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (AddCoins(coins) == TRUE) gSpecialVar_Result = FALSE; else @@ -2317,6 +2791,8 @@ bool8 ScrCmd_removecoins(struct ScriptContext *ctx) { u16 coins = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (RemoveCoins(coins) == TRUE) gSpecialVar_Result = FALSE; else @@ -2328,12 +2804,16 @@ bool8 ScrCmd_moverotatingtileobjects(struct ScriptContext *ctx) { u16 puzzleNumber = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + sMovingNpcId = MoveRotatingTileObjects(puzzleNumber); return FALSE; } bool8 ScrCmd_turnrotatingtileobjects(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + TurnRotatingTileObjects(); return FALSE; } @@ -2342,24 +2822,32 @@ bool8 ScrCmd_initrotatingtilepuzzle(struct ScriptContext *ctx) { u16 isTrickHouse = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + InitRotatingTilePuzzle(isTrickHouse); return FALSE; } bool8 ScrCmd_freerotatingtilepuzzle(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + FreeRotatingTilePuzzle(); return FALSE; } bool8 ScrCmd_selectapproachingtrainer(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + gSelectedObjectEvent = GetCurrentApproachingTrainerObjectEventId(); return FALSE; } bool8 ScrCmd_lockfortrainer(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1 | SCREFF_HARDWARE); + if (IsOverworldLinkActive()) { return FALSE; @@ -2381,6 +2869,8 @@ bool8 ScrCmd_setmodernfatefulencounter(struct ScriptContext *ctx) bool8 isModernFatefulEncounter = TRUE; u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + SetMonData(&gPlayerParty[partyIndex], MON_DATA_MODERN_FATEFUL_ENCOUNTER, &isModernFatefulEncounter); return FALSE; } @@ -2389,6 +2879,8 @@ bool8 ScrCmd_checkmodernfatefulencounter(struct ScriptContext *ctx) { u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_MODERN_FATEFUL_ENCOUNTER, NULL); return FALSE; } @@ -2399,6 +2891,8 @@ bool8 ScrCmd_trywondercardscript(struct ScriptContext *ctx) if (script) { + Script_RequestEffects(SCREFF_V1); + gRamScriptRetAddr = ctx->scriptPtr; ScriptJump(ctx, script); } @@ -2415,6 +2909,8 @@ bool8 ScrCmd_warpspinenter(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); SetSpinStartFacingDir(GetPlayerFacingDirection()); DoSpinEnterWarp(); @@ -2427,6 +2923,8 @@ bool8 ScrCmd_setmonmetlocation(struct ScriptContext *ctx) u16 partyIndex = VarGet(ScriptReadHalfword(ctx)); u8 location = ScriptReadByte(ctx); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (partyIndex < PARTY_SIZE) SetMonData(&gPlayerParty[partyIndex], MON_DATA_MET_LOCATION, &location); return FALSE; @@ -2443,6 +2941,8 @@ bool8 ScrCmd_buffertrainerclassname(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 trainerClassId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], GetTrainerClassNameFromId(trainerClassId)); return FALSE; } @@ -2452,6 +2952,8 @@ bool8 ScrCmd_buffertrainername(struct ScriptContext *ctx) u8 stringVarIndex = ScriptReadByte(ctx); u16 trainerClassId = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + StringCopy(sScriptStringVars[stringVarIndex], GetTrainerNameFromId(trainerClassId)); return FALSE; } @@ -2469,6 +2971,8 @@ bool8 ScrCmd_warpwhitefade(struct ScriptContext *ctx) u16 x = VarGet(ScriptReadHalfword(ctx)); u16 y = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE); + SetWarpDestination(mapGroup, mapNum, warpId, x, y); DoWhiteFadeWarp(); ResetInitialPlayerAvatarState(); @@ -2477,12 +2981,17 @@ bool8 ScrCmd_warpwhitefade(struct ScriptContext *ctx) void ScriptSetDoubleBattleFlag(struct ScriptContext *ctx) { + Script_RequestEffects(SCREFF_V1); + sIsScriptedWildDouble = TRUE; } bool8 ScrCmd_removeallitem(struct ScriptContext *ctx) { u32 itemId = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + u32 count = CountTotalItemQuantityInBag(itemId); gSpecialVar_Result = count; RemoveBagItem(itemId, count); @@ -2494,8 +3003,15 @@ bool8 ScrCmd_getobjectxy(struct ScriptContext *ctx) { u32 localId = VarGet(ScriptReadHalfword(ctx)); u32 useTemplate = VarGet(ScriptReadHalfword(ctx)); - u16 *pX = GetVarPointer(ScriptReadHalfword(ctx)); - u16 *pY = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varIdX = ScriptReadHalfword(ctx); + u32 varIdY = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varIdX); + Script_RequestWriteVar(varIdY); + + u16 *pX = GetVarPointer(varIdX); + u16 *pY = GetVarPointer(varIdY); GetObjectPosition(pX, pY, localId, useTemplate); return FALSE; @@ -2505,7 +3021,12 @@ bool8 ScrCmd_checkobjectat(struct ScriptContext *ctx) { u32 x = VarGet(ScriptReadHalfword(ctx)) + 7; u32 y = VarGet(ScriptReadHalfword(ctx)) + 7; - u16 *varPointer = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + + u16 *varPointer = GetVarPointer(varId); *varPointer = CheckObjectAtXY(x, y); @@ -2515,7 +3036,13 @@ bool8 ScrCmd_checkobjectat(struct ScriptContext *ctx) bool8 Scrcmd_getsetpokedexflag(struct ScriptContext *ctx) { u32 speciesId = SpeciesToNationalPokedexNum(VarGet(ScriptReadHalfword(ctx))); - bool32 desiredFlag = VarGet(ScriptReadHalfword(ctx)); + u32 desiredFlag = VarGet(ScriptReadHalfword(ctx)); + + if (desiredFlag == FLAG_SET_CAUGHT || desiredFlag == FLAG_SET_SEEN) + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + else + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = GetSetPokedexFlag(speciesId, desiredFlag); if (desiredFlag == FLAG_SET_CAUGHT) @@ -2527,6 +3054,9 @@ bool8 Scrcmd_getsetpokedexflag(struct ScriptContext *ctx) bool8 Scrcmd_checkspecies(struct ScriptContext *ctx) { u32 givenSpecies = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = CheckPartyHasSpecies(givenSpecies); return FALSE; @@ -2535,6 +3065,9 @@ bool8 Scrcmd_checkspecies(struct ScriptContext *ctx) bool8 Scrcmd_checkspecies_choose(struct ScriptContext *ctx) { u32 givenSpecies = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = (GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_SPECIES) == givenSpecies); return FALSE; @@ -2543,9 +3076,21 @@ bool8 Scrcmd_checkspecies_choose(struct ScriptContext *ctx) bool8 Scrcmd_getobjectfacingdirection(struct ScriptContext *ctx) { u32 objectId = VarGet(ScriptReadHalfword(ctx)); - u16 *varPointer = GetVarPointer(ScriptReadHalfword(ctx)); + u32 varId = ScriptReadHalfword(ctx); + + Script_RequestEffects(SCREFF_V1); + Script_RequestWriteVar(varId); + + u16 *varPointer = GetVarPointer(varId); *varPointer = gObjectEvents[GetObjectEventIdByLocalId(objectId)].facingDirection; return FALSE; } + +void Script_EndTrainerCanSeeIf(struct ScriptContext *ctx) +{ + u8 condition = ScriptReadByte(ctx); + if (ctx->breakOnTrainerBattle && sScriptConditionTable[condition][ctx->comparisonResult] == 1) + StopScript(ctx); +} diff --git a/src/script.c b/src/script.c index e6e2aa264d86..7111f3228df4 100644 --- a/src/script.c +++ b/src/script.c @@ -2,6 +2,8 @@ #include "script.h" #include "event_data.h" #include "mystery_gift.h" +#include "random.h" +#include "trainer_see.h" #include "util.h" #include "constants/event_objects.h" #include "constants/map_scripts.h" @@ -50,6 +52,8 @@ void InitScriptContext(struct ScriptContext *ctx, void *cmdTable, void *cmdTable for (i = 0; i < (int)ARRAY_COUNT(ctx->stack); i++) ctx->stack[i] = NULL; + + ctx->breakOnTrainerBattle = FALSE; } u8 SetupBytecodeScript(struct ScriptContext *ctx, const u8 *ptr) @@ -258,6 +262,14 @@ void ScriptContext_SetupScript(const u8 *ptr) sGlobalScriptContextStatus = CONTEXT_RUNNING; } +// Moves a script from a local context to the global context and enables it. +void ScriptContext_ContinueScript(struct ScriptContext *ctx) +{ + sGlobalScriptContext = *ctx; + LockPlayerFieldControls(); + sGlobalScriptContextStatus = CONTEXT_RUNNING; +} + // Puts the script into waiting mode; usually called from a wait* script command. void ScriptContext_Stop(void) { @@ -281,7 +293,7 @@ void RunScriptImmediately(const u8 *ptr) while (RunScriptCommand(&sImmediateScriptContext) == TRUE); } -u8 *MapHeaderGetScriptTable(u8 tag) +const u8 *MapHeaderGetScriptTable(u8 tag) { const u8 *mapScripts = gMapHeader.mapScripts; @@ -303,14 +315,14 @@ u8 *MapHeaderGetScriptTable(u8 tag) void MapHeaderRunScriptType(u8 tag) { - u8 *ptr = MapHeaderGetScriptTable(tag); + const u8 *ptr = MapHeaderGetScriptTable(tag); if (ptr) RunScriptImmediately(ptr); } -u8 *MapHeaderCheckScriptTable(u8 tag) +const u8 *MapHeaderCheckScriptTable(u8 tag) { - u8 *ptr = MapHeaderGetScriptTable(tag); + const u8 *ptr = MapHeaderGetScriptTable(tag); if (!ptr) return NULL; @@ -332,7 +344,12 @@ u8 *MapHeaderCheckScriptTable(u8 tag) // Run map script if vars are equal if (VarGet(varIndex1) == VarGet(varIndex2)) - return T2_READ_PTR(ptr); + { + const u8 *mapScript = T2_READ_PTR(ptr); + if (!Script_HasNoEffect(mapScript)) + return mapScript; + } + ptr += 4; } } @@ -364,7 +381,7 @@ void RunOnDiveWarpMapScript(void) bool8 TryRunOnFrameMapScript(void) { - u8 *ptr = MapHeaderCheckScriptTable(MAP_SCRIPT_ON_FRAME_TABLE); + const u8 *ptr = MapHeaderCheckScriptTable(MAP_SCRIPT_ON_FRAME_TABLE); if (!ptr) return FALSE; @@ -375,7 +392,7 @@ bool8 TryRunOnFrameMapScript(void) void TryRunOnWarpIntoMapScript(void) { - u8 *ptr = MapHeaderCheckScriptTable(MAP_SCRIPT_ON_WARP_INTO_MAP_TABLE); + const u8 *ptr = MapHeaderCheckScriptTable(MAP_SCRIPT_ON_WARP_INTO_MAP_TABLE); if (ptr) RunScriptImmediately(ptr); } @@ -504,3 +521,116 @@ void InitRamScript_NoObjectEvent(u8 *script, u16 scriptSize) InitRamScript(script, scriptSize, MAP_GROUP(UNDEFINED), MAP_NUM(UNDEFINED), NO_OBJECT); #endif //FREE_MYSTERY_EVENT_BUFFERS } + +bool8 LoadTrainerObjectScript(void) +{ + sGlobalScriptContext.scriptPtr = gApproachingTrainers[gNoOfApproachingTrainers - 1].trainerScriptPtr; + return TRUE; +} + +struct ScriptEffectContext { + u32 breakOn; + intptr_t breakTo[5]; + const u8 *nextCmd; +}; + +struct ScriptEffectContext *gScriptEffectContext = NULL; + +static bool32 Script_IsEffectInstrumentedCommand(ScrCmdFunc func) +{ + // In ROM mirror 1. + return (((uintptr_t)func) & 0xE000000) == 0xA000000; +} + +/* 'setjmp' and 'longjmp' cause link errors, so we use + * '__builtin_setjmp' and '__builtin_longjmp' instead. + * See https://gcc.gnu.org/onlinedocs/gcc/Nonlocal-Gotos.html */ +static bool32 RunScriptImmediatelyUntilEffect_InternalLoop(struct ScriptContext *ctx) +{ + if (__builtin_setjmp(gScriptEffectContext->breakTo) == 0) + { + while (TRUE) + { + u32 cmdCode; + ScrCmdFunc *func; + + gScriptEffectContext->nextCmd = ctx->scriptPtr; + + if (!ctx->scriptPtr) + return FALSE; + + cmdCode = *ctx->scriptPtr; + ctx->scriptPtr++; + func = &ctx->cmdTable[cmdCode]; + + // Invalid script command. + if (func >= ctx->cmdTableEnd) + return TRUE; + + if (!Script_IsEffectInstrumentedCommand(*func)) + return TRUE; + + // Command which waits for a frame. + if ((*func)(ctx)) + { + gScriptEffectContext->nextCmd = ctx->scriptPtr; + return TRUE; + } + } + } + else + { + return TRUE; + } +} + +void Script_GotoBreak_Internal(void) +{ + __builtin_longjmp(gScriptEffectContext->breakTo, 1); +} + +bool32 RunScriptImmediatelyUntilEffect_Internal(u32 effects, const u8 *ptr, struct ScriptContext *ctx) +{ + bool32 result; + struct ScriptEffectContext seCtx; + seCtx.breakOn = effects & 0x7FFFFFFF; + + if (ctx == NULL) + ctx = &sImmediateScriptContext; + + InitScriptContext(ctx, gScriptCmdTable, gScriptCmdTableEnd); + if (effects & SCREFF_TRAINERBATTLE) + ctx->breakOnTrainerBattle = TRUE; + SetupBytecodeScript(ctx, ptr); + + rng_value_t rngValue = gRngValue; + gScriptEffectContext = &seCtx; + result = RunScriptImmediatelyUntilEffect_InternalLoop(ctx); + gScriptEffectContext = NULL; + gRngValue = rngValue; + + if (result) + ctx->scriptPtr = seCtx.nextCmd; + + return result; +} + +bool32 Script_HasNoEffect(const u8 *ptr) +{ + return !RunScriptImmediatelyUntilEffect(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE, ptr, NULL); +} + +void Script_RequestEffects_Internal(u32 effects) +{ + if (gScriptEffectContext->breakOn & effects) + __builtin_longjmp(gScriptEffectContext->breakTo, 1); +} + +void Script_RequestWriteVar_Internal(u32 varId) +{ + if (varId == 0) + return; + if (SPECIAL_VARS_START <= varId && varId <= SPECIAL_VARS_END) + return; + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); +} diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index fc248435a90d..77ce6411db26 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -240,6 +240,9 @@ void CanHyperTrain(struct ScriptContext *ctx) { u32 stat = ScriptReadByte(ctx); u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1); + if (stat < NUM_STATS && partyIndex < PARTY_SIZE && !GetMonData(&gPlayerParty[partyIndex], MON_DATA_HYPER_TRAINED_HP + stat) @@ -257,6 +260,9 @@ void HyperTrain(struct ScriptContext *ctx) { u32 stat = ScriptReadByte(ctx); u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (stat < NUM_STATS && partyIndex < PARTY_SIZE) { bool32 data = TRUE; @@ -268,6 +274,9 @@ void HyperTrain(struct ScriptContext *ctx) void HasGigantamaxFactor(struct ScriptContext *ctx) { u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + Script_RequestEffects(SCREFF_V1); + if (partyIndex < PARTY_SIZE) gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_GIGANTAMAX_FACTOR); else @@ -278,6 +287,8 @@ void ToggleGigantamaxFactor(struct ScriptContext *ctx) { u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + gSpecialVar_Result = FALSE; if (partyIndex < PARTY_SIZE) @@ -298,6 +309,8 @@ void CheckTeraType(struct ScriptContext *ctx) { u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1); + gSpecialVar_Result = TYPE_NONE; if (partyIndex < PARTY_SIZE) @@ -309,6 +322,8 @@ void SetTeraType(struct ScriptContext *ctx) u32 type = ScriptReadByte(ctx); u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (type < NUMBER_OF_MON_TYPES && partyIndex < PARTY_SIZE) SetMonData(&gPlayerParty[partyIndex], MON_DATA_TERA_TYPE, &type); } @@ -317,7 +332,7 @@ void SetTeraType(struct ScriptContext *ctx) * if side/slot are assigned, it will create the mon at the assigned party location * if slot == PARTY_SIZE, it will give the mon to first available party or storage slot */ -static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u16 item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, bool8 isShiny, bool8 ggMaxFactor, u8 teraType) +static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u16 item, enum PokeBall ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, bool8 isShiny, bool8 gmaxFactor, u8 teraType, u8 dmaxLevel) { u16 nationalDexNum; int sentToPc; @@ -352,7 +367,10 @@ static u32 ScriptGiveMonParameterized(u8 side, u8 slot, u16 species, u8 level, u SetMonData(&mon, MON_DATA_IS_SHINY, &isShiny); // gigantamax factor - SetMonData(&mon, MON_DATA_GIGANTAMAX_FACTOR, &ggMaxFactor); + SetMonData(&mon, MON_DATA_GIGANTAMAX_FACTOR, &gmaxFactor); + + // Dynamax Level + SetMonData(&mon, MON_DATA_DYNAMAX_LEVEL, &dmaxLevel); // tera type if (teraType >= NUMBER_OF_MON_TYPES) @@ -461,7 +479,7 @@ u32 ScriptGiveMon(u16 species, u8 level, u16 item) MAX_PER_STAT_IVS + 1, MAX_PER_STAT_IVS + 1, MAX_PER_STAT_IVS + 1}; // ScriptGiveMonParameterized won't touch the stats' IV. u16 moves[MAX_MON_MOVES] = {MOVE_NONE, MOVE_NONE, MOVE_NONE, MOVE_NONE}; - return ScriptGiveMonParameterized(0, PARTY_SIZE, species, level, item, ITEM_POKE_BALL, NUM_NATURES, NUM_ABILITY_PERSONALITY, MON_GENDERLESS, evs, ivs, moves, FALSE, FALSE, NUMBER_OF_MON_TYPES); + return ScriptGiveMonParameterized(0, PARTY_SIZE, species, level, item, ITEM_POKE_BALL, NUM_NATURES, NUM_ABILITY_PERSONALITY, MON_GENDERLESS, evs, ivs, moves, FALSE, FALSE, NUMBER_OF_MON_TYPES, 0); } #define PARSE_FLAG(n, default_) (flags & (1 << (n))) ? VarGet(ScriptReadHalfword(ctx)) : (default_) @@ -535,14 +553,20 @@ void ScrCmd_createmon(struct ScriptContext *ctx) u16 move3 = PARSE_FLAG(19, MOVE_NONE); u16 move4 = PARSE_FLAG(20, MOVE_NONE); bool8 isShiny = PARSE_FLAG(21, FALSE); - bool8 ggMaxFactor = PARSE_FLAG(22, FALSE); + bool8 gmaxFactor = PARSE_FLAG(22, FALSE); u8 teraType = PARSE_FLAG(23, NUMBER_OF_MON_TYPES); + u8 dmaxLevel = PARSE_FLAG(24, 0); u8 evs[NUM_STATS] = {hpEv, atkEv, defEv, speedEv, spAtkEv, spDefEv}; u8 ivs[NUM_STATS] = {hpIv, atkIv, defIv, speedIv, spAtkIv, spDefIv}; u16 moves[MAX_MON_MOVES] = {move1, move2, move3, move4}; - gSpecialVar_Result = ScriptGiveMonParameterized(side, slot, species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, isShiny, ggMaxFactor, teraType); + if (side == 0) + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + else + Script_RequestEffects(SCREFF_V1); + + gSpecialVar_Result = ScriptGiveMonParameterized(side, slot, species, level, item, ball, nature, abilityNum, gender, evs, ivs, moves, isShiny, gmaxFactor, teraType, dmaxLevel); } #undef PARSE_FLAG @@ -580,6 +604,8 @@ void Script_SetStatus1(struct ScriptContext *ctx) u32 status1 = VarGet(ScriptReadHalfword(ctx)); u32 slot = VarGet(ScriptReadHalfword(ctx)); + Script_RequestEffects(SCREFF_V1 | SCREFF_SAVE); + if (slot >= PARTY_SIZE) { u16 species; diff --git a/src/shop.c b/src/shop.c index a343bab0d3ee..dae2ea86ffb4 100644 --- a/src/shop.c +++ b/src/shop.c @@ -21,6 +21,7 @@ #include "menu.h" #include "menu_helpers.h" #include "money.h" +#include "move.h" #include "overworld.h" #include "palette.h" #include "party_menu.h" diff --git a/src/start_menu.c b/src/start_menu.c index 0c364bb07dea..004403e659e7 100644 --- a/src/start_menu.c +++ b/src/start_menu.c @@ -44,6 +44,8 @@ #include "trainer_card.h" #include "window.h" #include "union_room.h" +#include "dexnav.h" +#include "wild_encounter.h" #include "constants/battle_frontier.h" #include "constants/rgb.h" #include "constants/songs.h" @@ -65,6 +67,7 @@ enum MENU_ACTION_RETIRE_FRONTIER, MENU_ACTION_PYRAMID_BAG, MENU_ACTION_DEBUG, + MENU_ACTION_DEXNAV, }; // Save status @@ -106,6 +109,7 @@ static bool8 StartMenuLinkModePlayerNameCallback(void); static bool8 StartMenuBattlePyramidRetireCallback(void); static bool8 StartMenuBattlePyramidBagCallback(void); static bool8 StartMenuDebugCallback(void); +static bool8 StartMenuDexNavCallback(void); // Menu callbacks static bool8 SaveStartCallback(void); @@ -200,6 +204,7 @@ static const struct MenuAction sStartMenuItems[] = [MENU_ACTION_RETIRE_FRONTIER] = {gText_MenuRetire, {.u8_void = StartMenuBattlePyramidRetireCallback}}, [MENU_ACTION_PYRAMID_BAG] = {gText_MenuBag, {.u8_void = StartMenuBattlePyramidBagCallback}}, [MENU_ACTION_DEBUG] = {sText_MenuDebug, {.u8_void = StartMenuDebugCallback}}, + [MENU_ACTION_DEXNAV] = {gText_MenuDexNav, {.u8_void = StartMenuDexNavCallback}}, }; static const struct BgTemplate sBgTemplates_LinkBattleSave[] = @@ -324,22 +329,20 @@ static void AddStartMenuAction(u8 action) } static void BuildNormalStartMenu(void) -{ +{ if (FlagGet(FLAG_SYS_POKEDEX_GET) == TRUE) - { AddStartMenuAction(MENU_ACTION_POKEDEX); - } + + if (FLAG_SYS_DEXNAV_GET != 0 && FlagGet(FLAG_SYS_DEXNAV_GET)) + AddStartMenuAction(MENU_ACTION_DEXNAV); + if (FlagGet(FLAG_SYS_POKEMON_GET) == TRUE) - { AddStartMenuAction(MENU_ACTION_POKEMON); - } AddStartMenuAction(MENU_ACTION_BAG); if (FlagGet(FLAG_SYS_POKENAV_GET) == TRUE) - { AddStartMenuAction(MENU_ACTION_POKENAV); - } AddStartMenuAction(MENU_ACTION_PLAYER); AddStartMenuAction(MENU_ACTION_SAVE); @@ -638,7 +641,10 @@ static bool8 HandleStartMenuInput(void) if (GetNationalPokedexCount(FLAG_GET_SEEN) == 0) return FALSE; } - + if (sCurrentStartMenuActions[sStartMenuCursorPos] == MENU_ACTION_DEXNAV + && MapHasNoEncounterData()) + return FALSE; + gMenuCallback = sStartMenuItems[sCurrentStartMenuActions[sStartMenuCursorPos]].func.u8_void; if (gMenuCallback != StartMenuSaveCallback @@ -663,7 +669,7 @@ static bool8 HandleStartMenuInput(void) return FALSE; } -static bool8 StartMenuPokedexCallback(void) +bool8 StartMenuPokedexCallback(void) { if (!gPaletteFade.active) { @@ -1485,3 +1491,9 @@ void AppendToList(u8 *list, u8 *pos, u8 newEntry) list[*pos] = newEntry; (*pos)++; } + +static bool8 StartMenuDexNavCallback(void) +{ + CreateTask(Task_OpenDexNavFromStartMenu, 0); + return TRUE; +} diff --git a/src/strings.c b/src/strings.c index fb3c96eb9db8..37feea0da091 100644 --- a/src/strings.c +++ b/src/strings.c @@ -1023,6 +1023,7 @@ const u8 gText_MenuOption[] = _("OPTION"); const u8 gText_MenuExit[] = _("EXIT"); const u8 gText_MenuRetire[] = _("RETIRE"); const u8 gText_MenuRest[] = _("REST"); +const u8 gText_MenuDexNav[] = _("DEXNAV"); const u8 gText_SafariBallStock[] = _("SAFARI BALLS\nStock: {STR_VAR_1}"); const u8 gText_BattlePyramidFloor[] = _("Battle Pyramid\n{STR_VAR_1}"); const u8 gText_Floor1[] = _("Floor 1"); diff --git a/src/text_window.c b/src/text_window.c index efd087977eb8..a1bae0d123d5 100644 --- a/src/text_window.c +++ b/src/text_window.c @@ -82,6 +82,9 @@ static const struct TilesPal sWindowFrames[WINDOW_FRAMES_COUNT] = {sTextWindowFrame20_Gfx, sTextWindowFrame20_Pal} }; +static const u16 sTextWindowDexNavFrame[] = INCBIN_U16("graphics/text_window/dexnav_pal.gbapal"); +static const struct TilesPal sDexNavWindowFrame = {gTextWindowFrame1_Gfx, sTextWindowDexNavFrame}; + // code const struct TilesPal *GetWindowFrameTilesPal(u8 id) { @@ -202,3 +205,9 @@ void LoadUserWindowBorderGfxOnBg(u8 bg, u16 destOffset, u8 palOffset) LoadBgTiles(bg, sWindowFrames[gSaveBlock2Ptr->optionsWindowFrameType].tiles, 0x120, destOffset); LoadPalette(GetWindowFrameTilesPal(gSaveBlock2Ptr->optionsWindowFrameType)->pal, palOffset, PLTT_SIZE_4BPP); } + +void LoadDexNavWindowGfx(u8 windowId, u16 destOffset, u8 palOffset) +{ + LoadBgTiles(GetWindowAttribute(windowId, WINDOW_BG), sDexNavWindowFrame.tiles, 0x120, destOffset); + LoadPalette(sDexNavWindowFrame.pal, palOffset, 32); +} diff --git a/src/trainer_hill.c b/src/trainer_hill.c index c89803ffb25a..dd8ae78aa774 100644 --- a/src/trainer_hill.c +++ b/src/trainer_hill.c @@ -212,6 +212,14 @@ static const struct TrainerHillChallenge *const sChallengeData[NUM_TRAINER_HILL_ [HILL_MODE_EXPERT] = &sChallenge_Expert, }; +static const struct TrainerHillFloor *const sFloorData[NUM_TRAINER_HILL_MODES] = +{ + [HILL_MODE_NORMAL] = &sFloors_Normal[0], + [HILL_MODE_VARIETY] = &sFloors_Variety[0], + [HILL_MODE_UNIQUE] = &sFloors_Unique[0], + [HILL_MODE_EXPERT] = &sFloors_Expert[0], +}; + // Unused. static const u8 *const sFloorStrings[] = { @@ -357,20 +365,14 @@ void FreeTrainerHillBattleStruct(void) static void SetUpDataStruct(void) { #if FREE_TRAINER_HILL == FALSE - if (sHillData == NULL) - { - sHillData = AllocZeroed(sizeof(*sHillData)); - sHillData->floorId = gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F; - - // This copy depends on the floor data for each challenge being directly after the - // challenge header data, and for the field 'floors' in sHillData to come directly - // after the field 'challenge'. - // e.g. for HILL_MODE_NORMAL, it will copy sChallenge_Normal to sHillData->challenge and - // it will copy sFloors_Normal to sHillData->floors - CpuCopy32(sChallengeData[gSaveBlock1Ptr->trainerHill.mode], &sHillData->challenge, sizeof(sHillData->challenge) + sizeof(sHillData->floors)); - TrainerHillDummy(); - } -#endif //FREE_TRAINER_HILL + if (sHillData != NULL) return; + + sHillData = AllocZeroed(sizeof(*sHillData)); + sHillData->floorId = gMapHeader.mapLayoutId - LAYOUT_TRAINER_HILL_1F; + + CpuCopy32(sChallengeData[gSaveBlock1Ptr->trainerHill.mode], &sHillData->challenge, sizeof(sHillData->challenge)); + CpuCopy32(sFloorData[gSaveBlock1Ptr->trainerHill.mode], &sHillData->floors, sizeof(sHillData->floors)); +#endif // FREE_TRAINER_HILL } static void FreeDataStruct(void) diff --git a/src/trainer_see.c b/src/trainer_see.c index 2582637aa186..12c6cba61215 100644 --- a/src/trainer_see.c +++ b/src/trainer_see.c @@ -2,6 +2,7 @@ #include "battle_setup.h" #include "event_data.h" #include "event_object_movement.h" +#include "event_scripts.h" #include "field_effect.h" #include "field_player_avatar.h" #include "pokemon.h" @@ -375,6 +376,16 @@ bool8 CheckForTrainersWantingBattle(void) continue; numTrainers = CheckTrainer(i); + if (numTrainers == 0xFF) // non-trainerbatle script + { + u32 objectEventId = gApproachingTrainers[gNoOfApproachingTrainers - 1].objectEventId; + gSelectedObjectEvent = objectEventId; + gSpecialVar_LastTalked = gObjectEvents[objectEventId].localId; + ScriptContext_SetupScript(EventScript_ObjectApproachPlayer); + LockPlayerFieldControls(); + return TRUE; + } + if (numTrainers == 2) break; @@ -417,14 +428,33 @@ bool8 CheckForTrainersWantingBattle(void) static u8 CheckTrainer(u8 objectEventId) { - const u8 *scriptPtr; + const u8 *scriptPtr, *trainerBattlePtr; u8 numTrainers = 1; - u8 approachDistance; + + u8 approachDistance = GetTrainerApproachDistance(&gObjectEvents[objectEventId]); + if (approachDistance == 0) + return 0; if (InTrainerHill() == TRUE) - scriptPtr = GetTrainerHillTrainerScript(); + { + trainerBattlePtr = scriptPtr = GetTrainerHillTrainerScript(); + } else - scriptPtr = GetObjectEventScriptPointerByObjectEventId(objectEventId); + { + trainerBattlePtr = scriptPtr = GetObjectEventScriptPointerByObjectEventId(objectEventId); + struct ScriptContext ctx; + if (RunScriptImmediatelyUntilEffect(SCREFF_V1 | SCREFF_SAVE | SCREFF_HARDWARE | SCREFF_TRAINERBATTLE, scriptPtr, &ctx)) + { + if (*ctx.scriptPtr == 0x5c) // trainerbattle + trainerBattlePtr = ctx.scriptPtr; + else + trainerBattlePtr = NULL; + } + else + { + return 0; // no effect + } + } if (InBattlePyramid()) { @@ -436,36 +466,36 @@ static u8 CheckTrainer(u8 objectEventId) if (GetHillTrainerFlag(objectEventId)) return 0; } - else + else if (trainerBattlePtr) { - if (GetTrainerFlagFromScriptPointer(scriptPtr)) + if (GetTrainerFlagFromScriptPointer(trainerBattlePtr)) return 0; } + else + { + numTrainers = 0xFF; + } - approachDistance = GetTrainerApproachDistance(&gObjectEvents[objectEventId]); - - if (approachDistance != 0) + if (trainerBattlePtr) { - if (scriptPtr[1] == TRAINER_BATTLE_DOUBLE - || scriptPtr[1] == TRAINER_BATTLE_REMATCH_DOUBLE - || scriptPtr[1] == TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE) + if (trainerBattlePtr[1] == TRAINER_BATTLE_DOUBLE + || trainerBattlePtr[1] == TRAINER_BATTLE_REMATCH_DOUBLE + || trainerBattlePtr[1] == TRAINER_BATTLE_CONTINUE_SCRIPT_DOUBLE) { if (GetMonsStateToDoubles_2() != PLAYER_HAS_TWO_USABLE_MONS) return 0; numTrainers = 2; } - - gApproachingTrainers[gNoOfApproachingTrainers].objectEventId = objectEventId; - gApproachingTrainers[gNoOfApproachingTrainers].trainerScriptPtr = scriptPtr; - gApproachingTrainers[gNoOfApproachingTrainers].radius = approachDistance; - InitTrainerApproachTask(&gObjectEvents[objectEventId], approachDistance - 1); - gNoOfApproachingTrainers++; - - return numTrainers; } - return 0; + gApproachingTrainers[gNoOfApproachingTrainers].objectEventId = objectEventId; + gApproachingTrainers[gNoOfApproachingTrainers].trainerScriptPtr = scriptPtr; + gApproachingTrainers[gNoOfApproachingTrainers].radius = approachDistance; + InitTrainerApproachTask(&gObjectEvents[objectEventId], approachDistance - 1); + gNoOfApproachingTrainers++; + + return numTrainers; } static u8 GetTrainerApproachDistance(struct ObjectEvent *trainerObj) diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 033eec56daef..bd00e58fcd20 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -186,7 +186,7 @@ static void FeebasSeedRng(u16 seed) } // LAND_WILD_COUNT -static u8 ChooseWildMonIndex_Land(void) +u8 ChooseWildMonIndex_Land(void) { u8 wildMonIndex = 0; bool8 swap = FALSE; @@ -227,7 +227,7 @@ static u8 ChooseWildMonIndex_Land(void) } // ROCK_WILD_COUNT / WATER_WILD_COUNT -static u8 ChooseWildMonIndex_WaterRock(void) +u8 ChooseWildMonIndex_WaterRock(void) { u8 wildMonIndex = 0; bool8 swap = FALSE; @@ -354,7 +354,7 @@ static u8 ChooseWildMonLevel(const struct WildPokemon *wildPokemon, u8 wildMonIn } } -static u16 GetCurrentMapWildMonHeaderId(void) +u16 GetCurrentMapWildMonHeaderId(void) { u16 i; @@ -417,7 +417,7 @@ u8 PickWildMonNature(void) return Random() % NUM_NATURES; } -static void CreateWildMon(u16 species, u8 level) +void CreateWildMon(u16 species, u8 level) { bool32 checkCuteCharm = TRUE; @@ -1134,3 +1134,24 @@ bool8 StandardWildEncounter_Debug(void) DoStandardWildBattle_Debug(); return TRUE; } + +u8 ChooseHiddenMonIndex(void) +{ + #ifdef ENCOUNTER_CHANCE_HIDDEN_MONS_TOTAL + u8 rand = Random() % ENCOUNTER_CHANCE_HIDDEN_MONS_TOTAL; + + if (rand < ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_0) + return 0; + else if (rand >= ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_0 && rand < ENCOUNTER_CHANCE_HIDDEN_MONS_SLOT_1) + return 1; + else + return 2; + #else + return 0xFF; + #endif +} + +bool32 MapHasNoEncounterData(void) +{ + return (GetCurrentMapWildMonHeaderId() == HEADER_NONE); +} diff --git a/test/battle/ability/aerilate.c b/test/battle/ability/aerilate.c index 4386034a59f1..efd6776d9ba7 100644 --- a/test/battle/ability/aerilate.c +++ b/test/battle/ability/aerilate.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); } SINGLE_BATTLE_TEST("Aerilate turns a Normal-type move into Flying-type move") diff --git a/test/battle/ability/anger_point.c b/test/battle/ability/anger_point.c index b803b40f3fcf..7e8be8cb3378 100644 --- a/test/battle/ability/anger_point.c +++ b/test/battle/ability/anger_point.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Anger Point raises Attack stage to maximum after receiving a critical hit") { GIVEN { - ASSUME(gMovesInfo[MOVE_FROST_BREATH].alwaysCriticalHit); + ASSUME(MoveAlwaysCrits(MOVE_FROST_BREATH)); PLAYER(SPECIES_PRIMEAPE) { Ability(ABILITY_ANGER_POINT); } OPPONENT(SPECIES_SNORUNT); } WHEN { @@ -23,8 +23,8 @@ SINGLE_BATTLE_TEST("Anger Point raises Attack stage to maximum after receiving a SINGLE_BATTLE_TEST("Anger Point does not trigger when already at maximum Attack stage") { GIVEN { - ASSUME(gMovesInfo[MOVE_FROST_BREATH].alwaysCriticalHit); - ASSUME(gMovesInfo[MOVE_BELLY_DRUM].effect == EFFECT_BELLY_DRUM); + ASSUME(MoveAlwaysCrits(MOVE_FROST_BREATH)); + ASSUME(GetMoveEffect(MOVE_BELLY_DRUM) == EFFECT_BELLY_DRUM); PLAYER(SPECIES_PRIMEAPE) { Ability(ABILITY_ANGER_POINT); Speed(2); } OPPONENT(SPECIES_SNORUNT) { Speed(1); } } WHEN { @@ -50,8 +50,8 @@ TO_DO_BATTLE_TEST("Anger Point triggers when a substitute takes the hit (Gen4)") SINGLE_BATTLE_TEST("Anger Point does not trigger when a substitute takes the hit (Gen5+)") { GIVEN { - ASSUME(gMovesInfo[MOVE_FROST_BREATH].alwaysCriticalHit); - ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE); + ASSUME(MoveAlwaysCrits(MOVE_FROST_BREATH)); + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); PLAYER(SPECIES_PRIMEAPE) { Ability(ABILITY_ANGER_POINT); Speed(2); } OPPONENT(SPECIES_SNORUNT) { Speed(1); } } WHEN { diff --git a/test/battle/ability/anger_shell.c b/test/battle/ability/anger_shell.c index cf28fad28c07..0dde568ca088 100644 --- a/test/battle/ability/anger_shell.c +++ b/test/battle/ability/anger_shell.c @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Anger Shell activates only if the target had more than 50% o PARAMETRIZE { hp = 254; activates = TRUE; } GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(hp); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Anger Shell lowers Def/Sp.Def by 1 and raises Atk/Sp.Atk/Spd { u16 maxHp = 500; GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -73,7 +73,7 @@ SINGLE_BATTLE_TEST("Anger Shell activates after all hits from a multi-hit move") u32 j; u16 maxHp = 500; GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SLAP) == EFFECT_MULTI_HIT); PLAYER(SPECIES_KLAWF) { Ability(ABILITY_ANGER_SHELL); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times. } WHEN { diff --git a/test/battle/ability/battle_bond.c b/test/battle/ability/battle_bond.c index ef2b2753b3b4..f48036779818 100644 --- a/test/battle/ability/battle_bond.c +++ b/test/battle/ability/battle_bond.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(!IS_MOVE_STATUS(MOVE_WATER_GUN)); + ASSUME(!IsBattleMoveStatus(MOVE_WATER_GUN)); } SINGLE_BATTLE_TEST("Battle Bond does not transform species other than Greninja") diff --git a/test/battle/ability/beads_of_ruin.c b/test/battle/ability/beads_of_ruin.c index bbc71f6c2b34..63b07d7c8a62 100644 --- a/test/battle/ability/beads_of_ruin.c +++ b/test/battle/ability/beads_of_ruin.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_ROLE_PLAY].effect == EFFECT_ROLE_PLAY); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_ROLE_PLAY) == EFFECT_ROLE_PLAY); } SINGLE_BATTLE_TEST("Beads of Ruin reduces Sp. Def if opposing mon's ability doesn't match") @@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Beads of Ruin reduces Sp. Def if opposing mon's ability does SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battlers fainted - Player") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} PLAYER(SPECIES_CHI_YU); OPPONENT(SPECIES_WOBBUFFET); @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battler SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battlers fainted - Opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} diff --git a/test/battle/ability/berserk.c b/test/battle/ability/berserk.c index 7d7f905170ee..c96bb260f84e 100644 --- a/test/battle/ability/berserk.c +++ b/test/battle/ability/berserk.c @@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Berserk activates only if the target had more than 50% of it PARAMETRIZE { hp = 254; activates = TRUE; } GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(hp); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Berserk raises Sp.Atk by 1") { u16 maxHp = 500; GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -57,7 +57,7 @@ SINGLE_BATTLE_TEST("Berserk activates after all hits from a multi-hit move") u32 j; u16 maxHp = 500; GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SLAP) == EFFECT_MULTI_HIT); PLAYER(SPECIES_DRAMPA) { Ability(ABILITY_BERSERK); MaxHP(maxHp); HP(maxHp / 2 + 1); } OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } // Always hits 5 times. } WHEN { diff --git a/test/battle/ability/blaze.c b/test/battle/ability/blaze.c index a21d133359bf..c68c7466a165 100644 --- a/test/battle/ability/blaze.c +++ b/test/battle/ability/blaze.c @@ -7,7 +7,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 { diff --git a/test/battle/ability/clear_body.c b/test/battle/ability/clear_body.c index 1e955431a1b6..89b89e96bf31 100644 --- a/test/battle/ability/clear_body.c +++ b/test/battle/ability/clear_body.c @@ -58,13 +58,13 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent stat st } GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); - ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); - ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_LEER) == EFFECT_DEFENSE_DOWN); + ASSUME(GetMoveEffect(MOVE_CONFIDE) == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_FAKE_TEARS) == EFFECT_SPECIAL_DEFENSE_DOWN_2); + ASSUME(GetMoveEffect(MOVE_SCARY_FACE) == EFFECT_SPEED_DOWN_2); + ASSUME(GetMoveEffect(MOVE_SWEET_SCENT) == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) OPPONENT(species) { Ability(ability); } } WHEN { @@ -91,7 +91,7 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke prevent Sticky PARAMETRIZE{ species = SPECIES_SOLGALEO; ability = ABILITY_FULL_METAL_BODY; } PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } GIVEN { - ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); + ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_WOBBUFFET) OPPONENT(species) { Ability(ability); } @@ -166,13 +166,13 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body and } GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); - ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); - ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_LEER) == EFFECT_DEFENSE_DOWN); + ASSUME(GetMoveEffect(MOVE_CONFIDE) == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_FAKE_TEARS) == EFFECT_SPECIAL_DEFENSE_DOWN_2); + ASSUME(GetMoveEffect(MOVE_SCARY_FACE) == EFFECT_SPEED_DOWN_2); + ASSUME(GetMoveEffect(MOVE_SWEET_SCENT) == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET) { Ability(breakerAbility); } OPPONENT(species) { Ability(ability); } } WHEN { @@ -284,7 +284,7 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent A PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; burned = FALSE; } PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; burned = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) OPPONENT(species) { Ability(ability); if (burned) Status1(STATUS1_BURN); } } WHEN { @@ -306,8 +306,8 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent r PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_SCARY_FACE) == EFFECT_SPEED_DOWN_2); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } OPPONENT(species) { Speed(6); Ability(ability); } @@ -336,9 +336,9 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent T PARAMETRIZE{ species = SPECIES_TORKOAL; ability = ABILITY_WHITE_SMOKE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY); - ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_TOPSY_TURVY) == EFFECT_TOPSY_TURVY); + ASSUME(GetMoveEffect(MOVE_SCARY_FACE) == EFFECT_SPEED_DOWN_2); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } OPPONENT(species) { Speed(6); Ability(ability); } @@ -378,7 +378,7 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent S GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF) == TRUE); - ASSUME(gMovesInfo[MOVE_AGILITY].effect == EFFECT_SPEED_UP_2); + ASSUME(GetMoveEffect(MOVE_AGILITY) == EFFECT_SPEED_UP_2); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(species) { Speed(5); Ability(ability); } } WHEN { diff --git a/test/battle/ability/cloud_nine.c b/test/battle/ability/cloud_nine.c index fb87b7f2ba35..613ea86e0acf 100644 --- a/test/battle/ability/cloud_nine.c +++ b/test/battle/ability/cloud_nine.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Cloud Nine/Air Lock prevent basic weather effects, but witho PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_CLOUD_NINE; } PARAMETRIZE { species = SPECIES_RAYQUAZA; ability = ABILITY_AIR_LOCK; } GIVEN { - ASSUME(gMovesInfo[MOVE_SANDSTORM].effect == EFFECT_SANDSTORM); + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/commander.c b/test/battle/ability/commander.c index 26f5574ba827..2220fb9ec204 100644 --- a/test/battle/ability/commander.c +++ b/test/battle/ability/commander.c @@ -175,7 +175,7 @@ DOUBLE_BATTLE_TEST("Commander prevents Red Card from working while Commander is DOUBLE_BATTLE_TEST("Commander Tatsugiri is not damaged by a double target move if Dondozo faints") { GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_DONDOZO) { HP(1); }; PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } PLAYER(SPECIES_WYNAUT); @@ -308,7 +308,7 @@ DOUBLE_BATTLE_TEST("Commander Tatsugiri is still affected by Haze while controll DOUBLE_BATTLE_TEST("Commander Attacker is kept (Dondozo Left Slot)") { GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } PLAYER(SPECIES_DONDOZO); @@ -331,7 +331,7 @@ DOUBLE_BATTLE_TEST("Commander Attacker is kept (Dondozo Left Slot)") DOUBLE_BATTLE_TEST("Commander Attacker is kept (Dondozo Right Slot)") { GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_DONDOZO); @@ -380,7 +380,7 @@ DOUBLE_BATTLE_TEST("Commander Tatsugiri does not attack if Dondozo faints the sa DOUBLE_BATTLE_TEST("Commander Tatsugiri does not get hit by Dragon Darts when a commanded Dondozo faints") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DARTS].effect == EFFECT_DRAGON_DARTS); + ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_DONDOZO) { HP(1); } PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } @@ -402,7 +402,7 @@ DOUBLE_BATTLE_TEST("Commander Tatsugiri does not get hit by Dragon Darts when co PARAMETRIZE { targetPlayerRight = TRUE; } PARAMETRIZE { targetPlayerRight = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DARTS].effect == EFFECT_DRAGON_DARTS); + ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS); PLAYER(SPECIES_TATSUGIRI) { Ability(ABILITY_COMMANDER); } PLAYER(SPECIES_DONDOZO); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/compound_eyes.c b/test/battle/ability/compound_eyes.c index 32fa1dda2edf..338da6bf21d9 100644 --- a/test/battle/ability/compound_eyes.c +++ b/test/battle/ability/compound_eyes.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Compound Eyes raises accuracy") { PASSES_RANDOMLY(91, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDER].accuracy == 70); + ASSUME(GetMoveAccuracy(MOVE_THUNDER) == 70); PLAYER(SPECIES_BUTTERFREE) { Ability(ABILITY_COMPOUND_EYES); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -20,8 +20,8 @@ SINGLE_BATTLE_TEST("Compound Eyes does not affect OHKO moves") { PASSES_RANDOMLY(30, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_FISSURE].accuracy == 30); - ASSUME(gMovesInfo[MOVE_FISSURE].effect == EFFECT_OHKO); + ASSUME(GetMoveAccuracy(MOVE_FISSURE) == 30); + ASSUME(GetMoveEffect(MOVE_FISSURE) == EFFECT_OHKO); PLAYER(SPECIES_BUTTERFREE) { Ability(ABILITY_COMPOUND_EYES); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/contrary.c b/test/battle/ability/contrary.c index 56eb6abf6521..3c9c3e6dff9b 100644 --- a/test/battle/ability/contrary.c +++ b/test/battle/ability/contrary.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Contrary raises Attack when Intimidated in a single battle", s16 damage) @@ -83,7 +83,7 @@ SINGLE_BATTLE_TEST("Contrary raises stats after using a move which would normall PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { ASSUME(MoveHasAdditionalEffectSelf(MOVE_OVERHEAT, MOVE_EFFECT_SP_ATK_MINUS_2) == TRUE); - ASSUME(gMovesInfo[MOVE_OVERHEAT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_OVERHEAT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_SPINDA) { Ability(ability); } } WHEN { @@ -126,7 +126,7 @@ SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normal PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_WOBBUFFET) { Defense(102); } OPPONENT(SPECIES_SPINDA) { Ability(ability); Attack(100); } } WHEN { @@ -163,7 +163,7 @@ SINGLE_BATTLE_TEST("Contrary raises a stat after using a move which would normal PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); PLAYER(SPECIES_WOBBUFFET) { Speed(3); } OPPONENT(SPECIES_SPINDA) { Ability(ability); Speed(2); } } WHEN { @@ -194,7 +194,7 @@ SINGLE_BATTLE_TEST("Contrary lowers a stat after using a move which would normal PARAMETRIZE { ability = ABILITY_CONTRARY; } PARAMETRIZE { ability = ABILITY_TANGLED_FEET; } GIVEN { - ASSUME(gMovesInfo[MOVE_BELLY_DRUM].effect == EFFECT_BELLY_DRUM); + ASSUME(GetMoveEffect(MOVE_BELLY_DRUM) == EFFECT_BELLY_DRUM); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_SPINDA) { Ability(ability); } } WHEN { diff --git a/test/battle/ability/corrosion.c b/test/battle/ability/corrosion.c index 8addbd90faab..8541c21f271e 100644 --- a/test/battle/ability/corrosion.c +++ b/test/battle/ability/corrosion.c @@ -30,8 +30,8 @@ SINGLE_BATTLE_TEST("Corrosion can poison or badly poison a Steel type with a sta PARAMETRIZE { move = MOVE_TOXIC; } GIVEN { - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); } OPPONENT(SPECIES_BELDUM); } WHEN { @@ -72,7 +72,7 @@ SINGLE_BATTLE_TEST("Corrosion can poison Poison- and Steel-type targets if it us PARAMETRIZE { heldItem = ITEM_TOXIC_ORB; } GIVEN { - ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING); + ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING); ASSUME(gItemsInfo[ITEM_POISON_BARB].holdEffect == HOLD_EFFECT_POISON_POWER); ASSUME(gItemsInfo[ITEM_TOXIC_ORB].holdEffect == HOLD_EFFECT_TOXIC_ORB); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); Item(heldItem); } @@ -110,8 +110,8 @@ SINGLE_BATTLE_TEST("If a Poison- or Steel-type Pokémon with Corrosion poisons a PARAMETRIZE { move = MOVE_TOXIC; } PARAMETRIZE { move = MOVE_POISON_POWDER; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); } OPPONENT(SPECIES_ABRA) { Ability(ABILITY_SYNCHRONIZE); } } WHEN { @@ -137,8 +137,8 @@ SINGLE_BATTLE_TEST("Corrosion cannot bypass moves that prevent poisoning such as PARAMETRIZE { move = MOVE_TOXIC; } PARAMETRIZE { move = MOVE_POISON_POWDER; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -159,8 +159,8 @@ SINGLE_BATTLE_TEST("Corrosion cannot bypass abilities that prevent poisoning suc PARAMETRIZE { move = MOVE_TOXIC; } PARAMETRIZE { move = MOVE_POISON_POWDER; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); } OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_IMMUNITY); } } WHEN { @@ -181,9 +181,9 @@ SINGLE_BATTLE_TEST("Corrosion allows the Pokémon with the ability to poison a S PARAMETRIZE { move = MOVE_TOXIC; } PARAMETRIZE { move = MOVE_POISON_POWDER; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); - ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); } OPPONENT(SPECIES_BELDUM); } WHEN { @@ -205,9 +205,9 @@ SINGLE_BATTLE_TEST("Corrosion's effect is lost if the move used by the Pokémon PARAMETRIZE { move = MOVE_TOXIC; } PARAMETRIZE { move = MOVE_POISON_POWDER; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); - ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); PLAYER(SPECIES_SALANDIT) { Ability(ABILITY_CORROSION); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/cud_chew.c b/test/battle/ability/cud_chew.c index b3dd92ecd5f9..9ac5593474aa 100644 --- a/test/battle/ability/cud_chew.c +++ b/test/battle/ability/cud_chew.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Cud Chew will activate Kee Berry effect again on the next tu { GIVEN { ASSUME(gItemsInfo[ITEM_KEE_BERRY].holdEffect == HOLD_EFFECT_KEE_BERRY); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TAUROS_PALDEA_COMBAT) { Ability(ABILITY_CUD_CHEW); Item(ITEM_KEE_BERRY); } } WHEN { @@ -28,8 +28,8 @@ SINGLE_BATTLE_TEST("Cud Chew will activate Oran Berry effect again on the next t GIVEN { ASSUME(gItemsInfo[ITEM_ORAN_BERRY].holdEffect == HOLD_EFFECT_RESTORE_HP); ASSUME(gItemsInfo[ITEM_ORAN_BERRY].holdEffectParam == 10); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TAUROS_PALDEA_COMBAT) { MaxHP(60); HP(60); Ability(ABILITY_CUD_CHEW); Item(ITEM_ORAN_BERRY); } } WHEN { diff --git a/test/battle/ability/cute_charm.c b/test/battle/ability/cute_charm.c index e6eee0ae0862..55e64b3226b5 100644 --- a/test/battle/ability/cute_charm.c +++ b/test/battle/ability/cute_charm.c @@ -7,15 +7,15 @@ SINGLE_BATTLE_TEST("Cute Charm inflicts infatuation on contact") PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_SWIFT)); PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); } OPPONENT(SPECIES_CLEFAIRY) { Gender(MON_FEMALE); Ability(ABILITY_CUTE_CHARM); } } WHEN { TURN { MOVE(player, move); } TURN { MOVE(player, move); } } SCENE { - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(opponent, ABILITY_CUTE_CHARM); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_INFATUATION, player); MESSAGE("The opposing Clefairy's Cute Charm infatuated Wobbuffet!"); @@ -51,7 +51,7 @@ SINGLE_BATTLE_TEST("Cute Charm triggers 30% of the time") PASSES_RANDOMLY(3, 10, RNG_CUTE_CHARM); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET) { Gender(MON_MALE); } OPPONENT(SPECIES_CLEFAIRY) { Gender(MON_FEMALE); Ability(ABILITY_CUTE_CHARM); } } WHEN { diff --git a/test/battle/ability/damp.c b/test/battle/ability/damp.c index b567293aa09b..1088a7a17e92 100644 --- a/test/battle/ability/damp.c +++ b/test/battle/ability/damp.c @@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Damp prevents explosion-like moves from self") SINGLE_BATTLE_TEST("Damp prevents damage from Aftermath") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_PARAS) { Ability(ABILITY_DAMP); } OPPONENT(SPECIES_VOLTORB) { Ability(ABILITY_AFTERMATH); HP(1); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/dancer.c b/test/battle/ability/dancer.c index 5519ac3222c4..657a126470ee 100644 --- a/test/battle/ability/dancer.c +++ b/test/battle/ability/dancer.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Dancer can copy a dance move immediately after it was used and allow the user of Dancer to still use its move") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUIVER_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_QUIVER_DANCE)); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } } WHEN { @@ -22,7 +22,7 @@ SINGLE_BATTLE_TEST("Dancer can copy a dance move immediately after it was used a SINGLE_BATTLE_TEST("Dancer can copy Teeter Dance") { GIVEN { - ASSUME(gMovesInfo[MOVE_TEETER_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_TEETER_DANCE)); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Item(ITEM_LUM_BERRY); } } WHEN { @@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Dancer can copy Teeter Dance") DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targets") { GIVEN { - ASSUME(gMovesInfo[MOVE_TEETER_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_TEETER_DANCE)); ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); PLAYER(SPECIES_WOBBUFFET) PLAYER(SPECIES_WYNAUT) { Item(ITEM_LUM_BERRY); } @@ -57,7 +57,7 @@ DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targe DOUBLE_BATTLE_TEST("Dancer triggers from slowest to fastest") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); } PLAYER(SPECIES_WYNAUT) { Speed(50); } OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } @@ -83,7 +83,7 @@ SINGLE_BATTLE_TEST("Dancer doesn't trigger if the original user flinches") { GIVEN { ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); } } WHEN { @@ -102,7 +102,7 @@ DOUBLE_BATTLE_TEST("Dancer still triggers if another dancer flinches") { GIVEN { ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Speed(10); } PLAYER(SPECIES_WYNAUT) { Speed(5); } OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Speed(20); } @@ -130,8 +130,8 @@ DOUBLE_BATTLE_TEST("Dancer still triggers if another dancer flinches") SINGLE_BATTLE_TEST("Dancer-called attacks have their type updated") { GIVEN { - ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].danceMove == TRUE); - ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].effect == EFFECT_REVELATION_DANCE); + ASSUME(IsDanceMove(MOVE_REVELATION_DANCE)); + ASSUME(GetMoveEffect(MOVE_REVELATION_DANCE) == EFFECT_REVELATION_DANCE); PLAYER(SPECIES_TANGROWTH); OPPONENT(SPECIES_ORICORIO_BAILE); } WHEN { @@ -149,8 +149,8 @@ SINGLE_BATTLE_TEST("Dancer-called attacks have their type updated") DOUBLE_BATTLE_TEST("Dancer doesn't trigger on a snatched move") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); - ASSUME(gMovesInfo[MOVE_SNATCH].effect == EFFECT_SNATCH); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(GetMoveEffect(MOVE_SNATCH) == EFFECT_SNATCH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ORICORIO); @@ -173,9 +173,9 @@ DOUBLE_BATTLE_TEST("Dancer doesn't trigger on a snatched move") DOUBLE_BATTLE_TEST("Dancer triggers on Instructed dance moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].instructBanned == FALSE); - ASSUME(gMovesInfo[MOVE_INSTRUCT].effect == EFFECT_INSTRUCT); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(!IsMoveInstructBanned(MOVE_DRAGON_DANCE)); + ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ORICORIO); @@ -200,9 +200,9 @@ DOUBLE_BATTLE_TEST("Dancer triggers on Instructed dance moves") DOUBLE_BATTLE_TEST("Dancer-called move doesn't update move to be Instructed") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); - ASSUME(gMovesInfo[MOVE_TACKLE].instructBanned == FALSE); - ASSUME(gMovesInfo[MOVE_INSTRUCT].effect == EFFECT_INSTRUCT); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); + ASSUME(!IsMoveInstructBanned(MOVE_TACKLE)); + ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ORICORIO); @@ -228,8 +228,8 @@ DOUBLE_BATTLE_TEST("Dancer-called move doesn't update move to be Instructed") DOUBLE_BATTLE_TEST("Dancer doesn't call a move that didn't execute due to Powder") { GIVEN { - ASSUME(gMovesInfo[MOVE_FIERY_DANCE].danceMove == TRUE); - ASSUME(gMovesInfo[MOVE_FIERY_DANCE].type == TYPE_FIRE); + ASSUME(IsDanceMove(MOVE_FIERY_DANCE)); + ASSUME(GetMoveType(MOVE_FIERY_DANCE) == TYPE_FIRE); PLAYER(SPECIES_VOLCARONA); PLAYER(SPECIES_ORICORIO); OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/ability/dazzling.c b/test/battle/ability/dazzling.c index 9eedb56a4957..cc77e9a3bdee 100644 --- a/test/battle/ability/dazzling.c +++ b/test/battle/ability/dazzling.c @@ -4,7 +4,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority > 0); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) > 0); } DOUBLE_BATTLE_TEST("Dazzling, Queenly Majesty and Armor Tail protect the user from priority moves") diff --git a/test/battle/ability/defeatist.c b/test/battle/ability/defeatist.c index d2866d6f300b..18d8186a50e8 100644 --- a/test/battle/ability/defeatist.c +++ b/test/battle/ability/defeatist.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_ECHOED_VOICE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_ECHOED_VOICE) == DAMAGE_CATEGORY_SPECIAL); } SINGLE_BATTLE_TEST("Defeatist halves Attack when HP <= 50%", s16 damage) diff --git a/test/battle/ability/defiant.c b/test/battle/ability/defiant.c index 9b767b8323c2..b1bd1024531e 100644 --- a/test/battle/ability/defiant.c +++ b/test/battle/ability/defiant.c @@ -277,7 +277,7 @@ SINGLE_BATTLE_TEST("Defiant activates before White Herb") SINGLE_BATTLE_TEST("Defiant activates for each stat that is lowered") { GIVEN { - ASSUME(gMovesInfo[MOVE_TICKLE].effect == EFFECT_TICKLE); + ASSUME(GetMoveEffect(MOVE_TICKLE) == EFFECT_TICKLE); PLAYER(SPECIES_MANKEY) { Ability(ABILITY_DEFIANT); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/desolate_land.c b/test/battle/ability/desolate_land.c index 18fe76b0c905..5bf1358503b1 100644 --- a/test/battle/ability/desolate_land.c +++ b/test/battle/ability/desolate_land.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(!IS_MOVE_STATUS(MOVE_WATER_GUN)); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(!IsBattleMoveStatus(MOVE_WATER_GUN)); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); } SINGLE_BATTLE_TEST("Desolate Land blocks damaging Water-type moves") @@ -32,9 +32,9 @@ SINGLE_BATTLE_TEST("Desolate Land blocks damaging Water-type moves") DOUBLE_BATTLE_TEST("Desolate Land blocks damaging Water-type moves and prints the message only once with moves hitting multiple targets") { GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_SURF)); - ASSUME(gMovesInfo[MOVE_SURF].type == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(!IsBattleMoveStatus(MOVE_SURF)); + ASSUME(GetMoveType(MOVE_SURF) == TYPE_WATER); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_GROUDON) {Item(ITEM_RED_ORB); {Speed(5);}} PLAYER(SPECIES_WOBBUFFET) {Speed(5);} OPPONENT(SPECIES_WOBBUFFET) {Speed(10);} diff --git a/test/battle/ability/disguise.c b/test/battle/ability/disguise.c index 9c5f917e9db0..b1d854f0cfe0 100644 --- a/test/battle/ability/disguise.c +++ b/test/battle/ability/disguise.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_AERIAL_ACE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_AERIAL_ACE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Disguised Mimikyu will lose 1/8 of its max HP upon changing to its busted form") @@ -28,7 +28,7 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu will lose 1/8 of its max HP upon changing SINGLE_BATTLE_TEST("Disguised Mimikyu takes no damage from a confusion hit and changes to its busted form") { GIVEN { - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -69,7 +69,7 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu's Air Balloon will pop upon changing to it SINGLE_BATTLE_TEST("Disguised Mimikyu takes damage from secondary damage without breaking the disguise") { GIVEN { - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK); + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); } OPPONENT(SPECIES_WOBBUFFET); @@ -138,7 +138,7 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu is ignored by Mold Breaker") SINGLE_BATTLE_TEST("Disguised Mimikyu's types revert back to Ghost/Fairy when Disguise is broken") { GIVEN { - ASSUME(gMovesInfo[MOVE_SHADOW_CLAW].type == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_SHADOW_CLAW) == TYPE_GHOST); PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -158,7 +158,7 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu's types revert back to Ghost/Fairy when Di SINGLE_BATTLE_TEST("Disguised Mimikyu blocks a move after getting Gastro Acid Batton Passed") { GIVEN { - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); } OPPONENT(SPECIES_WOBBUFFET); @@ -177,7 +177,7 @@ SINGLE_BATTLE_TEST("Disguised Mimikyu blocks a move after getting Gastro Acid Ba SINGLE_BATTLE_TEST("Disguise does not break from a teammate's Wish") { GIVEN { - ASSUME(gMovesInfo[MOVE_WISH].effect == EFFECT_WISH); + ASSUME(GetMoveEffect(MOVE_WISH) == EFFECT_WISH); PLAYER(SPECIES_JIRACHI); PLAYER(SPECIES_MIMIKYU_DISGUISED) { Ability(ABILITY_DISGUISE); HP(219); MaxHP(220); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/download.c b/test/battle/ability/download.c index 480f0bf10e5c..eec380e4218c 100644 --- a/test/battle/ability/download.c +++ b/test/battle/ability/download.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_TRI_ATTACK].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TRI_ATTACK) == DAMAGE_CATEGORY_SPECIAL); } SINGLE_BATTLE_TEST("Download raises Attack if player has lower Def than Sp. Def", s16 damage) @@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Download doesn't activate if target hasn't been sent out yet PARAMETRIZE { ability = ABILITY_TRACE; } PARAMETRIZE { ability = ABILITY_DOWNLOAD; } GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { Speed(100); } PLAYER(SPECIES_PORYGON) { Ability(ability); Defense(400); SpDefense(300); Speed(300); Attack(100); } OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } diff --git a/test/battle/ability/dragons_maw.c b/test/battle/ability/dragons_maw.c index 401c4244c86a..d7e1ebd79378 100644 --- a/test/battle/ability/dragons_maw.c +++ b/test/battle/ability/dragons_maw.c @@ -14,11 +14,11 @@ SINGLE_BATTLE_TEST("Dragon's Maw increases Dragon-type move damage", s16 damage) PARAMETRIZE { move = MOVE_DRAGON_BREATH; ability = ABILITY_DRAGONS_MAW; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_DRAGON); - ASSUME(gMovesInfo[MOVE_DRAGON_CLAW].type == TYPE_DRAGON); - ASSUME(gMovesInfo[MOVE_DRAGON_BREATH].type == TYPE_DRAGON); - ASSUME(gMovesInfo[MOVE_DRAGON_CLAW].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_DRAGON_BREATH].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveType(MOVE_TACKLE) != TYPE_DRAGON); + ASSUME(GetMoveType(MOVE_DRAGON_CLAW) == TYPE_DRAGON); + ASSUME(GetMoveType(MOVE_DRAGON_BREATH) == TYPE_DRAGON); + ASSUME(GetMoveCategory(MOVE_DRAGON_CLAW) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_DRAGON_BREATH) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_REGIDRAGO) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/dry_skin.c b/test/battle/ability/dry_skin.c index 5709a58a9448..95a0cd8fa84d 100644 --- a/test/battle/ability/dry_skin.c +++ b/test/battle/ability/dry_skin.c @@ -39,8 +39,8 @@ SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%" PARAMETRIZE { ability = ABILITY_EFFECT_SPORE; } PARAMETRIZE { ability = ABILITY_DRY_SKIN; } GIVEN { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_EMBER].power == 40); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMovePower(MOVE_EMBER) == 40); ASSUME(gSpeciesInfo[SPECIES_PARASECT].types[0] == TYPE_BUG); ASSUME(gSpeciesInfo[SPECIES_PARASECT].types[1] == TYPE_GRASS); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC); @@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Dry Skin increases damage taken from Fire-type moves by 25%" SINGLE_BATTLE_TEST("Dry Skin heals 25% when hit by water type moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(200); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("Dry Skin heals 25% when hit by water type moves") SINGLE_BATTLE_TEST("Dry Skin does not activate if protected") { GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(200); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -92,8 +92,8 @@ SINGLE_BATTLE_TEST("Dry Skin does not activate if protected") SINGLE_BATTLE_TEST("Dry Skin is only triggered once on multi strike moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_SHURIKEN].type == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_WATER_SHURIKEN].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveType(MOVE_WATER_SHURIKEN) == TYPE_WATER); + ASSUME(GetMoveEffect(MOVE_WATER_SHURIKEN) == EFFECT_MULTI_HIT); PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(200); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -111,7 +111,7 @@ SINGLE_BATTLE_TEST("Dry Skin prevents Absorb Bulb and Luminous Moss from activat PARAMETRIZE { item = ITEM_ABSORB_BULB; } PARAMETRIZE { item = ITEM_LUMINOUS_MOSS; } GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_PARASECT) { Ability(ABILITY_DRY_SKIN); HP(100); MaxHP(200); Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/earth_eater.c b/test/battle/ability/earth_eater.c index 2e6ae6dab561..c30b9674f50e 100644 --- a/test/battle/ability/earth_eater.c +++ b/test/battle/ability/earth_eater.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Earth Eater heals 25% when hit by ground type moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_MUD_SLAP].type == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND); PLAYER(SPECIES_ORTHWORM) { Ability(ABILITY_EARTH_EATER); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Earth Eater heals 25% when hit by ground type moves") SINGLE_BATTLE_TEST("Earth Eater does not activate if protected") { GIVEN { - ASSUME(gMovesInfo[MOVE_MUD_SLAP].type == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND); PLAYER(SPECIES_ORTHWORM) { Ability(ABILITY_EARTH_EATER); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -35,8 +35,8 @@ SINGLE_BATTLE_TEST("Earth Eater does not activate if protected") SINGLE_BATTLE_TEST("Earth Eater activates on status moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].type == TYPE_GROUND); - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveType(MOVE_SAND_ATTACK) == TYPE_GROUND); + ASSUME(GetMoveCategory(MOVE_SAND_ATTACK) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_ORTHWORM) { Ability(ABILITY_EARTH_EATER); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/effect_spore.c b/test/battle/ability/effect_spore.c index 49750c4797b9..06ac84f39a11 100644 --- a/test/battle/ability/effect_spore.c +++ b/test/battle/ability/effect_spore.c @@ -8,15 +8,15 @@ SINGLE_BATTLE_TEST("Effect Spore only inflicts status on contact") PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_SWIFT)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } } WHEN { TURN { MOVE(player, move, WITH_RNG(RNG_EFFECT_SPORE, 1)); } TURN {} } SCENE { - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(opponent, ABILITY_EFFECT_SPORE); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); MESSAGE("Wobbuffet was poisoned by the opposing Breloom's Effect Spore!"); @@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Effect Spore causes poison 9% of the time") PASSES_RANDOMLY(9, 100, RNG_EFFECT_SPORE); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } } WHEN { @@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("Effect Spore causes paralysis 10% of the time") PASSES_RANDOMLY(10, 100, RNG_EFFECT_SPORE); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } } WHEN { @@ -75,7 +75,7 @@ SINGLE_BATTLE_TEST("Effect Spore causes sleep 11% of the time") PASSES_RANDOMLY(11, 100, RNG_EFFECT_SPORE); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } } WHEN { diff --git a/test/battle/ability/electric_surge.c b/test/battle/ability/electric_surge.c new file mode 100644 index 000000000000..3509f1c68702 --- /dev/null +++ b/test/battle/ability/electric_surge.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Electric Surge creates Electric Terrain when entering the battle"); diff --git a/test/battle/ability/electromorphosis.c b/test/battle/ability/electromorphosis.c index 0f0ac1c39a1f..38a61f4c2910 100644 --- a/test/battle/ability/electromorphosis.c +++ b/test/battle/ability/electromorphosis.c @@ -10,12 +10,12 @@ SINGLE_BATTLE_TEST("Electromorphosis sets up Charge when hit by any move") PARAMETRIZE {move = MOVE_GUST; } GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); - ASSUME(!IS_MOVE_STATUS(MOVE_GUST)); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(!IS_MOVE_STATUS(MOVE_THUNDER_SHOCK)); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_GUST)); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(!IsBattleMoveStatus(MOVE_THUNDER_SHOCK)); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); PLAYER(SPECIES_BELLIBOLT) { Ability(ABILITY_ELECTROMORPHOSIS); Speed(10); } OPPONENT(SPECIES_WOBBUFFET) {Ability(ABILITY_LIMBER); Speed(5) ;} // Limber, so it doesn't get paralyzed. diff --git a/test/battle/ability/flame_body.c b/test/battle/ability/flame_body.c index b8fa850b65ab..95afa862c1df 100644 --- a/test/battle/ability/flame_body.c +++ b/test/battle/ability/flame_body.c @@ -7,14 +7,14 @@ SINGLE_BATTLE_TEST("Flame Body inflicts burn on contact") PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_SWIFT)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_MAGMAR) { Ability(ABILITY_FLAME_BODY); } } WHEN { TURN { MOVE(player, move); } } SCENE { - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(opponent, ABILITY_FLAME_BODY); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_BRN, player); MESSAGE("The opposing Magmar's Flame Body burned Wobbuffet!"); @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Flame Body triggers 30% of the time") PASSES_RANDOMLY(3, 10, RNG_FLAME_BODY); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_MAGMAR) { Ability(ABILITY_FLAME_BODY); } } WHEN { diff --git a/test/battle/ability/flash_fire.c b/test/battle/ability/flash_fire.c new file mode 100644 index 000000000000..c81967d1af0b --- /dev/null +++ b/test/battle/ability/flash_fire.c @@ -0,0 +1,28 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Flash Fire boosts fire type moves by 50% but no subsequent increase is applied") +{ + s16 damage[3]; + + GIVEN { + PLAYER(SPECIES_HEATRAN) { Ability(ABILITY_FLASH_FIRE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_EMBER); MOVE(opponent, MOVE_EMBER); } + TURN { MOVE(player, MOVE_EMBER); MOVE(opponent, MOVE_EMBER); } + TURN { MOVE(player, MOVE_EMBER); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[0]); + ABILITY_POPUP(player, ABILITY_FLASH_FIRE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[1]); + ABILITY_POPUP(player, ABILITY_FLASH_FIRE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.5), damage[1]); + EXPECT_EQ(damage[1], damage[2]); + } +} diff --git a/test/battle/ability/flower_gift.c b/test/battle/ability/flower_gift.c index 5ceb26c5c121..4f09e84a9a52 100644 --- a/test/battle/ability/flower_gift.c +++ b/test/battle/ability/flower_gift.c @@ -96,7 +96,7 @@ DOUBLE_BATTLE_TEST("Flower Gift increases the attack of Cherrim and its allies b PARAMETRIZE { sunny = FALSE; } PARAMETRIZE { sunny = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_CHERRIM_OVERCAST) { Ability(ABILITY_FLOWER_GIFT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -131,7 +131,7 @@ DOUBLE_BATTLE_TEST("Flower Gift increases the Sp. Def of Cherrim and its allies PARAMETRIZE { sunny = FALSE; } PARAMETRIZE { sunny = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_HYPER_VOICE) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_CHERRIM_OVERCAST) { Ability(ABILITY_FLOWER_GIFT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/fluffy.c b/test/battle/ability/fluffy.c index 30a8b83182d0..5c51ec2627ab 100644 --- a/test/battle/ability/fluffy.c +++ b/test/battle/ability/fluffy.c @@ -3,11 +3,11 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_FIRE_PUNCH].makesContact); - ASSUME(gMovesInfo[MOVE_FIRE_PUNCH].type == TYPE_FIRE); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(MoveMakesContact(MOVE_FIRE_PUNCH)); + ASSUME(GetMoveType(MOVE_FIRE_PUNCH) == TYPE_FIRE); } SINGLE_BATTLE_TEST("Fluffy halves damage taken from moves that make direct contact", s16 damage) diff --git a/test/battle/ability/frisk.c b/test/battle/ability/frisk.c index 28bd477a35dc..e6d7f275fb98 100644 --- a/test/battle/ability/frisk.c +++ b/test/battle/ability/frisk.c @@ -42,7 +42,7 @@ DOUBLE_BATTLE_TEST("Frisk triggers for player in a Double Battle after switching PARAMETRIZE { target = playerRight; } GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_POUND)); + ASSUME(!IsBattleMoveStatus(MOVE_POUND)); PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_FURRET) { Ability(ABILITY_FRISK); }; @@ -65,7 +65,7 @@ DOUBLE_BATTLE_TEST("Frisk triggers for opponent in a Double Battle after switchi PARAMETRIZE { target = opponentRight; } GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_POUND)); + ASSUME(!IsBattleMoveStatus(MOVE_POUND)); PLAYER(SPECIES_WYNAUT) { Item(ITEM_POTION); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { HP(1); } diff --git a/test/battle/ability/gale_wings.c b/test/battle/ability/gale_wings.c index eff458964927..df8f02532649 100644 --- a/test/battle/ability/gale_wings.c +++ b/test/battle/ability/gale_wings.c @@ -1,20 +1,22 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Gale Wings only grants priority at full HP") +SINGLE_BATTLE_TEST("Gale Wings only grants priority at full HP (Gen 7+)") { - u16 hp; - PARAMETRIZE { hp = 100; } - PARAMETRIZE { hp = 99; } + u32 hp, config; + PARAMETRIZE { hp = 100; config = GEN_7; } + PARAMETRIZE { hp = 99; config = GEN_7; } + PARAMETRIZE { hp = 100; config = GEN_6; } + PARAMETRIZE { hp = 99; config = GEN_6; } GIVEN { - ASSUME(B_GALE_WINGS >= GEN_7); - ASSUME(gMovesInfo[MOVE_AERIAL_ACE].type == TYPE_FLYING); + WITH_CONFIG(GEN_CONFIG_GALE_WINGS, config); + ASSUME(GetMoveType(MOVE_AERIAL_ACE) == TYPE_FLYING); PLAYER(SPECIES_TALONFLAME) { Ability(ABILITY_GALE_WINGS); HP(hp); MaxHP(100); Speed(1);} OPPONENT(SPECIES_WOBBUFFET) { Speed(100);}; } WHEN { TURN { MOVE(player, MOVE_AERIAL_ACE); } } SCENE { - if (hp == 100) { + if (hp == 100 || config <= GEN_6) { MESSAGE("Talonflame used Aerial Ace!"); MESSAGE("The opposing Wobbuffet used Celebrate!"); } @@ -31,9 +33,8 @@ SINGLE_BATTLE_TEST("Gale Wings only grants priority to Flying-type moves") PARAMETRIZE { move = MOVE_AERIAL_ACE; } PARAMETRIZE { move = MOVE_FLARE_BLITZ; } GIVEN { - ASSUME(B_GALE_WINGS >= GEN_7); - ASSUME(gMovesInfo[MOVE_AERIAL_ACE].type == TYPE_FLYING); - ASSUME(gMovesInfo[MOVE_FLARE_BLITZ].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_AERIAL_ACE) == TYPE_FLYING); + ASSUME(GetMoveType(MOVE_FLARE_BLITZ) == TYPE_FIRE); PLAYER(SPECIES_TALONFLAME) { Ability(ABILITY_GALE_WINGS); HP(100); MaxHP(100); Speed(1);} OPPONENT(SPECIES_WOBBUFFET) { Speed(100);}; } WHEN { @@ -58,12 +59,11 @@ SINGLE_BATTLE_TEST("Gale Wings doesn't increase priority of Flying-type Natural PARAMETRIZE { move = MOVE_JUDGMENT; heldItem = ITEM_SKY_PLATE; } PARAMETRIZE { move = MOVE_HIDDEN_POWER; heldItem = ITEM_NONE; } GIVEN { - ASSUME(B_GALE_WINGS >= GEN_7); - ASSUME(gMovesInfo[MOVE_NATURAL_GIFT].effect == EFFECT_NATURAL_GIFT); - ASSUME(gMovesInfo[MOVE_JUDGMENT].effect == EFFECT_CHANGE_TYPE_ON_ITEM); + ASSUME(GetMoveEffect(MOVE_NATURAL_GIFT) == EFFECT_NATURAL_GIFT); + ASSUME(GetMoveEffect(MOVE_JUDGMENT) == EFFECT_CHANGE_TYPE_ON_ITEM); // IV combinations sourced from https://www.smogon.com/forums/threads/hidden-power-iv-combinations.78083/ - ASSUME(gMovesInfo[MOVE_HIDDEN_POWER].effect == EFFECT_HIDDEN_POWER); - ASSUME(gMovesInfo[MOVE_TERA_BLAST].effect == EFFECT_TERA_BLAST); + ASSUME(GetMoveEffect(MOVE_HIDDEN_POWER) == EFFECT_HIDDEN_POWER); + ASSUME(GetMoveEffect(MOVE_TERA_BLAST) == EFFECT_TERA_BLAST); ASSUME(gItemsInfo[ITEM_SKY_PLATE].holdEffect == HOLD_EFFECT_PLATE); ASSUME(gItemsInfo[ITEM_SKY_PLATE].secondaryId == TYPE_FLYING); ASSUME(gNaturalGiftTable[ITEM_TO_BERRY(ITEM_LUM_BERRY)].type == TYPE_FLYING); diff --git a/test/battle/ability/galvanize.c b/test/battle/ability/galvanize.c index 1da82e861dfb..6de5675b6a8a 100644 --- a/test/battle/ability/galvanize.c +++ b/test/battle/ability/galvanize.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); } SINGLE_BATTLE_TEST("Galvanize turns a normal type move into Electric") @@ -29,9 +29,9 @@ SINGLE_BATTLE_TEST("Galvanize can not turn certain moves into Electric type move PARAMETRIZE { move = MOVE_MULTI_ATTACK; } GIVEN { - ASSUME(gMovesInfo[MOVE_HIDDEN_POWER].effect == EFFECT_HIDDEN_POWER); - ASSUME(gMovesInfo[MOVE_WEATHER_BALL].effect == EFFECT_WEATHER_BALL); - ASSUME(gMovesInfo[MOVE_MULTI_ATTACK].effect == EFFECT_CHANGE_TYPE_ON_ITEM); + ASSUME(GetMoveEffect(MOVE_HIDDEN_POWER) == EFFECT_HIDDEN_POWER); + ASSUME(GetMoveEffect(MOVE_WEATHER_BALL) == EFFECT_WEATHER_BALL); + ASSUME(GetMoveEffect(MOVE_MULTI_ATTACK) == EFFECT_CHANGE_TYPE_ON_ITEM); PLAYER(SPECIES_KRABBY); OPPONENT(SPECIES_GEODUDE_ALOLA) { Ability(ABILITY_GALVANIZE); } } WHEN { diff --git a/test/battle/ability/good_as_gold.c b/test/battle/ability/good_as_gold.c index 40561ee767ee..fc6c6bc8c467 100644 --- a/test/battle/ability/good_as_gold.c +++ b/test/battle/ability/good_as_gold.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Good as Gold protects from status moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveCategory(MOVE_TOXIC) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); } } WHEN { @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Good as Gold protects from status moves") SINGLE_BATTLE_TEST("Good as Gold doesn't protect the user from it's own moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_NASTY_PLOT].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveCategory(MOVE_NASTY_PLOT) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); } } WHEN { @@ -37,8 +37,8 @@ SINGLE_BATTLE_TEST("Good as Gold doesn't protect the user from it's own moves") SINGLE_BATTLE_TEST("Good as Gold doesn't protect from moves that target the field") { GIVEN { - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD); + ASSUME(GetMoveCategory(MOVE_STEALTH_ROCK) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveTarget(MOVE_STEALTH_ROCK) == MOVE_TARGET_OPPONENTS_FIELD); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); } } WHEN { @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Good as Gold doesn't protect from moves that target the fiel DOUBLE_BATTLE_TEST("Good as Gold protects from partner's status moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_HELPING_HAND].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveCategory(MOVE_HELPING_HAND) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GHOLDENGO) { Ability(ABILITY_GOOD_AS_GOLD); } diff --git a/test/battle/ability/grassy_surge.c b/test/battle/ability/grassy_surge.c new file mode 100644 index 000000000000..ccdb471d9f05 --- /dev/null +++ b/test/battle/ability/grassy_surge.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Grassy Surge creates Grassy Terrain when entering the battle"); diff --git a/test/battle/ability/grim_neigh.c b/test/battle/ability/grim_neigh.c index 6e0073f955b7..c58487722be5 100644 --- a/test/battle/ability/grim_neigh.c +++ b/test/battle/ability/grim_neigh.c @@ -7,7 +7,7 @@ DOUBLE_BATTLE_TEST("Grim Neigh raises Sp. Attack by one stage after directly cau PARAMETRIZE { species = SPECIES_SPECTRIER; ability = ABILITY_GRIM_NEIGH; abilityPopUp = ABILITY_GRIM_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; abilityPopUp = ABILITY_GRIM_NEIGH; } GIVEN { - ASSUME(gMovesInfo[MOVE_DISCHARGE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(species) { Ability(ability); } PLAYER(SPECIES_SNORUNT) { HP(1); } OPPONENT(SPECIES_GLALIE) { HP(1); } @@ -81,7 +81,7 @@ DOUBLE_BATTLE_TEST("Grim Neigh does not increase damage done by the same move th PARAMETRIZE { species = SPECIES_CALYREX_SHADOW; ability = ABILITY_AS_ONE_SHADOW_RIDER; abilityPopUp = ABILITY_GRIM_NEIGH; } GIVEN { - ASSUME(gMovesInfo[MOVE_DISCHARGE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(species) { Ability(ability); } PLAYER(SPECIES_ABRA) { HP(1); } OPPONENT(SPECIES_GLALIE); diff --git a/test/battle/ability/gulp_missile.c b/test/battle/ability/gulp_missile.c index 189702a4bef9..72e826b252a9 100644 --- a/test/battle/ability/gulp_missile.c +++ b/test/battle/ability/gulp_missile.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - // ASSUME(gMovesInfo[MOVE_AERIAL_ACE].category == DAMAGE_CATEGORY_PHYSICAL); + // ASSUME(GetMoveCategory(MOVE_AERIAL_ACE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("(Gulp Missile) If base Cramorant hits target with Surf it transforms into Gulping form if max HP is over 1/2") @@ -167,7 +167,7 @@ SINGLE_BATTLE_TEST("(Gulp Missile) Transformed Cramorant Gulping lowers defense PARAMETRIZE { ability = ABILITY_INFILTRATOR; } PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact == TRUE); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_CRAMORANT) { Ability(ABILITY_GULP_MISSILE); Item(ITEM_ROCKY_HELMET); } OPPONENT(SPECIES_DRAGAPULT) { Ability(ability); } } WHEN { diff --git a/test/battle/ability/harvest.c b/test/battle/ability/harvest.c index 03e13b394e33..92e7517df5e7 100644 --- a/test/battle/ability/harvest.c +++ b/test/battle/ability/harvest.c @@ -5,7 +5,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_SITRUS_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PCT_HP); ASSUME(I_SITRUS_BERRY_HEAL >= GEN_4); - ASSUME(gMovesInfo[MOVE_SUNNY_DAY].effect == EFFECT_SUNNY_DAY); + ASSUME(GetMoveEffect(MOVE_SUNNY_DAY) == EFFECT_SUNNY_DAY); } SINGLE_BATTLE_TEST("Harvest has a 50% chance to restore a Berry at the end of the turn") @@ -61,7 +61,7 @@ SINGLE_BATTLE_TEST("Harvest doesn't always restore a Berry if Cloud Nine/Air Loc SINGLE_BATTLE_TEST("Harvest restores a Berry even after being switched out and back in") { GIVEN { - ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT); + ASSUME(GetMoveEffect(MOVE_PARTING_SHOT) == EFFECT_PARTING_SHOT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); MaxHP(500); HP(251); Item(ITEM_SITRUS_BERRY); } OPPONENT(SPECIES_WOBBUFFET); @@ -80,7 +80,7 @@ SINGLE_BATTLE_TEST("Harvest restores a Berry even after being switched out and b SINGLE_BATTLE_TEST("Harvest restores a Berry consumed by Fling") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING); + ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); } } WHEN { @@ -97,7 +97,7 @@ SINGLE_BATTLE_TEST("Harvest restores a Berry consumed by Fling") SINGLE_BATTLE_TEST("Harvest restores a Berry consumed by Natural Gift") { GIVEN { - ASSUME(gMovesInfo[MOVE_NATURAL_GIFT].effect == EFFECT_NATURAL_GIFT); + ASSUME(GetMoveEffect(MOVE_NATURAL_GIFT) == EFFECT_NATURAL_GIFT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); } } WHEN { @@ -209,7 +209,7 @@ DOUBLE_BATTLE_TEST("Harvest order is affected by speed") SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry when transfered to another Pokémon") { GIVEN { - ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK); + ASSUME(GetMoveEffect(MOVE_TRICK) == EFFECT_TRICK); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); Item(ITEM_SITRUS_BERRY); } } WHEN { @@ -226,7 +226,7 @@ SINGLE_BATTLE_TEST("Harvest doesn't restore a Berry when transfered to another P SINGLE_BATTLE_TEST("Harvest can restore a Berry that was transferred from another Pokémon") { GIVEN { - ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK); + ASSUME(GetMoveEffect(MOVE_TRICK) == EFFECT_TRICK); PLAYER(SPECIES_TORKOAL) { Ability(ABILITY_DROUGHT); Item(ITEM_SITRUS_BERRY); } OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); HP(100); MaxHP(500); } } WHEN { @@ -245,7 +245,7 @@ SINGLE_BATTLE_TEST("Harvest can restore a Berry that was transferred from anothe SINGLE_BATTLE_TEST("Harvest can only restore the newest berry consumed that was transferred from another Pokémon instead of its original Berry") { GIVEN { - ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK); + ASSUME(GetMoveEffect(MOVE_TRICK) == EFFECT_TRICK); ASSUME(gItemsInfo[ITEM_APICOT_BERRY].holdEffect == HOLD_EFFECT_SP_DEFENSE_UP); PLAYER(SPECIES_TORKOAL) { Ability(ABILITY_DROUGHT); Item(ITEM_SITRUS_BERRY); } OPPONENT(SPECIES_EXEGGUTOR) { Ability(ABILITY_HARVEST); HP(100); MaxHP(500); Item(ITEM_APICOT_BERRY); } diff --git a/test/battle/ability/hyper_cutter.c b/test/battle/ability/hyper_cutter.c index a688da25319c..7bd5504965e6 100644 --- a/test/battle/ability/hyper_cutter.c +++ b/test/battle/ability/hyper_cutter.c @@ -29,7 +29,7 @@ SINGLE_BATTLE_TEST("Hyper Cutter prevents intimidate") SINGLE_BATTLE_TEST("Hyper Cutter prevents Attack stage reduction from moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); } } WHEN { @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Hyper Cutter prevents Attack stage reduction from moves") SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Attack reduction from burn") { GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); } } WHEN { @@ -59,7 +59,7 @@ SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Attack reduction from burn") SINGLE_BATTLE_TEST("Hyper Cutter is ignored by Mold Breaker") { GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); } } WHEN { @@ -97,8 +97,8 @@ SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Attack stage reduction from mov SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Topsy-Turvy") { GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); - ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_TOPSY_TURVY) == EFFECT_TOPSY_TURVY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); } } WHEN { @@ -116,7 +116,7 @@ SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Topsy-Turvy") SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Spectral Thief from resetting positive Attack stage changes") { GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); } @@ -135,8 +135,8 @@ SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent Spectral Thief from resetting p SINGLE_BATTLE_TEST("Hyper Cutter doesn't prevent receiving negative Attack stage changes from Baton Pass") { GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KRABBY) { Ability(ABILITY_HYPER_CUTTER); } diff --git a/test/battle/ability/ice_body.c b/test/battle/ability/ice_body.c index 3f278a50cd5e..07890d52f222 100644 --- a/test/battle/ability/ice_body.c +++ b/test/battle/ability/ice_body.c @@ -2,8 +2,8 @@ #include "test/battle.h" ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); } SINGLE_BATTLE_TEST("Ice Body prevents damage from hail") diff --git a/test/battle/ability/ice_face.c b/test/battle/ability/ice_face.c index 22b67a7a5369..a462b8026533 100644 --- a/test/battle/ability/ice_face.c +++ b/test/battle/ability/ice_face.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Ice Face blocks physical moves, changing Eiscue into its Noice Face form") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_EISCUE); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -18,8 +18,8 @@ SINGLE_BATTLE_TEST("Ice Face blocks physical moves, changing Eiscue into its Noi SINGLE_BATTLE_TEST("Ice Face does not block special moves, Eiscue stays in Ice Face form") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_EMBER].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_EMBER) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_EISCUE); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -35,9 +35,9 @@ SINGLE_BATTLE_TEST("Ice Face is restored if hail or snow begins while Noice Face PARAMETRIZE { move = MOVE_SNOWSCAPE; } PARAMETRIZE { move = MOVE_HAIL; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); PLAYER(SPECIES_EISCUE); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -60,9 +60,9 @@ SINGLE_BATTLE_TEST("Ice Face is restored if Noice Face Eiscue is sent in while h PARAMETRIZE { move = MOVE_SNOWSCAPE; } PARAMETRIZE { move = MOVE_HAIL; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); PLAYER(SPECIES_EISCUE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -86,9 +86,9 @@ SINGLE_BATTLE_TEST("Ice Face is not restored if Eiscue changes into Noice Face f PARAMETRIZE { move = MOVE_SNOWSCAPE; } PARAMETRIZE { move = MOVE_HAIL; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); PLAYER(SPECIES_EISCUE) { HP(1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -105,7 +105,7 @@ SINGLE_BATTLE_TEST("Ice Face is not restored if Eiscue changes into Noice Face f SINGLE_BATTLE_TEST("Ice Face form change persists after switching out") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_EISCUE) { HP(1); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -123,7 +123,7 @@ SINGLE_BATTLE_TEST("Ice Face form change persists after switching out") SINGLE_BATTLE_TEST("Ice Face doesn't transform Eiscue if Cloud Nine/Air Lock is on the field") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_EISCUE) { HP(1); } OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_AIR_LOCK); } } WHEN { @@ -142,9 +142,9 @@ SINGLE_BATTLE_TEST("Ice Face is not restored if hail or snow and Eiscue are alre PARAMETRIZE { move = MOVE_SNOWSCAPE; } PARAMETRIZE { move = MOVE_HAIL; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); PLAYER(SPECIES_EISCUE); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/ability/ice_scales.c b/test/battle/ability/ice_scales.c index fd262147a57b..37c5aa0944cb 100644 --- a/test/battle/ability/ice_scales.c +++ b/test/battle/ability/ice_scales.c @@ -12,10 +12,10 @@ SINGLE_BATTLE_TEST("Ice Scales halves the damage from special moves", s16 damage PARAMETRIZE { ability = ABILITY_SHIELD_DUST; move = MOVE_TACKLE; } PARAMETRIZE { ability = ABILITY_ICE_SCALES; move = MOVE_TACKLE; } GIVEN { - ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_PSYSHOCK].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_PSYSHOCK].effect == EFFECT_PSYSHOCK); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_PSYCHIC) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_PSYSHOCK) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_PSYSHOCK) == EFFECT_PSYSHOCK); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_FROSMOTH) { Ability(ability); } } WHEN { diff --git a/test/battle/ability/immunity.c b/test/battle/ability/immunity.c index 2fa90686c53a..92e32d31f32e 100644 --- a/test/battle/ability/immunity.c +++ b/test/battle/ability/immunity.c @@ -18,7 +18,7 @@ SINGLE_BATTLE_TEST("Immunity prevents Poison Sting poison") SINGLE_BATTLE_TEST("Immunity prevents Toxic bad poison") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_IMMUNITY); } } WHEN { @@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Immunity prevents Toxic bad poison") SINGLE_BATTLE_TEST("Immunity prevents Toxic Spikes poison") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_IMMUNITY); } diff --git a/test/battle/ability/innards_out.c b/test/battle/ability/innards_out.c index 5837b98d1f68..ed11354e3a9a 100644 --- a/test/battle/ability/innards_out.c +++ b/test/battle/ability/innards_out.c @@ -14,8 +14,8 @@ SINGLE_BATTLE_TEST("Innards Out deal dmg on fainting equal to the amount of dmg PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(70); SpAttack(1000); } OPPONENT(SPECIES_WOBBUFFET); - ASSUME(!IS_MOVE_STATUS(MOVE_PSYCHIC)); - ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(!IsBattleMoveStatus(MOVE_PSYCHIC)); + ASSUME(GetMoveCategory(MOVE_PSYCHIC) == DAMAGE_CATEGORY_SPECIAL); } WHEN { TURN { MOVE(opponent, MOVE_PSYCHIC); SEND_OUT(player, 1); if (hp == 100) { SEND_OUT(opponent, 1); } } } SCENE { @@ -32,8 +32,8 @@ SINGLE_BATTLE_TEST("Innards Out does not trigger after Gastro Acid has been used PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); - ASSUME(!IS_MOVE_STATUS(MOVE_PSYCHIC)); - ASSUME(gMovesInfo[MOVE_GASTRO_ACID].effect == EFFECT_GASTRO_ACID); + ASSUME(!IsBattleMoveStatus(MOVE_PSYCHIC)); + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); } WHEN { TURN { MOVE(opponent, MOVE_GASTRO_ACID); } TURN { MOVE(opponent, MOVE_PSYCHIC); SEND_OUT(player, 1); } @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Innards Out does not damage Magic Guard Pokemon") PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_CLEFABLE) { Ability(ABILITY_MAGIC_GUARD); } - ASSUME(!IS_MOVE_STATUS(MOVE_PSYCHIC)); + ASSUME(!IsBattleMoveStatus(MOVE_PSYCHIC)); } WHEN { TURN { MOVE(opponent, MOVE_PSYCHIC); SEND_OUT(player, 1); } } SCENE { @@ -65,3 +65,66 @@ SINGLE_BATTLE_TEST("Innards Out does not damage Magic Guard Pokemon") NOT HP_BAR(opponent); } } + +SINGLE_BATTLE_TEST("Innards Out uses correct damage amount for Future Sight") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); + PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("Pyukumuku took the Future Sight attack!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_INNARDS_OUT); + HP_BAR(opponent, damage: 1); + } +} + +SINGLE_BATTLE_TEST("Innards Out doesn't trigger if Future Sight user is not on field") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); + PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN { SWITCH(opponent, 1); } + TURN { SEND_OUT(player, 1); } //SEND_OUT(opponent, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("Pyukumuku took the Future Sight attack!"); + HP_BAR(player); + NONE_OF { + ABILITY_POPUP(player, ABILITY_INNARDS_OUT); + HP_BAR(opponent); + } + } +} + +SINGLE_BATTLE_TEST("Innards Out triggers if Future Sight user is back on the field") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); + PLAYER(SPECIES_PYUKUMUKU) { HP(1); Ability(ABILITY_INNARDS_OUT); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, MOVE_FUTURE_SIGHT); } + TURN { SWITCH(opponent, 1); } + TURN { SWITCH(opponent, 0); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, opponent); + MESSAGE("Pyukumuku took the Future Sight attack!"); + HP_BAR(player); + ABILITY_POPUP(player, ABILITY_INNARDS_OUT); + HP_BAR(opponent); + } +} diff --git a/test/battle/ability/insomnia.c b/test/battle/ability/insomnia.c index 3098ce6d3f4b..533ca9ce85ca 100644 --- a/test/battle/ability/insomnia.c +++ b/test/battle/ability/insomnia.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Insomnia prevents sleep") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_DROWZEE) { Ability(ABILITY_INSOMNIA); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -22,11 +22,11 @@ SINGLE_BATTLE_TEST("Insomnia prevents sleep") SINGLE_BATTLE_TEST("Insomnia prevents yawn") { GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_DROWZEE) { Ability(ABILITY_INSOMNIA); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_SPORE); } + TURN { MOVE(opponent, MOVE_YAWN); } TURN {} TURN {} } SCENE { @@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("Insomnia prevents yawn") SINGLE_BATTLE_TEST("Insomnia prevents rest") { GIVEN { - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_DROWZEE) { Ability(ABILITY_INSOMNIA); HP(1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/intimidate.c b/test/battle/ability/intimidate.c index e0f97d5bdaf2..2553c2755f7b 100644 --- a/test/battle/ability/intimidate.c +++ b/test/battle/ability/intimidate.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after switch out", s16 damage) @@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Intimidate (opponent) lowers player's attack after KO", s16 DOUBLE_BATTLE_TEST("Intimidate doesn't activate on an empty field in a double battle") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); } @@ -271,9 +271,9 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral PARAMETRIZE { move = MOVE_HEALING_WISH; } PARAMETRIZE { move = MOVE_BATON_PASS; } GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_HEALING_WISH].effect == EFFECT_HEALING_WISH); - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); } PLAYER(SPECIES_WOBBUFFET) { HP(1); } OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } @@ -302,9 +302,9 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral GIVEN { ASSUME(gItemsInfo[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON); ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK); - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_ROAR].effect == EFFECT_ROAR); - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); Item(item); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } @@ -333,7 +333,7 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted") { GIVEN { - ASSUME(gMovesInfo[MOVE_FELL_STINGER].effect == EFFECT_FELL_STINGER); + ASSUME(GetMoveEffect(MOVE_FELL_STINGER) == EFFECT_FELL_STINGER); PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } diff --git a/test/battle/ability/intrepid_sword.c b/test/battle/ability/intrepid_sword.c index 68300fb229d6..58fd9883ebfa 100644 --- a/test/battle/ability/intrepid_sword.c +++ b/test/battle/ability/intrepid_sword.c @@ -67,7 +67,7 @@ SINGLE_BATTLE_TEST("Intrepid Sword activates when it's no longer effected by Neu SINGLE_BATTLE_TEST("Intrepid Sword and Dauntless Shield both can be Skill Swapped and active their effects on the Skill Swap user") { GIVEN { - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_ZACIAN) { Ability(ABILITY_INTREPID_SWORD); } OPPONENT(SPECIES_ZAMAZENTA) { Ability(ABILITY_DAUNTLESS_SHIELD); } diff --git a/test/battle/ability/keen_eye.c b/test/battle/ability/keen_eye.c index b047ec988f71..0268477ded26 100644 --- a/test/battle/ability/keen_eye.c +++ b/test/battle/ability/keen_eye.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].accuracy == 100); - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + ASSUME(GetMoveAccuracy(MOVE_TACKLE) == 100); + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); ASSUME(B_ILLUMINATE_EFFECT >= GEN_9); } @@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye ignore target's evasi PASSES_RANDOMLY(100, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_TEAM].effect == EFFECT_EVASION_UP); + ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { @@ -78,7 +78,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye are ignored by Mold B PARAMETRIZE { speciesOpponent = SPECIES_URSALUNA_BLOODMOON; abilityOpponent = ABILITY_MINDS_EYE; } } - PASSES_RANDOMLY(gMovesInfo[MOVE_TACKLE].accuracy * 3 / 4, 100, RNG_ACCURACY); + PASSES_RANDOMLY(GetMoveAccuracy(MOVE_TACKLE) * 3 / 4, 100, RNG_ACCURACY); GIVEN { PLAYER(speciesPlayer) { Ability(abilityPlayer); } OPPONENT(speciesOpponent) { Ability(abilityOpponent); } @@ -102,8 +102,8 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent Topsy-T PARAMETRIZE { species = SPECIES_URSALUNA_BLOODMOON; ability = ABILITY_MINDS_EYE; } GIVEN { - ASSUME(gMovesInfo[MOVE_HONE_CLAWS].effect == EFFECT_ATTACK_ACCURACY_UP); - ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY); + ASSUME(GetMoveEffect(MOVE_HONE_CLAWS) == EFFECT_ATTACK_ACCURACY_UP); + ASSUME(GetMoveEffect(MOVE_TOPSY_TURVY) == EFFECT_TOPSY_TURVY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { @@ -141,7 +141,7 @@ SINGLE_BATTLE_TEST("Keen Eye, Gen9+ Illuminate & Minds Eye don't prevent receivi PARAMETRIZE { species = SPECIES_URSALUNA_BLOODMOON; ability = ABILITY_MINDS_EYE; } GIVEN { - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } @@ -173,7 +173,7 @@ SINGLE_BATTLE_TEST("Keen Eye & Gen9+ Illuminate don't prevent Spectral Thief fro PARAMETRIZE { species = SPECIES_STARYU; ability = ABILITY_ILLUMINATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_HONE_CLAWS].effect == EFFECT_ATTACK_ACCURACY_UP); + ASSUME(GetMoveEffect(MOVE_HONE_CLAWS) == EFFECT_ATTACK_ACCURACY_UP); ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF) == TRUE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } diff --git a/test/battle/ability/leaf_guard.c b/test/battle/ability/leaf_guard.c index af113f1bb640..e04881ecb4fd 100644 --- a/test/battle/ability/leaf_guard.c +++ b/test/battle/ability/leaf_guard.c @@ -11,10 +11,10 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents non-volatile status conditions in sun") PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; } // PARAMETRIZE { move = MOVE_POWDER_SNOW; status = STATUS1_FREEZE; } // Pointless since you can't freeze in sunlight anyway GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); - ASSUME(gMovesInfo[MOVE_HYPNOSIS].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_THUNDER_WAVE].effect == EFFECT_PARALYZE); - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_HYPNOSIS) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_PARALYZE); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -57,7 +57,7 @@ SINGLE_BATTLE_TEST("Leaf Guard prevents Rest during sun") { GIVEN { ASSUME(B_LEAF_GUARD_PREVENTS_REST >= GEN_5); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_LEAFEON) { Ability(ABILITY_LEAF_GUARD); HP(100); MaxHP(200); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/lightning_rod.c b/test/battle/ability/lightning_rod.c index c719ee145d41..e3c0a59212cd 100644 --- a/test/battle/ability/lightning_rod.c +++ b/test/battle/ability/lightning_rod.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the Sp. Attack [Gen5+]") { GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); } } WHEN { @@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Lightning Rod absorbs Electric-type moves and increases the DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to target the Pokémon with this Ability.") { GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); } @@ -71,3 +71,29 @@ DOUBLE_BATTLE_TEST("Lightning Rod forces single-target Electric-type moves to ta ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight); } } + +DOUBLE_BATTLE_TEST("Lightning Rod redirects an ally's attack") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, MOVE_THUNDERBOLT, target: playerLeft); } + } SCENE { + MESSAGE("The opposing Wobbuffet used Thunderbolt!"); + if (B_REDIRECT_ABILITY_ALLIES >= GEN_5) + { + NOT HP_BAR(playerLeft); + ABILITY_POPUP(opponentLeft, ABILITY_LIGHTNING_ROD); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + MESSAGE("The opposing Raichu's Sp. Atk rose!"); + } + else + { + HP_BAR(playerLeft); + } + } +} diff --git a/test/battle/ability/liquid_ooze.c b/test/battle/ability/liquid_ooze.c new file mode 100644 index 000000000000..6398a0be2b19 --- /dev/null +++ b/test/battle/ability/liquid_ooze.c @@ -0,0 +1,139 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Liquid Ooze causes Absorb users to lose HP instead of heal") +{ + s16 damage; + s16 healed; + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + } WHEN { + TURN { MOVE(player, MOVE_ABSORB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + HP_BAR(opponent, captureDamage: &damage); + HP_BAR(player, captureDamage: &healed); + MESSAGE("Wobbuffet sucked up the liquid ooze!"); + } THEN { + EXPECT_MUL_EQ(damage, Q_4_12(0.5), healed); + } +} + +SINGLE_BATTLE_TEST("Liquid Ooze causes Leech Seed users to lose HP instead of heal") +{ + s16 damage; + s16 healed; + + GIVEN { + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + } WHEN { + TURN { MOVE(player, MOVE_LEECH_SEED); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LEECH_SEED, player); + HP_BAR(opponent, captureDamage: &damage); + HP_BAR(player, captureDamage: &healed); + } THEN { + EXPECT_EQ(damage, healed); + } +} + +DOUBLE_BATTLE_TEST("Liquid Ooze causes Matcha Gatcha users to lose HP instead of heal") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_MATCHA_GOTCHA) == EFFECT_ABSORB); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_MATCHA_GOTCHA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MATCHA_GOTCHA, playerLeft); + HP_BAR(opponentLeft); + HP_BAR(playerLeft); + MESSAGE("Wobbuffet sucked up the liquid ooze!"); + MESSAGE("Wobbuffet fainted!"); + } +} + +DOUBLE_BATTLE_TEST("Liquid Ooze will faint Matcha Gatcha users if it deals enough damage") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_MATCHA_GOTCHA) == EFFECT_ABSORB); + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_MATCHA_GOTCHA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MATCHA_GOTCHA, playerLeft); + HP_BAR(opponentLeft); + HP_BAR(playerLeft); + MESSAGE("Wobbuffet sucked up the liquid ooze!"); + MESSAGE("Wobbuffet fainted!"); + } +} + +SINGLE_BATTLE_TEST("Liquid Ooze causes Strength Sap users to lose HP instead of heal") +{ + s16 lostHp; + s32 atkStat; + + PARAMETRIZE { atkStat = 100; } + PARAMETRIZE { atkStat = 490; } // Checks that attacker can faint with no problems. + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Attack(atkStat); Ability(ABILITY_LIQUID_OOZE); } + } WHEN { + TURN { MOVE(player, MOVE_STRENGTH_SAP); if (atkStat == 490) { SEND_OUT(player, 1); } } + } SCENE { + MESSAGE("Wobbuffet used Strength Sap!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STRENGTH_SAP, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("The opposing Wobbuffet's Attack fell!"); + ABILITY_POPUP(opponent, ABILITY_LIQUID_OOZE); + HP_BAR(player, captureDamage: &lostHp); + MESSAGE("Wobbuffet sucked up the liquid ooze!"); + if (atkStat >= 490) { + MESSAGE("Wobbuffet fainted!"); + SEND_IN_MESSAGE("Wobbuffet"); + } + } THEN { + EXPECT_EQ(lostHp, atkStat); + } +} + +SINGLE_BATTLE_TEST("Liquid Ooze causes leech seedee to faint before seeder") +{ + KNOWN_FAILING; // Message fails + u16 ability; + PARAMETRIZE { ability = ABILITY_CLEAR_BODY; } + PARAMETRIZE { ability = ABILITY_LIQUID_OOZE; } + GIVEN { + PLAYER(SPECIES_BULBASAUR) { HP(1); } + OPPONENT(SPECIES_TENTACOOL) { HP(1); Ability(ability); } + } WHEN { + TURN { MOVE(player, MOVE_LEECH_SEED); } + } SCENE { + MESSAGE("Bulbasaur used Leech Seed!"); + // Drain at end of turn + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_LEECH_SEED_DRAIN, opponent); + if (ability != ABILITY_LIQUID_OOZE) { + MESSAGE("The opposing Tentacool's health is sapped by Leech Seed!"); + MESSAGE("The opposing Tentacool fainted!"); + } else { + ABILITY_POPUP(opponent, ABILITY_LIQUID_OOZE); + MESSAGE("Bulbasaur sucked up the liquid ooze!"); + MESSAGE("The opposing Tentacool fainted!"); + MESSAGE("Bulbasaur fainted!"); + } + } +} + +TO_DO_BATTLE_TEST("Liquid Ooze does not cause Dream Eater users to lose HP instead of heal (Gen 3-4"); +TO_DO_BATTLE_TEST("Liquid Ooze causes Dream Eater users to lose HP instead of heal (Gen 5+"); diff --git a/test/battle/ability/magic_bounce.c b/test/battle/ability/magic_bounce.c index a643b228248f..2731a21fede4 100644 --- a/test/battle/ability/magic_bounce.c +++ b/test/battle/ability/magic_bounce.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Magic Bounce bounces back status moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } } WHEN { @@ -22,8 +22,8 @@ SINGLE_BATTLE_TEST("Magic Bounce bounces back status moves") SINGLE_BATTLE_TEST("Magic Bounce bounces back powder moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove); - ASSUME(gMovesInfo[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE); + ASSUME(IsPowderMove(MOVE_STUN_SPORE)); + ASSUME(GetMoveEffect(MOVE_STUN_SPORE) == EFFECT_PARALYZE); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } } WHEN { @@ -40,7 +40,7 @@ SINGLE_BATTLE_TEST("Magic Bounce bounces back powder moves") SINGLE_BATTLE_TEST("Magic Bounce cannot bounce back powder moves against 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); OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } @@ -59,8 +59,8 @@ SINGLE_BATTLE_TEST("Magic Bounce cannot bounce back powder moves against Grass T DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting both foes at two foes") { GIVEN { - ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); - ASSUME(gMovesInfo[MOVE_LEER].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveEffect(MOVE_LEER) == EFFECT_DEFENSE_DOWN); + ASSUME(GetMoveTarget(MOVE_LEER) == MOVE_TARGET_BOTH); PLAYER(SPECIES_ABRA); PLAYER(SPECIES_KADABRA); OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } @@ -92,7 +92,7 @@ DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting foes field") battlerTwo = SPECIES_ESPEON; abilityBattlerTwo = ABILITY_MAGIC_BOUNCE; } GIVEN { - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD); + ASSUME(GetMoveTarget(MOVE_STEALTH_ROCK) == MOVE_TARGET_OPPONENTS_FIELD); PLAYER(SPECIES_ABRA); PLAYER(SPECIES_KADABRA); OPPONENT(battlerOne) { Ability(abilityBattlerOne); } @@ -118,7 +118,7 @@ DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting foes field") SINGLE_BATTLE_TEST("Magic Bounce bounced back status moves can not be bounced back by Magic Bounce") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } } WHEN { diff --git a/test/battle/ability/magic_guard.c b/test/battle/ability/magic_guard.c index 5579652265eb..8941fb21303a 100644 --- a/test/battle/ability/magic_guard.c +++ b/test/battle/ability/magic_guard.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Magic Guard prevents recoil damage to the user") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_EDGE].recoil == 33); + ASSUME(GetMoveRecoil(MOVE_DOUBLE_EDGE) == 33); PLAYER(SPECIES_CLEFABLE) { Ability(ABILITY_MAGIC_GUARD); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -15,3 +15,32 @@ SINGLE_BATTLE_TEST("Magic Guard prevents recoil damage to the user") NOT HP_BAR(player); } } + +SINGLE_BATTLE_TEST("Magic Guard ignores immobilization that can be caused by paralysis") +{ + if (B_MAGIC_GUARD >= GEN_4) + PASSES_RANDOMLY(1, 1, RNG_PARALYSIS); + else + PASSES_RANDOMLY(75, 100, RNG_PARALYSIS); + GIVEN { + PLAYER(SPECIES_CLEFABLE) { Ability(ABILITY_MAGIC_GUARD); Status1(STATUS1_PARALYSIS);} + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} + +SINGLE_BATTLE_TEST("Magic Guard does not ignore speed stat changes caused by paralysis") +{ + GIVEN { + PLAYER(SPECIES_CLEFABLE) { Speed(100); Ability(ABILITY_MAGIC_GUARD); Status1(STATUS1_PARALYSIS);} + OPPONENT(SPECIES_WOBBUFFET) { Speed(99); } + } WHEN { + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + } +} diff --git a/test/battle/ability/magician.c b/test/battle/ability/magician.c index 14e553a76330..f622ac07df0a 100644 --- a/test/battle/ability/magician.c +++ b/test/battle/ability/magician.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Magician does not get self-damage recoil after stealing Life { GIVEN { ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_DELPHOX) { Ability(ABILITY_MAGICIAN); Item(ITEM_NONE); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LIFE_ORB); } } WHEN { diff --git a/test/battle/ability/mimicry.c b/test/battle/ability/mimicry.c new file mode 100644 index 000000000000..fbdb5cf98aee --- /dev/null +++ b/test/battle/ability/mimicry.c @@ -0,0 +1,72 @@ +#include "global.h" +#include "test/battle.h" + +static const u16 terrainData[][2] = +{ + { MOVE_ELECTRIC_TERRAIN, TYPE_ELECTRIC, }, + { MOVE_PSYCHIC_TERRAIN, TYPE_PSYCHIC, }, + { MOVE_GRASSY_TERRAIN, TYPE_GRASS, }, + { MOVE_MISTY_TERRAIN, TYPE_FAIRY, }, +}; + +SINGLE_BATTLE_TEST("Mimicry changes the battler's type based on Terrain") +{ + u32 j; + u32 terrainMove = MOVE_NONE; + u32 terrainType = TYPE_NONE; + + for (j = 0; j < ARRAY_COUNT(terrainData); j++) + PARAMETRIZE { terrainMove = terrainData[j][0]; terrainType = terrainData[j][1]; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } + } WHEN { + TURN { MOVE(player, terrainMove); } + } SCENE { + ABILITY_POPUP(opponent); + switch (terrainMove) + { + case MOVE_ELECTRIC_TERRAIN: MESSAGE("The opposing Stunfisk's type changed to Electric!"); break; + case MOVE_PSYCHIC_TERRAIN: MESSAGE("The opposing Stunfisk's type changed to Psychic!"); break; + case MOVE_GRASSY_TERRAIN: MESSAGE("The opposing Stunfisk's type changed to Grass!"); break; + case MOVE_MISTY_TERRAIN: MESSAGE("The opposing Stunfisk's type changed to Fairy!"); break; + } + } THEN { + EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[0], terrainType); + EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[1], terrainType); + } +} + +SINGLE_BATTLE_TEST("Mimicry restores the battler's types when terrain is removed by Steel Roller and Ice Spinner") +{ + u32 j; + u32 terrainMove = MOVE_NONE; + u32 removeTerrainMove = MOVE_NONE; + + for (j = 0; j < ARRAY_COUNT(terrainData); j++) + { + PARAMETRIZE { removeTerrainMove = MOVE_STEEL_ROLLER; terrainMove = terrainData[j][0]; } + PARAMETRIZE { removeTerrainMove = MOVE_ICE_SPINNER; terrainMove = terrainData[j][0]; } + } + + GIVEN { + ASSUME(gSpeciesInfo[SPECIES_STUNFISK_GALAR].types[0] == TYPE_GROUND); + ASSUME(gSpeciesInfo[SPECIES_STUNFISK_GALAR].types[1] == TYPE_STEEL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } + } WHEN { + TURN { MOVE(opponent, terrainMove); MOVE(player, removeTerrainMove); } + } SCENE { + switch (terrainMove) + { + case MOVE_ELECTRIC_TERRAIN: MESSAGE("The electricity disappeared from the battlefield."); break; + case MOVE_PSYCHIC_TERRAIN: MESSAGE("The weirdness disappeared from the battlefield!"); break; + case MOVE_GRASSY_TERRAIN: MESSAGE("The grass disappeared from the battlefield."); break; + case MOVE_MISTY_TERRAIN: MESSAGE("The mist disappeared from the battlefield."); break; + } + } THEN { + EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[0], TYPE_GROUND); + EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[1], TYPE_STEEL); + } +} diff --git a/test/battle/ability/minds_eye.c b/test/battle/ability/minds_eye.c index bf50fa0e2eeb..59c81746c74f 100644 --- a/test/battle/ability/minds_eye.c +++ b/test/battle/ability/minds_eye.c @@ -48,7 +48,7 @@ AI_SINGLE_BATTLE_TEST("AI doesn't use accuracy-lowering moves if it knows that t for (j = MOVE_NONE + 1; j < MOVES_COUNT; j++) { - if (gMovesInfo[j].effect == EFFECT_ACCURACY_DOWN || gMovesInfo[j].effect == EFFECT_ACCURACY_DOWN_2) { + if (GetMoveEffect(j) == EFFECT_ACCURACY_DOWN || GetMoveEffect(j) == EFFECT_ACCURACY_DOWN_2) { PARAMETRIZE { moveAI = j; abilityAI = ABILITY_SWIFT_SWIM; } PARAMETRIZE { moveAI = j; abilityAI = ABILITY_MOLD_BREAKER; } } diff --git a/test/battle/ability/mirror_armor.c b/test/battle/ability/mirror_armor.c index 288fe72334eb..5aa2b55ef317 100644 --- a/test/battle/ability/mirror_armor.c +++ b/test/battle/ability/mirror_armor.c @@ -171,8 +171,8 @@ DOUBLE_BATTLE_TEST("Mirror Armor lowers Speed of the partner Pokemon after Court { KNOWN_FAILING; GIVEN { - ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); - ASSUME(gMovesInfo[MOVE_COURT_CHANGE].effect == EFFECT_COURT_CHANGE); + ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB); + ASSUME(GetMoveEffect(MOVE_COURT_CHANGE) == EFFECT_COURT_CHANGE); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); } diff --git a/test/battle/ability/misty_surge.c b/test/battle/ability/misty_surge.c new file mode 100644 index 000000000000..229d26c3ba80 --- /dev/null +++ b/test/battle/ability/misty_surge.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Misty Surge creates Misty Terrain when entering the battle"); diff --git a/test/battle/ability/moxie.c b/test/battle/ability/moxie.c index d6c7d11d9d89..35ae64d164b9 100644 --- a/test/battle/ability/moxie.c +++ b/test/battle/ability/moxie.c @@ -8,7 +8,7 @@ DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh raises Attack by one stage after direct PARAMETRIZE { species = SPECIES_GLASTRIER; ability = ABILITY_CHILLING_NEIGH; abilityPopUp = ABILITY_CHILLING_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(species) { Ability(ability); } PLAYER(SPECIES_SNORUNT) { HP(1); } OPPONENT(SPECIES_GLALIE) { HP(1); } @@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Moxie/Chilling Neigh does not trigger when already at maximu PARAMETRIZE { species = SPECIES_GLASTRIER; ability = ABILITY_CHILLING_NEIGH; abilityPopUp = ABILITY_CHILLING_NEIGH; } PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } GIVEN { - ASSUME(gMovesInfo[MOVE_BELLY_DRUM].effect == EFFECT_BELLY_DRUM); + ASSUME(GetMoveEffect(MOVE_BELLY_DRUM) == EFFECT_BELLY_DRUM); PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_SNORUNT) { HP(1); } OPPONENT(SPECIES_SNORUNT); @@ -123,7 +123,7 @@ DOUBLE_BATTLE_TEST("Moxie/Chilling Neigh does not increase damage done by the sa PARAMETRIZE { species = SPECIES_CALYREX_ICE; ability = ABILITY_AS_ONE_ICE_RIDER; abilityPopUp = ABILITY_CHILLING_NEIGH; } GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(species) { Ability(ability); } PLAYER(SPECIES_ABRA) { HP(1); } OPPONENT(SPECIES_GLALIE); diff --git a/test/battle/ability/mummy.c b/test/battle/ability/mummy.c index 74461ec2ee24..f03e453e5cb0 100644 --- a/test/battle/ability/mummy.c +++ b/test/battle/ability/mummy.c @@ -10,14 +10,14 @@ SINGLE_BATTLE_TEST("Mummy/Lingering Aroma replace the attacker's ability on cont PARAMETRIZE { move = MOVE_AQUA_JET; ability = ABILITY_LINGERING_AROMA; species = SPECIES_OINKOLOGNE; } PARAMETRIZE { move = MOVE_WATER_GUN; ability = ABILITY_LINGERING_AROMA; species = SPECIES_OINKOLOGNE; } GIVEN { - ASSUME(gMovesInfo[MOVE_AQUA_JET].makesContact); - ASSUME(!gMovesInfo[MOVE_WATER_GUN].makesContact); + ASSUME(MoveMakesContact(MOVE_AQUA_JET)); + ASSUME(!MoveMakesContact(MOVE_WATER_GUN)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { TURN { MOVE(player, move); } } SCENE { - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(opponent, ability); if (ability == ABILITY_MUMMY) MESSAGE("Wobbuffet acquired Mummy!"); @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Mummy and Lingering Aroma don't replace each other") PARAMETRIZE { ability1 = ABILITY_MUMMY; species1 = SPECIES_YAMASK; ability2 = ABILITY_LINGERING_AROMA; species2 = SPECIES_OINKOLOGNE; } PARAMETRIZE { ability1 = ability2 = ABILITY_LINGERING_AROMA; species1 = species2 = SPECIES_OINKOLOGNE; } GIVEN { - ASSUME(gMovesInfo[MOVE_AQUA_JET].makesContact); + ASSUME(MoveMakesContact(MOVE_AQUA_JET)); PLAYER(species1) { Ability(ability1); Speed(2); } OPPONENT(species2) { Ability(ability2); Speed(1); } } WHEN { diff --git a/test/battle/ability/neuroforce.c b/test/battle/ability/neuroforce.c index 88af00b722d3..bd40982d0295 100644 --- a/test/battle/ability/neuroforce.c +++ b/test/battle/ability/neuroforce.c @@ -10,8 +10,8 @@ SINGLE_BATTLE_TEST("Neuroforce increases the strength of super-effective moves b PARAMETRIZE { ability = ABILITY_NEUROFORCE; move = MOVE_TACKLE; } PARAMETRIZE { ability = ABILITY_KLUTZ; move = MOVE_TACKLE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST); - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_SHADOW_BALL) == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); PLAYER(SPECIES_NECROZMA_ULTRA) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/oblivious.c b/test/battle/ability/oblivious.c index 70bf94192370..3ac979a271ba 100644 --- a/test/battle/ability/oblivious.c +++ b/test/battle/ability/oblivious.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Oblivious prevents Infatuation") { GIVEN { - ASSUME(gMovesInfo[MOVE_ATTRACT].effect == EFFECT_ATTRACT); + ASSUME(GetMoveEffect(MOVE_ATTRACT) == EFFECT_ATTRACT); PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); Gender(MON_MALE); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); } } WHEN { @@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Oblivious prevents Infatuation") SINGLE_BATTLE_TEST("Oblivious prevents Captivate") { GIVEN { - ASSUME(gMovesInfo[MOVE_CAPTIVATE].effect == EFFECT_CAPTIVATE); + ASSUME(GetMoveEffect(MOVE_CAPTIVATE) == EFFECT_CAPTIVATE); PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); Gender(MON_MALE); } OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); } } WHEN { @@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Oblivious prevents Captivate") SINGLE_BATTLE_TEST("Oblivious prevents Taunt") { GIVEN { - ASSUME(gMovesInfo[MOVE_TAUNT].effect == EFFECT_TAUNT); + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); ASSUME(B_OBLIVIOUS_TAUNT >= GEN_6); PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/opportunist.c b/test/battle/ability/opportunist.c index 662d442dbc8c..2abd4834666f 100644 --- a/test/battle/ability/opportunist.c +++ b/test/battle/ability/opportunist.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Opportunist only copies foe's positive stat changes in a turn", s16 damage) diff --git a/test/battle/ability/overcoat.c b/test/battle/ability/overcoat.c index b73f098e783c..96f3ffcb087c 100644 --- a/test/battle/ability/overcoat.c +++ b/test/battle/ability/overcoat.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove); + ASSUME(IsPowderMove(MOVE_STUN_SPORE)); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PINECO) { Ability(ABILITY_OVERCOAT); } } WHEN { diff --git a/test/battle/ability/overgrow.c b/test/battle/ability/overgrow.c index 0bc2d7cdd597..3ba779009306 100644 --- a/test/battle/ability/overgrow.c +++ b/test/battle/ability/overgrow.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Overgrow boosts Grass-type moves in a pinch", s16 damage) PARAMETRIZE { hp = 99; } PARAMETRIZE { hp = 33; } GIVEN { - ASSUME(gMovesInfo[MOVE_VINE_WHIP].type == TYPE_GRASS); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); PLAYER(SPECIES_BULBASAUR) { Ability(ABILITY_OVERGROW); MaxHP(99); HP(hp); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/own_tempo.c b/test/battle/ability/own_tempo.c index 4b3c42053b77..a6dd8c459171 100644 --- a/test/battle/ability/own_tempo.c +++ b/test/battle/ability/own_tempo.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Own Tempo prevents Intimidate but no other stat down changes { GIVEN { ASSUME(B_UPDATED_INTIMIDATE >= GEN_8); - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }; OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }; } WHEN { @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Own Tempo prevents Intimidate but no other stat down changes SINGLE_BATTLE_TEST("Own Tempo prevents confusion from moves by the opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }; } WHEN { @@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Own Tempo is ignored by Mold Breaker") { KNOWN_FAILING; // Ideally the func CanBeConfused should be split into AttackerCanBeConfused and TargetCanBeConfused or we do it in the same func but have a check for when battlerAtk == battlerDef GIVEN { - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }; } WHEN { @@ -77,7 +77,7 @@ SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mol { KNOWN_FAILING; GIVEN { - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }; OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }; } WHEN { @@ -96,8 +96,8 @@ SINGLE_BATTLE_TEST("Own Tempo cures confusion obtained from an opponent with Mol SINGLE_BATTLE_TEST("Own Tempo cures confusion if it's obtained via Skill Swap") { GIVEN { - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].effect == EFFECT_CONFUSE); - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); + ASSUME(GetMoveEffect(MOVE_CONFUSE_RAY) == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); }; OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/parental_bond.c b/test/battle/ability/parental_bond.c index a1614a8ffc32..29f137f6af2e 100644 --- a/test/battle/ability/parental_bond.c +++ b/test/battle/ability/parental_bond.c @@ -4,9 +4,9 @@ SINGLE_BATTLE_TEST("Parental Bond converts Tackle into a two-strike move") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_TACKLE].strikeCount < 2); - ASSUME(gMovesInfo[MOVE_TACKLE].effect == EFFECT_HIT); + ASSUME(GetMoveCategory(MOVE_TACKLE) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveStrikeCount(MOVE_TACKLE) < 2); + ASSUME(GetMoveEffect(MOVE_TACKLE) == EFFECT_HIT); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -27,8 +27,8 @@ SINGLE_BATTLE_TEST("Parental Bond converts Tackle into a two-strike move") SINGLE_BATTLE_TEST("Parental Bond does not convert a move with three or more strikes to a two-strike move") { GIVEN { - ASSUME(gMovesInfo[MOVE_TRIPLE_KICK].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_TRIPLE_KICK].strikeCount == 3); + ASSUME(GetMoveCategory(MOVE_TRIPLE_KICK) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveStrikeCount(MOVE_TRIPLE_KICK) == 3); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -54,10 +54,10 @@ SINGLE_BATTLE_TEST("Parental Bond converts multi-target moves into a two-strike PARAMETRIZE { move = MOVE_ICY_WIND; } GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].strikeCount < 2); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_ICY_WIND].strikeCount < 2); - ASSUME(gMovesInfo[MOVE_ICY_WIND].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveStrikeCount(MOVE_EARTHQUAKE) < 2); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveStrikeCount(MOVE_ICY_WIND) < 2); + ASSUME(GetMoveTarget(MOVE_ICY_WIND) == MOVE_TARGET_BOTH); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -78,8 +78,8 @@ SINGLE_BATTLE_TEST("Parental Bond converts multi-target moves into a two-strike DOUBLE_BATTLE_TEST("Parental Bond does not convert multi-target moves into a two-strike move in Double Battles, even if it only damages one") { GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].strikeCount < 2); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveStrikeCount(MOVE_EARTHQUAKE) < 2); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); ASSUME(gSpeciesInfo[SPECIES_PIDGEY].types[1] == TYPE_FLYING); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } PLAYER(SPECIES_PIDGEY); @@ -109,8 +109,8 @@ SINGLE_BATTLE_TEST("Parental Bond-converted moves only hit once on Lightning Rod PARAMETRIZE { move = MOVE_THUNDERBOLT; ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; type = TYPE_ELECTRIC; } PARAMETRIZE { move = MOVE_SURF; ability = ABILITY_STORM_DRAIN; species = SPECIES_LILEEP; type = TYPE_WATER; } GIVEN { - ASSUME(gMovesInfo[move].strikeCount < 2); - ASSUME(gMovesInfo[move].type == type); + ASSUME(GetMoveStrikeCount(move) < 2); + ASSUME(GetMoveType(move) == type); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(species) { Ability(ability); } } WHEN { @@ -137,8 +137,8 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil GIVEN { ASSUME(B_MULTI_HIT_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -163,8 +163,8 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil GIVEN { ASSUME(B_MULTI_HIT_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -190,8 +190,8 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil GIVEN { ASSUME(B_MULTI_HIT_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -218,8 +218,8 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil GIVEN { ASSUME(B_MULTI_HIT_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_COMET_PUNCH].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveCategory(MOVE_COMET_PUNCH) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_COMET_PUNCH) == EFFECT_MULTI_HIT); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -242,8 +242,8 @@ SINGLE_BATTLE_TEST("Parental Bond has no affect on multi hit moves and they stil SINGLE_BATTLE_TEST("Parental Bond Smack Down effect triggers after 2nd hit") { GIVEN { - ASSUME(gMovesInfo[MOVE_SMACK_DOWN].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_SMACK_DOWN].strikeCount < 2); + ASSUME(GetMoveCategory(MOVE_SMACK_DOWN) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveStrikeCount(MOVE_SMACK_DOWN) < 2); ASSUME(MoveHasAdditionalEffect(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN)); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_SKARMORY); @@ -267,7 +267,7 @@ SINGLE_BATTLE_TEST("Parental Bond Snore strikes twice while asleep") { s16 damage[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_SNORE].effect == EFFECT_SNORE); + ASSUME(GetMoveEffect(MOVE_SNORE) == EFFECT_SNORE); PLAYER(SPECIES_KANGASKHAN_MEGA) { Status1(STATUS1_SLEEP); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -289,7 +289,7 @@ SINGLE_BATTLE_TEST("Parental Bond Snore strikes twice while asleep") SINGLE_BATTLE_TEST("Parental Bond only triggers Dragon Tail's target switch out on the second hit") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); PLAYER(SPECIES_KANGASKHAN) { Item(ITEM_KANGASKHANITE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/ability/pastel_veil.c b/test/battle/ability/pastel_veil.c index a6b6168547eb..686ca0ff85df 100644 --- a/test/battle/ability/pastel_veil.c +++ b/test/battle/ability/pastel_veil.c @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Pastel Veil immediately cures Mold Breaker poison") { KNOWN_FAILING; GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } OPPONENT(SPECIES_PONYTA_GALAR) { Ability(ABILITY_PASTEL_VEIL); } } WHEN { @@ -53,7 +53,7 @@ SINGLE_BATTLE_TEST("Pastel Veil immediately cures Mold Breaker poison") DOUBLE_BATTLE_TEST("Pastel Veil does not cure Mold Breaker poison on partner") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PONYTA_GALAR) { Ability(ABILITY_PASTEL_VEIL); } @@ -70,7 +70,7 @@ DOUBLE_BATTLE_TEST("Pastel Veil does not cure Mold Breaker poison on partner") SINGLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PONYTA_GALAR) { Ability(ABILITY_PASTEL_VEIL); } } WHEN { @@ -86,7 +86,7 @@ SINGLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison") DOUBLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison on partner") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PONYTA_GALAR) { Ability(ABILITY_PASTEL_VEIL); } @@ -104,7 +104,7 @@ DOUBLE_BATTLE_TEST("Pastel Veil prevents Toxic bad poison on partner") SINGLE_BATTLE_TEST("Pastel Veil prevents Toxic Spikes poison") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PONYTA_GALAR) { Ability(ABILITY_PASTEL_VEIL); } @@ -120,7 +120,7 @@ SINGLE_BATTLE_TEST("Pastel Veil prevents Toxic Spikes poison") DOUBLE_BATTLE_TEST("Pastel Veil prevents Toxic Spikes poison on partner") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PONYTA_GALAR) { Ability(ABILITY_PASTEL_VEIL); } diff --git a/test/battle/ability/pickup.c b/test/battle/ability/pickup.c index a6dabb66cc91..22db259399a6 100644 --- a/test/battle/ability/pickup.c +++ b/test/battle/ability/pickup.c @@ -120,7 +120,7 @@ SINGLE_BATTLE_TEST("Pickup doesn't grant an item after its holder faints") SINGLE_BATTLE_TEST("Pickup doesn't grant an used item if holder is replaced") { GIVEN { - ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT); + ASSUME(GetMoveEffect(MOVE_PARTING_SHOT) == EFFECT_PARTING_SHOT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); } OPPONENT(SPECIES_WOBBUFFET) { MaxHP(300); HP(151); Item(ITEM_SITRUS_BERRY); } @@ -202,7 +202,7 @@ SINGLE_BATTLE_TEST("Pickup doesn't grant an item if the user eats it with Bug Bi SINGLE_BATTLE_TEST("Pickup doesn't grant an used item if its user already restored it") { GIVEN { - ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + ASSUME(GetMoveEffect(MOVE_RECYCLE) == EFFECT_RECYCLE); PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); } OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); HP(51); Item(ITEM_SITRUS_BERRY); } } WHEN { @@ -222,7 +222,7 @@ SINGLE_BATTLE_TEST("Pickup doesn't grant an used item if its user already restor SINGLE_BATTLE_TEST("Pickup restores an item that has been Flinged") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING); + ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING); PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); } } WHEN { @@ -239,7 +239,7 @@ SINGLE_BATTLE_TEST("Pickup restores an item that has been Flinged") SINGLE_BATTLE_TEST("Pickup restores an item that was used by Natural Gift") { GIVEN { - ASSUME(gMovesInfo[MOVE_NATURAL_GIFT].effect == EFFECT_NATURAL_GIFT); + ASSUME(GetMoveEffect(MOVE_NATURAL_GIFT) == EFFECT_NATURAL_GIFT); PLAYER(SPECIES_ZIGZAGOON) { Ability(ABILITY_PICKUP); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SITRUS_BERRY); } } WHEN { diff --git a/test/battle/ability/pixilate.c b/test/battle/ability/pixilate.c index 97c9c37a0c7c..44289769a6f9 100644 --- a/test/battle/ability/pixilate.c +++ b/test/battle/ability/pixilate.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); } SINGLE_BATTLE_TEST("Pixilate turns a Normal-type move into a Fairy-type move") diff --git a/test/battle/ability/poison_point.c b/test/battle/ability/poison_point.c index 9f9cd5e900cd..635698379cbb 100644 --- a/test/battle/ability/poison_point.c +++ b/test/battle/ability/poison_point.c @@ -7,15 +7,15 @@ SINGLE_BATTLE_TEST("Poison Point inflicts poison on contact") PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_SWIFT)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_NIDORAN_M) { Ability(ABILITY_POISON_POINT); } } WHEN { TURN { MOVE(player, move); } TURN {} } SCENE { - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(opponent, ABILITY_POISON_POINT); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, player); MESSAGE("Wobbuffet was poisoned by the opposing Nidoran♂'s Poison Point!"); @@ -36,7 +36,7 @@ SINGLE_BATTLE_TEST("Poison Point triggers 30% of the time") PASSES_RANDOMLY(3, 10, RNG_POISON_POINT); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_NIDORAN_M) { Ability(ABILITY_POISON_POINT); } } WHEN { diff --git a/test/battle/ability/poison_puppeteer.c b/test/battle/ability/poison_puppeteer.c index b8124b975bef..d5c470ad3747 100644 --- a/test/battle/ability/poison_puppeteer.c +++ b/test/battle/ability/poison_puppeteer.c @@ -53,7 +53,7 @@ SINGLE_BATTLE_TEST("Poison Puppeteer confuses target if it was (badly) poisoned SINGLE_BATTLE_TEST("Poison Puppeteer does not trigger if poison is Toxic Spikes induced") { GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); PLAYER(SPECIES_PECHARUNT) { Ability(ABILITY_POISON_PUPPETEER); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/poison_touch.c b/test/battle/ability/poison_touch.c index 8fb4d243fb71..530d36179438 100644 --- a/test/battle/ability/poison_touch.c +++ b/test/battle/ability/poison_touch.c @@ -5,8 +5,8 @@ SINGLE_BATTLE_TEST("Poison Touch has a 30% chance to poison when attacking with { PASSES_RANDOMLY(3, 10, RNG_POISON_TOUCH); GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -27,15 +27,15 @@ SINGLE_BATTLE_TEST("Poison Touch only applies when using contact moves") PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_SWIFT)); PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { TURN { MOVE(player, move); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, move, player); - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(player, ABILITY_POISON_TOUCH); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); MESSAGE("The opposing Wobbuffet was poisoned by Grimer's Poison Touch!"); @@ -54,8 +54,8 @@ SINGLE_BATTLE_TEST("Poison Touch only applies when using contact moves") SINGLE_BATTLE_TEST("Poison Touch applies between multi-hit move hits") { GIVEN { - ASSUME(gMovesInfo[MOVE_ARM_THRUST].effect == EFFECT_MULTI_HIT); - ASSUME(gMovesInfo[MOVE_ARM_THRUST].makesContact); + ASSUME(GetMoveEffect(MOVE_ARM_THRUST) == EFFECT_MULTI_HIT); + ASSUME(MoveMakesContact(MOVE_ARM_THRUST)); ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN); PLAYER(SPECIES_GRIMER) { Ability(ABILITY_POISON_TOUCH); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_PECHA_BERRY); }; diff --git a/test/battle/ability/prankster.c b/test/battle/ability/prankster.c index c56950672930..cf297214d9ab 100644 --- a/test/battle/ability/prankster.c +++ b/test/battle/ability/prankster.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gSpeciesInfo[SPECIES_UMBREON].types[0] == TYPE_DARK); - ASSUME(gMovesInfo[MOVE_CONFUSE_RAY].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveCategory(MOVE_CONFUSE_RAY) == DAMAGE_CATEGORY_STATUS); } SINGLE_BATTLE_TEST("Prankster-affected moves don't affect Dark-type Pokémon") @@ -135,7 +135,7 @@ SINGLE_BATTLE_TEST("Prankster is blocked by Quick Guard in Gen5+") DOUBLE_BATTLE_TEST("Prankster-affected moves that target all Pokémon are successful regardless of the presence of Dark-type Pokémon") { GIVEN { - ASSUME(gMovesInfo[MOVE_CAPTIVATE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_CAPTIVATE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_ILLUMISE) { Ability(ABILITY_PRANKSTER); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_UMBREON); diff --git a/test/battle/ability/primordial_sea.c b/test/battle/ability/primordial_sea.c index 01ed892874a4..e895d8ba4834 100644 --- a/test/battle/ability/primordial_sea.c +++ b/test/battle/ability/primordial_sea.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(!IS_MOVE_STATUS(MOVE_EMBER)); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(!IsBattleMoveStatus(MOVE_EMBER)); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); } SINGLE_BATTLE_TEST("Primordial Sea blocks damaging Fire-type moves") @@ -32,9 +32,9 @@ SINGLE_BATTLE_TEST("Primordial Sea blocks damaging Fire-type moves") DOUBLE_BATTLE_TEST("Primordial Sea blocks damaging Fire-type moves and prints the message only once with moves hitting multiple targets") { GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_ERUPTION)); - ASSUME(gMovesInfo[MOVE_ERUPTION].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_ERUPTION].target == MOVE_TARGET_BOTH); + ASSUME(!IsBattleMoveStatus(MOVE_ERUPTION)); + ASSUME(GetMoveType(MOVE_ERUPTION) == TYPE_FIRE); + ASSUME(GetMoveTarget(MOVE_ERUPTION) == MOVE_TARGET_BOTH); PLAYER(SPECIES_KYOGRE) {Item(ITEM_BLUE_ORB); {Speed(5);}} PLAYER(SPECIES_WOBBUFFET) {Speed(5);} OPPONENT(SPECIES_WOBBUFFET) {Speed(10);} diff --git a/test/battle/ability/protosynthesis.c b/test/battle/ability/protosynthesis.c index 2be9f81d284d..5a468893e5c1 100644 --- a/test/battle/ability/protosynthesis.c +++ b/test/battle/ability/protosynthesis.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_ROUND].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); } SINGLE_BATTLE_TEST("Protosynthesis boosts the highest stat") diff --git a/test/battle/ability/psychic_surge.c b/test/battle/ability/psychic_surge.c new file mode 100644 index 000000000000..d840e8d44032 --- /dev/null +++ b/test/battle/ability/psychic_surge.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Psychic Surge creates Psychic Terrain when entering the battle"); diff --git a/test/battle/ability/purifying_salt.c b/test/battle/ability/purifying_salt.c index 495ce01a468f..cb8fc6ca569c 100644 --- a/test/battle/ability/purifying_salt.c +++ b/test/battle/ability/purifying_salt.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Purifying Salt halves damage from Ghost-type moves", s16 dam PARAMETRIZE { ability = ABILITY_STURDY; } PARAMETRIZE { ability = ABILITY_PURIFYING_SALT; } GIVEN { - ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_SHADOW_BALL) == TYPE_GHOST); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GARGANACL) { Ability(ability); } } WHEN { @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Purifying Salt halves damage from dynamic Ghost-type moves", PARAMETRIZE { ability = ABILITY_STURDY; } PARAMETRIZE { ability = ABILITY_PURIFYING_SALT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TERA_BLAST].effect == EFFECT_TERA_BLAST); + ASSUME(GetMoveEffect(MOVE_TERA_BLAST) == EFFECT_TERA_BLAST); PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GHOST); } OPPONENT(SPECIES_GARGANACL) { Ability(ability); } } WHEN { @@ -61,10 +61,10 @@ SINGLE_BATTLE_TEST("Purifying Salt grants immunity to status effects") PARAMETRIZE { move = MOVE_TOXIC; status = STATUS1_TOXIC_POISON; } PARAMETRIZE { move = MOVE_POWDER_SNOW; status = STATUS1_FREEZE; } GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); - ASSUME(gMovesInfo[MOVE_HYPNOSIS].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_THUNDER_WAVE].effect == EFFECT_PARALYZE); - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_HYPNOSIS) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_THUNDER_WAVE) == EFFECT_PARALYZE); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); ASSUME(MoveHasAdditionalEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_PURIFYING_SALT); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/quark_drive.c b/test/battle/ability/quark_drive.c index 928ee45eb581..edefdc130595 100644 --- a/test/battle/ability/quark_drive.c +++ b/test/battle/ability/quark_drive.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_ROUND].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); } SINGLE_BATTLE_TEST("Quark Drive boosts the highest stat") diff --git a/test/battle/ability/rain_dish.c b/test/battle/ability/rain_dish.c index 93f642c633a2..dc7de954c377 100644 --- a/test/battle/ability/rain_dish.c +++ b/test/battle/ability/rain_dish.c @@ -2,7 +2,7 @@ #include "test/battle.h" ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_RAIN_DANCE].effect == EFFECT_RAIN_DANCE); + ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE); } SINGLE_BATTLE_TEST("Rain Dish recovers 1/16th of Max HP in Rain") diff --git a/test/battle/ability/rattled.c b/test/battle/ability/rattled.c index da8157d28af7..465a6889515c 100644 --- a/test/battle/ability/rattled.c +++ b/test/battle/ability/rattled.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FURY_CUTTER].type == TYPE_BUG); - ASSUME(!IS_MOVE_STATUS(MOVE_FURY_CUTTER)); - ASSUME(gMovesInfo[MOVE_FEINT_ATTACK].type == TYPE_DARK); - ASSUME(!IS_MOVE_STATUS(MOVE_FEINT_ATTACK)); - ASSUME(gMovesInfo[MOVE_SHADOW_PUNCH].type == TYPE_GHOST); - ASSUME(!IS_MOVE_STATUS(MOVE_SHADOW_PUNCH)); - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(GetMoveType(MOVE_FURY_CUTTER) == TYPE_BUG); + ASSUME(!IsBattleMoveStatus(MOVE_FURY_CUTTER)); + ASSUME(GetMoveType(MOVE_FEINT_ATTACK) == TYPE_DARK); + ASSUME(!IsBattleMoveStatus(MOVE_FEINT_ATTACK)); + ASSUME(GetMoveType(MOVE_SHADOW_PUNCH) == TYPE_GHOST); + ASSUME(!IsBattleMoveStatus(MOVE_SHADOW_PUNCH)); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); } SINGLE_BATTLE_TEST("Rattled boosts speed by 1 when hit by Bug, Dark or Ghost type move") @@ -73,8 +73,8 @@ SINGLE_BATTLE_TEST("Rattled boosts speed by 1 when affected by Intimidate") SINGLE_BATTLE_TEST("Rattled triggers correctly when hit by U-Turn") // Specific test here, because of #3124 { GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_U_TURN].type == TYPE_BUG); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveType(MOVE_U_TURN) == TYPE_BUG); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_SUDOWOODO) {Ability(ABILITY_RATTLED); } diff --git a/test/battle/ability/refrigerate.c b/test/battle/ability/refrigerate.c index dbbaa30eb8dd..b3f7b59a9e83 100644 --- a/test/battle/ability/refrigerate.c +++ b/test/battle/ability/refrigerate.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); } SINGLE_BATTLE_TEST("Refrigerate turns a Normal-type move into a Ice-type move") diff --git a/test/battle/ability/rocky_payload.c b/test/battle/ability/rocky_payload.c index 27cc45fda0f5..6756b98b8b16 100644 --- a/test/battle/ability/rocky_payload.c +++ b/test/battle/ability/rocky_payload.c @@ -14,11 +14,11 @@ SINGLE_BATTLE_TEST("Rocky Payload increases Rock-type move damage", s16 damage) PARAMETRIZE { move = MOVE_POWER_GEM; ability = ABILITY_ROCKY_PAYLOAD; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_ROCK); - ASSUME(gMovesInfo[MOVE_ROCK_THROW].type == TYPE_ROCK); - ASSUME(gMovesInfo[MOVE_POWER_GEM].type == TYPE_ROCK); - ASSUME(gMovesInfo[MOVE_ROCK_THROW].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_POWER_GEM].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveType(MOVE_TACKLE) != TYPE_ROCK); + ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); + ASSUME(GetMoveType(MOVE_POWER_GEM) == TYPE_ROCK); + ASSUME(GetMoveCategory(MOVE_ROCK_THROW) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_POWER_GEM) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_BOMBIRDIER) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/sand_veil.c b/test/battle/ability/sand_veil.c index f42c2672734b..7622d1876367 100644 --- a/test/battle/ability/sand_veil.c +++ b/test/battle/ability/sand_veil.c @@ -18,7 +18,7 @@ SINGLE_BATTLE_TEST("Sand Veil increases evasion during sandstorm") { PASSES_RANDOMLY(4, 5, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_POUND].accuracy == 100); + ASSUME(GetMoveAccuracy(MOVE_POUND) == 100); PLAYER(SPECIES_SANDSHREW) { Ability(ABILITY_SAND_VEIL); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/sap_sipper.c b/test/battle/ability/sap_sipper.c index d691d4e91a96..aeb746d2c66a 100644 --- a/test/battle/ability/sap_sipper.c +++ b/test/battle/ability/sap_sipper.c @@ -61,7 +61,7 @@ SINGLE_BATTLE_TEST("Sap Sipper does not increase Attack if already maxed") SINGLE_BATTLE_TEST("Sap Sipper blocks multi-hit grass type moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_BULLET_SEED) == EFFECT_MULTI_HIT); PLAYER(SPECIES_MARILL) { Ability(ABILITY_SAP_SIPPER); } OPPONENT(SPECIES_SHELLDER) { Ability(ABILITY_SKILL_LINK); } } WHEN { diff --git a/test/battle/ability/seed_sower.c b/test/battle/ability/seed_sower.c index 5134bc131194..ad4beea515ea 100644 --- a/test/battle/ability/seed_sower.c +++ b/test/battle/ability/seed_sower.c @@ -49,8 +49,8 @@ DOUBLE_BATTLE_TEST("Multi-target moves hit correct battlers after Seed Sower is } GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_ARBOLIVA) { Ability(abilities[B_POSITION_PLAYER_LEFT]); } PLAYER(SPECIES_ARBOLIVA) { Ability(abilities[B_POSITION_PLAYER_RIGHT]); } OPPONENT(SPECIES_ARBOLIVA) { Ability(abilities[B_POSITION_OPPONENT_LEFT]); } diff --git a/test/battle/ability/sharpness.c b/test/battle/ability/sharpness.c index 8ecb07671db1..38ed79f86fc5 100644 --- a/test/battle/ability/sharpness.c +++ b/test/battle/ability/sharpness.c @@ -11,8 +11,8 @@ SINGLE_BATTLE_TEST("Sharpness increases the power of slicing moves", s16 damage) PARAMETRIZE { move = MOVE_SCRATCH; ability = ABILITY_STEADFAST; } GIVEN { - ASSUME(gMovesInfo[MOVE_AERIAL_ACE].slicingMove); - ASSUME(!gMovesInfo[MOVE_SCRATCH].slicingMove); + ASSUME(IsSlicingMove(MOVE_AERIAL_ACE)); + ASSUME(!IsSlicingMove(MOVE_SCRATCH)); PLAYER(SPECIES_GALLADE) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/shed_skin.c b/test/battle/ability/shed_skin.c index e4ab6b736c66..2df293ecb4a8 100644 --- a/test/battle/ability/shed_skin.c +++ b/test/battle/ability/shed_skin.c @@ -8,7 +8,7 @@ SINGLE_BATTLE_TEST("Shed Skin triggers 33% of the time") else PASSES_RANDOMLY(33, 100, RNG_SHED_SKIN); GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_ARBOK) { Status1(STATUS1_POISON); Ability(ABILITY_SHED_SKIN); } } WHEN { diff --git a/test/battle/ability/sheer_force.c b/test/battle/ability/sheer_force.c index e06e56c2c5bd..c5add71df0a2 100644 --- a/test/battle/ability/sheer_force.c +++ b/test/battle/ability/sheer_force.c @@ -616,7 +616,7 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to s16 damage1, damage2; u32 move = 0; for (u32 j = 1; j < MOVES_COUNT; j += 4) - if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + if (GetMoveCategory(j) != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) PARAMETRIZE { move = j; } GIVEN { PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } @@ -653,23 +653,26 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to } else TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + switch (GetMoveEffect(move)) { + case EFFECT_TWO_TURNS_ATTACK: + case EFFECT_SEMI_INVULNERABLE: + case EFFECT_SOLAR_BEAM: + case EFFECT_SKY_DROP: TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) - { - TURN { ; } - TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_BIDE) - { + break; + case EFFECT_FUTURE_SIGHT: + TURN { ; } + TURN { ; } + break; + case EFFECT_BIDE: TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + break; } } SCENE { - if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + if (GetMoveEffect(move) != EFFECT_FUTURE_SIGHT) { HP_BAR(opponentRight, captureDamage: &damage1); HP_BAR(playerRight, captureDamage: &damage2); @@ -691,7 +694,7 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to s16 damage1, damage2; u32 move = 0; for (u32 j = 2; j < MOVES_COUNT; j += 4) - if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + if (GetMoveCategory(j) != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) PARAMETRIZE { move = j; } GIVEN { PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } @@ -728,23 +731,26 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to } else TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + switch (GetMoveEffect(move)) { + case EFFECT_TWO_TURNS_ATTACK: + case EFFECT_SEMI_INVULNERABLE: + case EFFECT_SOLAR_BEAM: + case EFFECT_SKY_DROP: TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) - { - TURN { ; } - TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_BIDE) - { + break; + case EFFECT_FUTURE_SIGHT: + TURN { ; } + TURN { ; } + break; + case EFFECT_BIDE: TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + break; } } SCENE { - if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + if (GetMoveEffect(move) != EFFECT_FUTURE_SIGHT) { HP_BAR(opponentRight, captureDamage: &damage1); HP_BAR(playerRight, captureDamage: &damage2); @@ -766,7 +772,7 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to s16 damage1, damage2; u32 move = 0; for (u32 j = 3; j < MOVES_COUNT; j += 4) - if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + if (GetMoveCategory(j) != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) PARAMETRIZE { move = j; } GIVEN { PLAYER(SPECIES_STEELIX) { Ability(ABILITY_SHEER_FORCE); Item(ITEM_BLUK_BERRY); } @@ -803,23 +809,26 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to } else TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + switch (GetMoveEffect(move)) { + case EFFECT_TWO_TURNS_ATTACK: + case EFFECT_SEMI_INVULNERABLE: + case EFFECT_SOLAR_BEAM: + case EFFECT_SKY_DROP: TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) - { - TURN { ; } - TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_BIDE) - { + break; + case EFFECT_FUTURE_SIGHT: + TURN { ; } + TURN { ; } + break; + case EFFECT_BIDE: TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + break; } } SCENE { - if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + if (GetMoveEffect(move) != EFFECT_FUTURE_SIGHT) { HP_BAR(opponentRight, captureDamage: &damage1); HP_BAR(playerRight, captureDamage: &damage2); @@ -842,7 +851,7 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to u32 move = 0; for (u32 j = 4; j < MOVES_COUNT; j += 4) { - if (gMovesInfo[j].category != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) + if (GetMoveCategory(j) != DAMAGE_CATEGORY_STATUS && !IgnoreMoveForSheerForceBoost(j)) PARAMETRIZE { move = j; } } GIVEN { @@ -880,23 +889,26 @@ DOUBLE_BATTLE_TEST("Sheer Force only boosts the damage of moves it's supposed to } else TURN { MOVE(playerLeft, move, target: opponentRight); MOVE(opponentLeft, move, target: playerRight); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE || gMovesInfo[move].effect == EFFECT_SOLAR_BEAM || gMovesInfo[move].effect == EFFECT_SKY_DROP) + switch (GetMoveEffect(move)) { + case EFFECT_TWO_TURNS_ATTACK: + case EFFECT_SEMI_INVULNERABLE: + case EFFECT_SOLAR_BEAM: + case EFFECT_SKY_DROP: TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_FUTURE_SIGHT) - { - TURN { ; } - TURN { ; } - } - if (gMovesInfo[move].effect == EFFECT_BIDE) - { + break; + case EFFECT_FUTURE_SIGHT: + TURN { ; } + TURN { ; } + break; + case EFFECT_BIDE: TURN { MOVE(opponentRight, MOVE_WATER_GUN, target: playerLeft); MOVE(playerRight, MOVE_WATER_GUN, target: opponentLeft); SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } TURN { SKIP_TURN(playerLeft); SKIP_TURN(opponentLeft); } + break; } } SCENE { - if (gMovesInfo[move].effect != EFFECT_FUTURE_SIGHT) + if (GetMoveEffect(move) != EFFECT_FUTURE_SIGHT) { HP_BAR(opponentRight, captureDamage: &damage1); HP_BAR(playerRight, captureDamage: &damage2); diff --git a/test/battle/ability/shield_dust.c b/test/battle/ability/shield_dust.c index 9374a5f01846..bb56f84211bb 100644 --- a/test/battle/ability/shield_dust.c +++ b/test/battle/ability/shield_dust.c @@ -124,7 +124,6 @@ SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary o DOUBLE_BATTLE_TEST("Shield Dust does or does not block Sparkling Aria depending on number of targets hit") { u32 moveToUse; - KNOWN_FAILING; PARAMETRIZE { moveToUse = MOVE_FINAL_GAMBIT; } PARAMETRIZE { moveToUse = MOVE_TACKLE; } GIVEN { @@ -148,9 +147,22 @@ DOUBLE_BATTLE_TEST("Shield Dust does or does not block Sparkling Aria depending } } +DOUBLE_BATTLE_TEST("Shield Dust blocks Sparkling Aria if all other targets avoid getting hit by") +{ + GIVEN { + PLAYER(SPECIES_PRIMARINA); + PLAYER(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WYNAUT) { Status1(STATUS1_BURN); } + } WHEN { + TURN { MOVE(opponentLeft, MOVE_FLY, target:playerLeft); MOVE(opponentRight, MOVE_PROTECT); MOVE(playerRight, MOVE_CELEBRATE); MOVE(playerLeft, MOVE_SPARKLING_ARIA); } + } SCENE { + NOT MESSAGE("Vivillon's burn was cured!"); + } +} + SINGLE_BATTLE_TEST("Shield Dust blocks Sparkling Aria in singles") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); } diff --git a/test/battle/ability/snow_cloak.c b/test/battle/ability/snow_cloak.c index a4d1acadb7c5..4e129c3ff723 100644 --- a/test/battle/ability/snow_cloak.c +++ b/test/battle/ability/snow_cloak.c @@ -17,7 +17,7 @@ SINGLE_BATTLE_TEST("Snow Cloak increases evasion during hail") { PASSES_RANDOMLY(4, 5, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_POUND].accuracy == 100); + ASSUME(GetMoveAccuracy(MOVE_POUND) == 100); PLAYER(SPECIES_GLACEON) { Ability(ABILITY_SNOW_CLOAK); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/stalwart.c b/test/battle/ability/stalwart.c index 6f8acd6d8290..22debe74cd99 100644 --- a/test/battle/ability/stalwart.c +++ b/test/battle/ability/stalwart.c @@ -24,8 +24,8 @@ DOUBLE_BATTLE_TEST("Stalwart stops Lightning Rod and Storm Drain from redirectin PARAMETRIZE { ability = ABILITY_STORM_DRAIN; species = SPECIES_LUMINEON; } PARAMETRIZE { ability = ABILITY_LIGHTNING_ROD; species = SPECIES_RAICHU; } GIVEN { - ASSUME(gMovesInfo[MOVE_SPARK].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_SPARK) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STALWART); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } diff --git a/test/battle/ability/stamina.c b/test/battle/ability/stamina.c index 5bf7dc09a67e..172154cc8541 100644 --- a/test/battle/ability/stamina.c +++ b/test/battle/ability/stamina.c @@ -24,10 +24,10 @@ SINGLE_BATTLE_TEST("Stamina raises Defense by 1 when hit by a move") PARAMETRIZE {move = MOVE_GUST; } GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); - ASSUME(!IS_MOVE_STATUS(MOVE_GUST)); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_GUST)); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_STAMINA); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -56,7 +56,7 @@ DOUBLE_BATTLE_TEST("Stamina activates correctly for every battler with the abili PARAMETRIZE {abilityLeft = ABILITY_STAMINA, abilityRight = ABILITY_STAMINA; } GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET) { Ability(abilityLeft); Speed(10); } PLAYER(SPECIES_WOBBUFFET) { Ability(abilityRight); Speed(5); } OPPONENT(SPECIES_WOBBUFFET) {Speed(20); } diff --git a/test/battle/ability/stance_change.c b/test/battle/ability/stance_change.c index f8a0c70b3e48..d6e08909f9e0 100644 --- a/test/battle/ability/stance_change.c +++ b/test/battle/ability/stance_change.c @@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Stance Change changes Aegislash from Blade to Shield when us SINGLE_BATTLE_TEST("Stance Change doesn't change Aegislash to Shield if King's Shield is called by a different move - Sleep Talk") { GIVEN { - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); PLAYER(SPECIES_AEGISLASH_BLADE) { Moves(MOVE_KINGS_SHIELD, MOVE_SLEEP_TALK); Status1(STATUS1_SLEEP_TURN(3)); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/static.c b/test/battle/ability/static.c index 3c5d042cd0c9..8d5a27c6b5ba 100644 --- a/test/battle/ability/static.c +++ b/test/battle/ability/static.c @@ -7,14 +7,14 @@ SINGLE_BATTLE_TEST("Static inflicts paralysis on contact") PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_SWIFT].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_SWIFT)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PIKACHU) { Ability(ABILITY_STATIC); } } WHEN { TURN { MOVE(player, move); } } SCENE { - if (gMovesInfo[move].makesContact) { + if (MoveMakesContact(move)) { ABILITY_POPUP(opponent, ABILITY_STATIC); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, player); MESSAGE("The opposing Pikachu's Static paralyzed Wobbuffet, so it may be unable to move!"); @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Static triggers 30% of the time") PASSES_RANDOMLY(3, 10, RNG_STATIC); GIVEN { ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_4); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PIKACHU) { Ability(ABILITY_STATIC); } } WHEN { diff --git a/test/battle/ability/steelworker.c b/test/battle/ability/steelworker.c index 7e8ecbb56886..23d4be2917e6 100644 --- a/test/battle/ability/steelworker.c +++ b/test/battle/ability/steelworker.c @@ -14,11 +14,11 @@ SINGLE_BATTLE_TEST("Steelworker increases Steel-type move damage", s16 damage) PARAMETRIZE { move = MOVE_FLASH_CANNON; ability = ABILITY_STEELWORKER; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_STEEL); - ASSUME(gMovesInfo[MOVE_ANCHOR_SHOT].type == TYPE_STEEL); - ASSUME(gMovesInfo[MOVE_FLASH_CANNON].type == TYPE_STEEL); - ASSUME(gMovesInfo[MOVE_ANCHOR_SHOT].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_FLASH_CANNON].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveType(MOVE_TACKLE) != TYPE_STEEL); + ASSUME(GetMoveType(MOVE_ANCHOR_SHOT) == TYPE_STEEL); + ASSUME(GetMoveType(MOVE_FLASH_CANNON) == TYPE_STEEL); + ASSUME(GetMoveCategory(MOVE_ANCHOR_SHOT) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_FLASH_CANNON) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_DHELMISE) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/stench.c b/test/battle/ability/stench.c index 76b36f3ff342..f1484de6c941 100644 --- a/test/battle/ability/stench.c +++ b/test/battle/ability/stench.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Stench has a 10% chance to flinch") { PASSES_RANDOMLY(1, 10, RNG_STENCH); GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); PLAYER(SPECIES_GRIMER) { Ability(ABILITY_STENCH); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Stench does not stack with King's Rock") PASSES_RANDOMLY(1, 10, RNG_STENCH); GIVEN { ASSUME(gItemsInfo[ITEM_KINGS_ROCK].holdEffect == HOLD_EFFECT_FLINCH); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); PLAYER(SPECIES_GRIMER) { Ability(ABILITY_STENCH); Item(ITEM_KINGS_ROCK); } OPPONENT(SPECIES_WOBBUFFET); @@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Stench does not stack with King's Rock") DOUBLE_BATTLE_TEST("Stench only triggers if target takes damage") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); @@ -58,7 +58,7 @@ DOUBLE_BATTLE_TEST("Stench only triggers if target takes damage") DOUBLE_BATTLE_TEST("Stench doesn't trigger if partner uses a move") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); ASSUME(MoveHasAdditionalEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100)); PLAYER(SPECIES_WOBBUFFET) { Speed(20); } PLAYER(SPECIES_WYNAUT) { Speed(10); } diff --git a/test/battle/ability/storm_drain.c b/test/battle/ability/storm_drain.c index b4d5a2c1691d..962317b10858 100644 --- a/test/battle/ability/storm_drain.c +++ b/test/battle/ability/storm_drain.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. Attack [Gen5+]") { GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GASTRODON_EAST) { Ability(ABILITY_STORM_DRAIN); } } WHEN { @@ -34,7 +34,7 @@ SINGLE_BATTLE_TEST("Storm Drain absorbs Water-type moves and increases the Sp. A DOUBLE_BATTLE_TEST("Storm Drain forces single-target Water-type moves to target the Pokémon with this Ability.") { GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GASTRODON_EAST) { Ability(ABILITY_STORM_DRAIN); } diff --git a/test/battle/ability/sturdy.c b/test/battle/ability/sturdy.c index b79fd5e92196..5ba7e16ea8e8 100644 --- a/test/battle/ability/sturdy.c +++ b/test/battle/ability/sturdy.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Sturdy prevents OHKO moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_FISSURE].effect == EFFECT_OHKO); + ASSUME(GetMoveEffect(MOVE_FISSURE) == EFFECT_OHKO); PLAYER(SPECIES_GEODUDE) { Ability(ABILITY_STURDY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/supreme_overlord.c b/test/battle/ability/supreme_overlord.c index f8868b4afb98..eec81e89eda9 100644 --- a/test/battle/ability/supreme_overlord.c +++ b/test/battle/ability/supreme_overlord.c @@ -95,7 +95,7 @@ SINGLE_BATTLE_TEST("Supreme Overlord does not boost attack if party members are SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Player") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} PLAYER(SPECIES_KINGAMBIT) { Ability(ABILITY_SUPREME_OVERLORD); } OPPONENT(SPECIES_WOBBUFFET); @@ -116,7 +116,7 @@ SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all batt SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} diff --git a/test/battle/ability/swarm.c b/test/battle/ability/swarm.c index c3da16f6b6a8..a70c1ffb5544 100644 --- a/test/battle/ability/swarm.c +++ b/test/battle/ability/swarm.c @@ -7,9 +7,9 @@ SINGLE_BATTLE_TEST("Swarm boosts Bug-type moves in a pinch", s16 damage) PARAMETRIZE { hp = 99; } PARAMETRIZE { hp = 33; } GIVEN { - ASSUME(gMovesInfo[MOVE_BUG_BITE].type == TYPE_BUG); - ASSUME(gMovesInfo[MOVE_BUG_BITE].power == 60); - ASSUME(gMovesInfo[MOVE_BUG_BITE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveType(MOVE_BUG_BITE) == TYPE_BUG); + ASSUME(GetMovePower(MOVE_BUG_BITE) == 60); + ASSUME(GetMoveCategory(MOVE_BUG_BITE) == DAMAGE_CATEGORY_PHYSICAL); ASSUME(gSpeciesInfo[SPECIES_LEDYBA].types[0] == TYPE_BUG); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC); diff --git a/test/battle/ability/sword_of_ruin.c b/test/battle/ability/sword_of_ruin.c index 3498522423a9..9501322ab7df 100644 --- a/test/battle/ability/sword_of_ruin.c +++ b/test/battle/ability/sword_of_ruin.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_ROLE_PLAY].effect == EFFECT_ROLE_PLAY); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_ROLE_PLAY) == EFFECT_ROLE_PLAY); } SINGLE_BATTLE_TEST("Sword of Ruin reduces Defense if opposing mon's ability doesn't match") @@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Sword of Ruin reduces Defense if opposing mon's ability does SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battlers fainted - Player") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} PLAYER(SPECIES_CHIEN_PAO); OPPONENT(SPECIES_WOBBUFFET); @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battler SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battlers fainted - Opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} diff --git a/test/battle/ability/tablets_of_ruin.c b/test/battle/ability/tablets_of_ruin.c index c98384b805f3..976f929bbe35 100644 --- a/test/battle/ability/tablets_of_ruin.c +++ b/test/battle/ability/tablets_of_ruin.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_ENTRAINMENT].effect == EFFECT_ENTRAINMENT); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_ENTRAINMENT) == EFFECT_ENTRAINMENT); } SINGLE_BATTLE_TEST("Tablets of Ruin reduces Attack if opposing mon's ability doesn't match") @@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Tablets of Ruin reduces Attack if opposing mon's ability doe SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battlers fainted - Player") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} PLAYER(SPECIES_WO_CHIEN); OPPONENT(SPECIES_WOBBUFFET); @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battl SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battlers fainted - Opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} diff --git a/test/battle/ability/tangling_hair.c b/test/battle/ability/tangling_hair.c index f663465163c6..45f6282fb878 100644 --- a/test/battle/ability/tangling_hair.c +++ b/test/battle/ability/tangling_hair.c @@ -3,9 +3,9 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].effect == EFFECT_HIT); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact == TRUE); + ASSUME(GetMoveEffect(MOVE_TACKLE) == EFFECT_HIT); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); + ASSUME(MoveMakesContact(MOVE_TACKLE) == TRUE); } @@ -17,7 +17,7 @@ SINGLE_BATTLE_TEST("Tangling Hair drops opposing mon's speed if ability user got PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].makesContact == FALSE); + ASSUME(MoveMakesContact(MOVE_SWIFT) == FALSE); PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_TANGLING_HAIR); } OPPONENT(SPECIES_WYNAUT); } WHEN { diff --git a/test/battle/ability/teraform_zero.c b/test/battle/ability/teraform_zero.c index 819d0eef3d16..09ce92193161 100644 --- a/test/battle/ability/teraform_zero.c +++ b/test/battle/ability/teraform_zero.c @@ -39,8 +39,8 @@ DOUBLE_BATTLE_TEST("Teraform Zero can be supressed") SINGLE_BATTLE_TEST("Teraform Zero can be replaced") { GIVEN { - ASSUME(gMovesInfo[MOVE_WORRY_SEED].effect == EFFECT_WORRY_SEED); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_TERAPAGOS); OPPONENT(SPECIES_WHIMSICOTT) { Ability(ABILITY_PRANKSTER); } } WHEN { @@ -57,7 +57,7 @@ SINGLE_BATTLE_TEST("Teraform Zero can be replaced") SINGLE_BATTLE_TEST("Teraform Zero cannot be swapped") { GIVEN { - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); PLAYER(SPECIES_TERAPAGOS); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -71,7 +71,7 @@ SINGLE_BATTLE_TEST("Teraform Zero cannot be swapped") SINGLE_BATTLE_TEST("Teraform Zero cannot be copied") { GIVEN { - ASSUME(gMovesInfo[MOVE_ROLE_PLAY].effect == EFFECT_ROLE_PLAY); + ASSUME(GetMoveEffect(MOVE_ROLE_PLAY) == EFFECT_ROLE_PLAY); PLAYER(SPECIES_TERAPAGOS); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/torrent.c b/test/battle/ability/torrent.c index df27d8e99670..f0da964b93ee 100644 --- a/test/battle/ability/torrent.c +++ b/test/battle/ability/torrent.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Torrent boosts Water-type moves in a pinch", s16 damage) PARAMETRIZE { hp = 99; } PARAMETRIZE { hp = 33; } GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_SQUIRTLE) { Ability(ABILITY_TORRENT); MaxHP(99); HP(hp); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/toxic_chain.c b/test/battle/ability/toxic_chain.c index c233f5fc92ac..97c3fdf4f917 100644 --- a/test/battle/ability/toxic_chain.c +++ b/test/battle/ability/toxic_chain.c @@ -5,8 +5,8 @@ SINGLE_BATTLE_TEST("Toxic Chain inflicts bad poison when attacking") { PASSES_RANDOMLY(3, 10, RNG_TOXIC_CHAIN); GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveCategory(MOVE_TACKLE) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -24,9 +24,9 @@ SINGLE_BATTLE_TEST("Toxic Chain inflicts bad poison when attacking") SINGLE_BATTLE_TEST("Toxic Chain inflicts bad poison on any hit of a multi-hit move") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].effect == EFFECT_MULTI_HIT); - ASSUME(gMovesInfo[MOVE_DOUBLE_SLAP].power > 0); + ASSUME(GetMoveCategory(MOVE_DOUBLE_SLAP) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SLAP) == EFFECT_MULTI_HIT); + ASSUME(GetMovePower(MOVE_DOUBLE_SLAP) > 0); ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN); PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_PECHA_BERRY); } @@ -51,9 +51,9 @@ SINGLE_BATTLE_TEST("Toxic Chain inflicts bad poison on any hit of a multi-hit mo DOUBLE_BATTLE_TEST("Toxic Chain can inflict bad poison on both foes") { GIVEN { - ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].power > 0); + ASSUME(GetMoveCategory(MOVE_RAZOR_LEAF) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveTarget(MOVE_RAZOR_LEAF) == MOVE_TARGET_BOTH); + ASSUME(GetMovePower(MOVE_RAZOR_LEAF) > 0); PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -85,9 +85,9 @@ SINGLE_BATTLE_TEST("Toxic Chain makes Lum/Pecha Berry trigger before being knock PARAMETRIZE { item = ITEM_LUM_BERRY; } GIVEN { - ASSUME(gMovesInfo[MOVE_KNOCK_OFF].category != DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF); - ASSUME(gMovesInfo[MOVE_KNOCK_OFF].power > 0); + ASSUME(GetMoveCategory(MOVE_KNOCK_OFF) != DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_KNOCK_OFF) == EFFECT_KNOCK_OFF); + ASSUME(GetMovePower(MOVE_KNOCK_OFF) > 0); ASSUME(gItemsInfo[ITEM_PECHA_BERRY].holdEffect == HOLD_EFFECT_CURE_PSN); ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); PLAYER(SPECIES_OKIDOGI) { Ability(ABILITY_TOXIC_CHAIN); } diff --git a/test/battle/ability/toxic_debris.c b/test/battle/ability/toxic_debris.c index c4a50a5d1363..b3b9dbbb2e1f 100644 --- a/test/battle/ability/toxic_debris.c +++ b/test/battle/ability/toxic_debris.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); } SINGLE_BATTLE_TEST("Toxic Debris sets Toxic Spikes on the opposing side if hit by a physical attack") diff --git a/test/battle/ability/transistor.c b/test/battle/ability/transistor.c index 8dd1a1bdb362..eb3c015af7d2 100644 --- a/test/battle/ability/transistor.c +++ b/test/battle/ability/transistor.c @@ -17,11 +17,11 @@ SINGLE_BATTLE_TEST("Transistor increases Electric-type attack / special attack", PARAMETRIZE { move = MOVE_THUNDER_SHOCK; ability = ABILITY_TRANSISTOR; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_WILD_CHARGE].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_WILD_CHARGE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveType(MOVE_TACKLE) != TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_WILD_CHARGE) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetMoveCategory(MOVE_WILD_CHARGE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_THUNDER_SHOCK) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_REGIELEKI) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Transistor is blocked by neutralizing gas", s16 damage) PARAMETRIZE { ability = ABILITY_LEVITATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); PLAYER(SPECIES_REGIELEKI) { Ability(ABILITY_TRANSISTOR); } OPPONENT(SPECIES_KOFFING) { Ability(ability); } } WHEN { diff --git a/test/battle/ability/vessel_of_ruin.c b/test/battle/ability/vessel_of_ruin.c index 6531cbbf3aae..4d159c0b0e18 100644 --- a/test/battle/ability/vessel_of_ruin.c +++ b/test/battle/ability/vessel_of_ruin.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_ENTRAINMENT].effect == EFFECT_ENTRAINMENT); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_ENTRAINMENT) == EFFECT_ENTRAINMENT); } SINGLE_BATTLE_TEST("Vessel of Ruin reduces Sp. Atk if opposing mon's ability doesn't match") @@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Vessel of Ruin reduces Sp. Atk if opposing mon's ability doe SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battlers fainted - Player") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) { HP(1);} PLAYER(SPECIES_TING_LU); OPPONENT(SPECIES_WOBBUFFET); @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battle SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battlers fainted - Opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1);} diff --git a/test/battle/ability/volt_absorb.c b/test/battle/ability/volt_absorb.c index 93498bd1c711..5d88cb95e4d4 100644 --- a/test/battle/ability/volt_absorb.c +++ b/test/battle/ability/volt_absorb.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Volt Absorb heals 25% when hit by electric type moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Volt Absorb heals 25% when hit by electric type moves") SINGLE_BATTLE_TEST("Volt Absorb does not activate if protected") { GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -32,8 +32,8 @@ SINGLE_BATTLE_TEST("Volt Absorb does not activate if protected") SINGLE_BATTLE_TEST("Volt Absorb activates on status moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDER_WAVE].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_THUNDER_WAVE].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveType(MOVE_THUNDER_WAVE) == TYPE_ELECTRIC); + ASSUME(GetMoveCategory(MOVE_THUNDER_WAVE) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -48,8 +48,8 @@ SINGLE_BATTLE_TEST("Volt Absorb activates on status moves") SINGLE_BATTLE_TEST("Volt Absorb is only triggered once on multi strike moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_FURY_SWIPES].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_FURY_SWIPES].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveType(MOVE_FURY_SWIPES) == TYPE_NORMAL); + ASSUME(GetMoveEffect(MOVE_FURY_SWIPES) == EFFECT_MULTI_HIT); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_GRAVELER_ALOLA) { Ability(ABILITY_GALVANIZE); } } WHEN { @@ -65,8 +65,8 @@ DOUBLE_BATTLE_TEST("Volt Absorb does not stop Electric Typed Explosion from dama { s16 damage1, damage2; GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); - ASSUME(gMovesInfo[MOVE_EXPLOSION].type == TYPE_NORMAL); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + ASSUME(GetMoveType(MOVE_EXPLOSION) == TYPE_NORMAL); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(100); } PLAYER(SPECIES_ABRA); OPPONENT(SPECIES_GRAVELER_ALOLA) { Ability(ABILITY_GALVANIZE); } @@ -88,7 +88,7 @@ DOUBLE_BATTLE_TEST("Volt Absorb does not stop Electric Typed Explosion from dama SINGLE_BATTLE_TEST("Volt Absorb prevents Cell Battery from activating") { GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); HP(1); MaxHP(100); Item(ITEM_CELL_BATTERY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/water_absorb.c b/test/battle/ability/water_absorb.c index 842a448bab8c..1c0406ebdc47 100644 --- a/test/battle/ability/water_absorb.c +++ b/test/battle/ability/water_absorb.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Water Absorb heals 25% when hit by water type moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_POLIWAG) { Ability(ABILITY_WATER_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Water Absorb heals 25% when hit by water type moves") SINGLE_BATTLE_TEST("Water Absorb does not activate if protected") { GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_POLIWAG) { Ability(ABILITY_WATER_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -32,8 +32,8 @@ SINGLE_BATTLE_TEST("Water Absorb does not activate if protected") SINGLE_BATTLE_TEST("Water Absorb activates on status moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_SOAK].type == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_SOAK].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveType(MOVE_SOAK) == TYPE_WATER); + ASSUME(GetMoveCategory(MOVE_SOAK) == DAMAGE_CATEGORY_STATUS); PLAYER(SPECIES_POLIWAG) { Ability(ABILITY_WATER_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -48,8 +48,8 @@ SINGLE_BATTLE_TEST("Water Absorb activates on status moves") SINGLE_BATTLE_TEST("Water Absorb is only triggered once on multi strike moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_SHURIKEN].type == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_WATER_SHURIKEN].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveType(MOVE_WATER_SHURIKEN) == TYPE_WATER); + ASSUME(GetMoveEffect(MOVE_WATER_SHURIKEN) == EFFECT_MULTI_HIT); PLAYER(SPECIES_POLIWAG) { Ability(ABILITY_WATER_ABSORB); HP(1); MaxHP(100); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -67,7 +67,7 @@ SINGLE_BATTLE_TEST("Water Absorb prevents Absorb Bulb and Luminous Moss from act PARAMETRIZE { item = ITEM_ABSORB_BULB; } PARAMETRIZE { item = ITEM_LUMINOUS_MOSS; } GIVEN { - ASSUME(gMovesInfo[MOVE_BUBBLE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_BUBBLE) == TYPE_WATER); PLAYER(SPECIES_POLIWAG) { Ability(ABILITY_WATER_ABSORB); HP(1); MaxHP(100); Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/ability/weak_armor.c b/test/battle/ability/weak_armor.c index 0d264e7ff93d..12e9ef3bcc11 100644 --- a/test/battle/ability/weak_armor.c +++ b/test/battle/ability/weak_armor.c @@ -3,10 +3,10 @@ ASSUMPTIONS { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); - ASSUME(!IS_MOVE_STATUS(MOVE_GUST)); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_GUST)); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); ASSUME(B_WEAK_ARMOR_SPEED >= GEN_7); } @@ -50,8 +50,8 @@ SINGLE_BATTLE_TEST("Weak Armor lowers Defense by 1 and boosts Speed by 2 when hi SINGLE_BATTLE_TEST("Weak Armor does not trigger when brought in by Dragon Tail and taking Stealth Rock damage") { GIVEN { - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK); - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/ability/wind_power.c b/test/battle/ability/wind_power.c index 9ad42fad0f20..fd4a4b95f56a 100644 --- a/test/battle/ability/wind_power.c +++ b/test/battle/ability/wind_power.c @@ -3,16 +3,16 @@ ASSUMPTIONS { - ASSUME(!IS_MOVE_STATUS(MOVE_THUNDERBOLT)); - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); - ASSUME(!IS_MOVE_STATUS(MOVE_AIR_CUTTER)); - ASSUME(gMovesInfo[MOVE_AIR_CUTTER].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_AIR_CUTTER].windMove == TRUE); - ASSUME(!IS_MOVE_STATUS(MOVE_PETAL_BLIZZARD)); - ASSUME(gMovesInfo[MOVE_PETAL_BLIZZARD].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_PETAL_BLIZZARD].windMove == TRUE); - ASSUME(gMovesInfo[MOVE_TACKLE].windMove == FALSE); + ASSUME(!IsBattleMoveStatus(MOVE_THUNDERBOLT)); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_AIR_CUTTER)); + ASSUME(GetMoveTarget(MOVE_AIR_CUTTER) == MOVE_TARGET_BOTH); + ASSUME(IsWindMove(MOVE_AIR_CUTTER)); + ASSUME(!IsBattleMoveStatus(MOVE_PETAL_BLIZZARD)); + ASSUME(GetMoveTarget(MOVE_PETAL_BLIZZARD) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(IsWindMove(MOVE_PETAL_BLIZZARD)); + ASSUME(!IsWindMove(MOVE_TACKLE)); } SINGLE_BATTLE_TEST("Wind Power sets up Charge for player when hit by a wind move") @@ -193,7 +193,7 @@ DOUBLE_BATTLE_TEST("Wind Power activates correctly when Tailwind is used") PARAMETRIZE {opponentSide = FALSE;} GIVEN { - ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND); + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); PLAYER(SPECIES_WATTREL) { Ability(ABILITY_WIND_POWER); Speed(10); } PLAYER(SPECIES_WATTREL) { Ability(ABILITY_WIND_POWER); Speed(5); } OPPONENT(SPECIES_WATTREL) { Ability(ABILITY_WIND_POWER); Speed(20); } diff --git a/test/battle/ability/wind_rider.c b/test/battle/ability/wind_rider.c index 44baacc8a229..d68414d060b7 100644 --- a/test/battle/ability/wind_rider.c +++ b/test/battle/ability/wind_rider.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND); - ASSUME(gMovesInfo[MOVE_TAILWIND].windMove == TRUE); + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); + ASSUME(IsWindMove(MOVE_TAILWIND)); } SINGLE_BATTLE_TEST("Wind Rider raises Attack by one stage if it sets up Tailwind") @@ -108,7 +108,7 @@ SINGLE_BATTLE_TEST("Wind Rider activates when it's no longer effected by Neutral SINGLE_BATTLE_TEST("Wind Rider absorbs Wind moves and raises Attack by one stage") { GIVEN { - ASSUME(gMovesInfo[MOVE_GUST].windMove == TRUE); + ASSUME(IsWindMove(MOVE_GUST)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRAMBLIN) { Ability(ABILITY_WIND_RIDER); } } WHEN { diff --git a/test/battle/ability/zero_to_hero.c b/test/battle/ability/zero_to_hero.c index 733104f15301..195bb4428992 100644 --- a/test/battle/ability/zero_to_hero.c +++ b/test/battle/ability/zero_to_hero.c @@ -60,7 +60,7 @@ SINGLE_BATTLE_TEST("Zero to Hero transforms both player and opponent") SINGLE_BATTLE_TEST("Zero to Hero will activate if a switch move is used") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLIP_TURN].effect == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_FLIP_TURN) == EFFECT_HIT_ESCAPE); PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -83,9 +83,9 @@ SINGLE_BATTLE_TEST("Gastro Acid, Worry Seed, and Simple Beam fail if the target PARAMETRIZE { move = MOVE_SIMPLE_BEAM; } GIVEN { - ASSUME(gMovesInfo[MOVE_GASTRO_ACID].effect == EFFECT_GASTRO_ACID); - ASSUME(gMovesInfo[MOVE_WORRY_SEED].effect == EFFECT_WORRY_SEED); - ASSUME(gMovesInfo[MOVE_SIMPLE_BEAM].effect == EFFECT_SIMPLE_BEAM); + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_SIMPLE_BEAM); PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -139,7 +139,7 @@ SINGLE_BATTLE_TEST("Imposter doesn't apply the heroic transformation message whe SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers fainted - Player") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_PALAFIN_ZERO); PLAYER(SPECIES_WOBBUFFET) { HP(1);} OPPONENT(SPECIES_WOBBUFFET); @@ -162,7 +162,7 @@ SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers fainted - Opponent") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PALAFIN_ZERO); diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index 0883e3cc5996..e9b5a2e51c68 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -80,25 +80,25 @@ AI_SINGLE_BATTLE_TEST("AI prefers moves with better accuracy, but only if they b AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(hp); } PLAYER(SPECIES_WOBBUFFET); - ASSUME(gMovesInfo[MOVE_SWIFT].accuracy == 0); - ASSUME(gMovesInfo[MOVE_SLAM].power == gMovesInfo[MOVE_STRENGTH].power); - ASSUME(gMovesInfo[MOVE_MEGA_KICK].power > gMovesInfo[MOVE_STRENGTH].power); - ASSUME(gMovesInfo[MOVE_SLAM].accuracy < gMovesInfo[MOVE_STRENGTH].accuracy); - ASSUME(gMovesInfo[MOVE_MEGA_KICK].accuracy < gMovesInfo[MOVE_STRENGTH].accuracy); - ASSUME(gMovesInfo[MOVE_TACKLE].accuracy == 100); - ASSUME(gMovesInfo[MOVE_GUST].accuracy == 100); - ASSUME(gMovesInfo[MOVE_SHOCK_WAVE].accuracy == 0); - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].accuracy == 100); - ASSUME(gMovesInfo[MOVE_ICY_WIND].accuracy != 100); - ASSUME(gMovesInfo[MOVE_SLAM].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_STRENGTH].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_MEGA_KICK].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_SHOCK_WAVE].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_ICY_WIND].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveAccuracy(MOVE_SWIFT) == 0); + ASSUME(GetMovePower(MOVE_SLAM) == GetMovePower(MOVE_STRENGTH)); + ASSUME(GetMovePower(MOVE_MEGA_KICK) > GetMovePower(MOVE_STRENGTH)); + ASSUME(GetMoveAccuracy(MOVE_SLAM) < GetMoveAccuracy(MOVE_STRENGTH)); + ASSUME(GetMoveAccuracy(MOVE_MEGA_KICK) < GetMoveAccuracy(MOVE_STRENGTH)); + ASSUME(GetMoveAccuracy(MOVE_TACKLE) == 100); + ASSUME(GetMoveAccuracy(MOVE_GUST) == 100); + ASSUME(GetMoveAccuracy(MOVE_SHOCK_WAVE) == 0); + ASSUME(GetMoveAccuracy(MOVE_THUNDERBOLT) == 100); + ASSUME(GetMoveAccuracy(MOVE_ICY_WIND) != 100); + ASSUME(GetMoveCategory(MOVE_SLAM) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_STRENGTH) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_MEGA_KICK) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SHOCK_WAVE) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_ICY_WIND) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_THUNDERBOLT) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); OPPONENT(SPECIES_EXPLOUD) { Moves(move1, move2, move3, move4); Ability(abilityAtk); SpAttack(50); } // Low Sp.Atk, so Swift deals less damage than Strength. } WHEN { switch (turns) @@ -146,10 +146,10 @@ AI_SINGLE_BATTLE_TEST("AI prefers moves which deal more damage instead of moves PARAMETRIZE { move1 = MOVE_POISON_JAB; move2 = MOVE_WATER_GUN; expectedMove = MOVE_POISON_JAB; abilityDef = ABILITY_IMMUNITY; turns = 3; } GIVEN { - ASSUME(gMovesInfo[MOVE_WATERFALL].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SCALD].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_POISON_JAB].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_WATERFALL) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SCALD) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_POISON_JAB) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_TYPHLOSION) { Ability(abilityDef); } PLAYER(SPECIES_WOBBUFFET); @@ -176,8 +176,8 @@ AI_SINGLE_BATTLE_TEST("AI prefers Earthquake over Drill Run if both require the { // Drill Run has less accuracy than E-quake, but can score a higher crit. However the chance is too small, so AI should ignore it. GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].category == DAMAGE_CATEGORY_PHYSICAL); // Added because Geodude has to KO Typhlosion - ASSUME(gMovesInfo[MOVE_DRILL_RUN].category == DAMAGE_CATEGORY_PHYSICAL); // Added because Geodude has to KO Typhlosion + ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL); // Added because Geodude has to KO Typhlosion + ASSUME(GetMoveCategory(MOVE_DRILL_RUN) == DAMAGE_CATEGORY_PHYSICAL); // Added because Geodude has to KO Typhlosion AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_TYPHLOSION); PLAYER(SPECIES_WOBBUFFET); @@ -202,8 +202,8 @@ AI_SINGLE_BATTLE_TEST("AI prefers a weaker move over a one with a downside effec PARAMETRIZE { move1 = MOVE_OVERHEAT; move2 = MOVE_FLAMETHROWER; hp = 250; expectedMove = MOVE_OVERHEAT; turns = 1; } GIVEN { - ASSUME(gMovesInfo[MOVE_FLAMETHROWER].category == DAMAGE_CATEGORY_SPECIAL); // Added because Typhlosion has to KO Wobbuffet - ASSUME(gMovesInfo[MOVE_OVERHEAT].category == DAMAGE_CATEGORY_SPECIAL); // Added because Typhlosion has to KO Wobbuffet + ASSUME(GetMoveCategory(MOVE_FLAMETHROWER) == DAMAGE_CATEGORY_SPECIAL); // Added because Typhlosion has to KO Wobbuffet + ASSUME(GetMoveCategory(MOVE_OVERHEAT) == DAMAGE_CATEGORY_SPECIAL); // Added because Typhlosion has to KO Wobbuffet AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(hp); } PLAYER(SPECIES_WOBBUFFET); @@ -242,8 +242,8 @@ AI_SINGLE_BATTLE_TEST("AI prefers moves with the best possible score, chosen ran AI_SINGLE_BATTLE_TEST("AI can choose a status move that boosts the attack by two") { GIVEN { - ASSUME(gMovesInfo[MOVE_STRENGTH].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_HORN_ATTACK].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_STRENGTH) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_HORN_ATTACK) == DAMAGE_CATEGORY_PHYSICAL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(277); }; PLAYER(SPECIES_WOBBUFFET); @@ -330,8 +330,8 @@ AI_SINGLE_BATTLE_TEST("AI won't use Solar Beam if there is no Sun up or the user PARAMETRIZE { } GIVEN { - ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_GRASS_PLEDGE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SOLAR_BEAM) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_GRASS_PLEDGE) == DAMAGE_CATEGORY_SPECIAL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(211); } PLAYER(SPECIES_WOBBUFFET); @@ -355,7 +355,7 @@ AI_SINGLE_BATTLE_TEST("AI won't use Solar Beam if there is no Sun up or the user AI_SINGLE_BATTLE_TEST("AI won't use ground type attacks against flying type Pokemon unless Gravity is in effect") { GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].category == DAMAGE_CATEGORY_PHYSICAL); // Otherwise, it doesn't KO Crobat + ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL); // Otherwise, it doesn't KO Crobat AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_CROBAT); PLAYER(SPECIES_WOBBUFFET); @@ -430,7 +430,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not use a status move if partner already chose He for (j = MOVE_NONE + 1; j < MOVES_COUNT; j++) { - if (gMovesInfo[j].category == DAMAGE_CATEGORY_STATUS) { + if (GetMoveCategory(j) == DAMAGE_CATEGORY_STATUS) { PARAMETRIZE { statusMove = j; } } } @@ -509,9 +509,9 @@ AI_SINGLE_BATTLE_TEST("AI will choose either Rock Tomb or Bulldoze if Stat drop AI_SINGLE_BATTLE_TEST("First Impression is preferred on the first turn of the species if it's the best dmg move") { GIVEN { - ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].effect == EFFECT_FIRST_TURN_ONLY); - ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].power == 90); - ASSUME(gMovesInfo[MOVE_LUNGE].power == 80); + ASSUME(GetMoveEffect(MOVE_FIRST_IMPRESSION) == EFFECT_FIRST_TURN_ONLY); + ASSUME(GetMovePower(MOVE_FIRST_IMPRESSION) == 90); + ASSUME(GetMovePower(MOVE_LUNGE) == 80); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_KANGASKHAN); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_FIRST_IMPRESSION, MOVE_LUNGE); } @@ -531,9 +531,9 @@ AI_SINGLE_BATTLE_TEST("First Impression is not chosen if it's blocked by certain PARAMETRIZE { species = SPECIES_TSAREENA; ability = ABILITY_QUEENLY_MAJESTY; } GIVEN { - ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].effect == EFFECT_FIRST_TURN_ONLY); - ASSUME(gMovesInfo[MOVE_FIRST_IMPRESSION].power == 90); - ASSUME(gMovesInfo[MOVE_LUNGE].power == 80); + ASSUME(GetMoveEffect(MOVE_FIRST_IMPRESSION) == EFFECT_FIRST_TURN_ONLY); + ASSUME(GetMovePower(MOVE_FIRST_IMPRESSION) == 90); + ASSUME(GetMovePower(MOVE_LUNGE) == 80); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_FIRST_IMPRESSION, MOVE_LUNGE); } @@ -545,7 +545,7 @@ AI_SINGLE_BATTLE_TEST("First Impression is not chosen if it's blocked by certain AI_SINGLE_BATTLE_TEST("AI will not choose Burn Up if the user lost the Fire typing") { GIVEN { - ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_BURN_UP) == EFFECT_FAIL_IF_NOT_ARG_TYPE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_CYNDAQUIL) { Moves(MOVE_BURN_UP, MOVE_EXTRASENSORY, MOVE_FLAMETHROWER); } @@ -559,7 +559,7 @@ AI_SINGLE_BATTLE_TEST("AI will only choose Surf 1/3 times if the opposing mon ha { PASSES_RANDOMLY(1, 3, RNG_AI_ABILITY); GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); }; OPPONENT(SPECIES_LANTURN) { Moves(MOVE_THUNDERBOLT, MOVE_ICE_BEAM, MOVE_SURF); } @@ -576,7 +576,7 @@ AI_SINGLE_BATTLE_TEST("AI will choose Thunderbolt then Surf 2/3 times if the opp { PASSES_RANDOMLY(2, 3, RNG_AI_ABILITY); GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); }; OPPONENT(SPECIES_LANTURN) { Moves(MOVE_THUNDERBOLT, MOVE_ICE_BEAM, MOVE_SURF); } @@ -596,10 +596,10 @@ AI_SINGLE_BATTLE_TEST("AI will choose Scratch over Power-up Punch with Contrary" PARAMETRIZE {ability = ABILITY_SUCTION_CUPS; } PARAMETRIZE {ability = ABILITY_CONTRARY; } GIVEN { - ASSUME(gMovesInfo[MOVE_SCRATCH].power == 40); - ASSUME(gMovesInfo[MOVE_SCRATCH].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_POWER_UP_PUNCH].power == 40); - ASSUME(gMovesInfo[MOVE_POWER_UP_PUNCH].type == TYPE_FIGHTING); + ASSUME(GetMovePower(MOVE_SCRATCH) == 40); + ASSUME(GetMoveType(MOVE_SCRATCH) == TYPE_NORMAL); + ASSUME(GetMovePower(MOVE_POWER_UP_PUNCH) == 40); + ASSUME(GetMoveType(MOVE_POWER_UP_PUNCH) == TYPE_FIGHTING); ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[0] == TYPE_WATER); ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[1] == TYPE_WATER); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); @@ -622,10 +622,10 @@ AI_SINGLE_BATTLE_TEST("AI will choose Superpower over Outrage with Contrary") PARAMETRIZE {ability = ABILITY_SUCTION_CUPS; } PARAMETRIZE {ability = ABILITY_CONTRARY; } GIVEN { - ASSUME(gMovesInfo[MOVE_SUPERPOWER].power == 120); - ASSUME(gMovesInfo[MOVE_SUPERPOWER].type == TYPE_FIGHTING); - ASSUME(gMovesInfo[MOVE_OUTRAGE].power == 120); - ASSUME(gMovesInfo[MOVE_OUTRAGE].type == TYPE_DRAGON); + ASSUME(GetMovePower(MOVE_SUPERPOWER) == 120); + ASSUME(GetMoveType(MOVE_SUPERPOWER) == TYPE_FIGHTING); + ASSUME(GetMovePower(MOVE_OUTRAGE) == 120); + ASSUME(GetMoveType(MOVE_OUTRAGE) == TYPE_DRAGON); ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[0] == TYPE_WATER); ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[1] == TYPE_WATER); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); @@ -650,7 +650,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not choose Earthquake if it damages the partner") PARAMETRIZE { species = SPECIES_CHIKORITA; } GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -667,7 +667,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not choose Earthquake if it damages the partner") AI_DOUBLE_BATTLE_TEST("AI will choose Earthquake if partner is not alive") { GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -682,7 +682,7 @@ AI_DOUBLE_BATTLE_TEST("AI will choose Earthquake if partner is not alive") AI_DOUBLE_BATTLE_TEST("AI will choose Earthquake if it kill an opposing mon and does 1/3 of damage to AI") { GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { HP(1); } @@ -700,7 +700,7 @@ AI_DOUBLE_BATTLE_TEST("AI will the see a corresponding absorbing ability on part PARAMETRIZE { ability = ABILITY_STATIC; } GIVEN { - ASSUME(gMovesInfo[MOVE_DISCHARGE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -721,11 +721,11 @@ AI_SINGLE_BATTLE_TEST("AI calculates guaranteed criticals and detects critical i PARAMETRIZE { ability = ABILITY_SHELL_ARMOR; } GIVEN { - ASSUME(gMovesInfo[MOVE_STORM_THROW].alwaysCriticalHit); - ASSUME(gMovesInfo[MOVE_STORM_THROW].power == 60); - ASSUME(gMovesInfo[MOVE_BRICK_BREAK].power == 75); - ASSUME(gMovesInfo[MOVE_STORM_THROW].type == gMovesInfo[MOVE_BRICK_BREAK].type); - ASSUME(gMovesInfo[MOVE_STORM_THROW].category == gMovesInfo[MOVE_BRICK_BREAK].category); + ASSUME(MoveAlwaysCrits(MOVE_STORM_THROW)); + ASSUME(GetMovePower(MOVE_STORM_THROW) == 60); + ASSUME(GetMovePower(MOVE_BRICK_BREAK) == 75); + ASSUME(GetMoveType(MOVE_STORM_THROW) == GetMoveType(MOVE_BRICK_BREAK)); + ASSUME(GetMoveCategory(MOVE_STORM_THROW) == GetMoveCategory(MOVE_BRICK_BREAK)); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); PLAYER(SPECIES_OMASTAR) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STORM_THROW, MOVE_BRICK_BREAK); } @@ -761,11 +761,11 @@ AI_SINGLE_BATTLE_TEST("AI avoids contact moves against rocky helmet") PARAMETRIZE { item = ITEM_ROCKY_HELMET; } GIVEN { - ASSUME(gMovesInfo[MOVE_BRANCH_POKE].makesContact); - ASSUME(!gMovesInfo[MOVE_LEAFAGE].makesContact); - ASSUME(gMovesInfo[MOVE_BRANCH_POKE].power == gMovesInfo[MOVE_LEAFAGE].power); - ASSUME(gMovesInfo[MOVE_BRANCH_POKE].type == gMovesInfo[MOVE_LEAFAGE].type); - ASSUME(gMovesInfo[MOVE_BRANCH_POKE].category == gMovesInfo[MOVE_LEAFAGE].category); + ASSUME(MoveMakesContact(MOVE_BRANCH_POKE)); + ASSUME(!MoveMakesContact(MOVE_LEAFAGE)); + ASSUME(GetMovePower(MOVE_BRANCH_POKE) == GetMovePower(MOVE_LEAFAGE)); + ASSUME(GetMoveType(MOVE_BRANCH_POKE) == GetMoveType(MOVE_LEAFAGE)); + ASSUME(GetMoveCategory(MOVE_BRANCH_POKE) == GetMoveCategory(MOVE_LEAFAGE)); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_BRANCH_POKE, MOVE_LEAFAGE); } @@ -785,11 +785,11 @@ AI_SINGLE_BATTLE_TEST("AI uses a guaranteed KO move instead of the move with the PARAMETRIZE { flags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT; } GIVEN { - ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); - ASSUME(gMovesInfo[MOVE_SLASH].power == 70); - ASSUME(gMovesInfo[MOVE_STRENGTH].power == 80); - ASSUME(gMovesInfo[MOVE_SLASH].type == gMovesInfo[MOVE_STRENGTH].type); - ASSUME(gMovesInfo[MOVE_SLASH].category == gMovesInfo[MOVE_STRENGTH].category); + ASSUME(GetMoveCriticalHitStage(MOVE_SLASH) == 1); + ASSUME(GetMovePower(MOVE_SLASH) == 70); + ASSUME(GetMovePower(MOVE_STRENGTH) == 80); + ASSUME(GetMoveType(MOVE_SLASH) == GetMoveType(MOVE_STRENGTH)); + ASSUME(GetMoveCategory(MOVE_SLASH) == GetMoveCategory(MOVE_STRENGTH)); AI_FLAGS(flags); PLAYER(SPECIES_WOBBUFFET) { HP(225); } OPPONENT(SPECIES_ABSOL) { Ability(ABILITY_SUPER_LUCK); Moves(MOVE_SLASH, MOVE_STRENGTH); } @@ -818,10 +818,10 @@ AI_SINGLE_BATTLE_TEST("AI stays choice locked into moves in spite of the player' GIVEN { ASSUME(gItemsInfo[ITEM_CHOICE_BAND].holdEffect == HOLD_EFFECT_CHOICE_BAND); - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); - ASSUME(gMovesInfo[MOVE_BOOMBURST].soundMove == TRUE); - ASSUME(gMovesInfo[MOVE_BULLET_SEED].ballisticMove == TRUE); - ASSUME(gMovesInfo[MOVE_TAIL_WHIP].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); + ASSUME(IsSoundMove(MOVE_BOOMBURST)); + ASSUME(IsBallisticMove(MOVE_BULLET_SEED)); + ASSUME(GetMoveCategory(MOVE_TAIL_WHIP) == DAMAGE_CATEGORY_STATUS); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(playerMon) { Ability(ability); } diff --git a/test/battle/ai/ai_calc_best_move_score.c b/test/battle/ai/ai_calc_best_move_score.c index bece527f3069..f3b339debaee 100644 --- a/test/battle/ai/ai_calc_best_move_score.c +++ b/test/battle/ai/ai_calc_best_move_score.c @@ -10,9 +10,9 @@ AI_SINGLE_BATTLE_TEST("AI will not further increase Attack / Sp. Atk stat if it PARAMETRIZE { move = MOVE_CALM_MIND; } GIVEN { - ASSUME(gMovesInfo[MOVE_SKY_UPPERCUT].power == 85); - ASSUME(gMovesInfo[MOVE_HOWL].effect == EFFECT_ATTACK_UP_USER_ALLY); - ASSUME(gMovesInfo[MOVE_CALM_MIND].effect == EFFECT_CALM_MIND); + ASSUME(GetMovePower(MOVE_SKY_UPPERCUT) == 85); + ASSUME(GetMoveEffect(MOVE_HOWL) == EFFECT_ATTACK_UP_USER_ALLY); + ASSUME(GetMoveEffect(MOVE_CALM_MIND) == EFFECT_CALM_MIND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_COMBUSKEN) { Speed(15); Moves(MOVE_SKY_UPPERCUT, MOVE_CELEBRATE); }; OPPONENT(SPECIES_KANGASKHAN) { Speed(20); Moves(MOVE_CHIP_AWAY, MOVE_SWIFT, move); } @@ -30,9 +30,9 @@ AI_SINGLE_BATTLE_TEST("AI will not further increase Attack / Sp. Atk stat if it PARAMETRIZE { move = MOVE_CALM_MIND; } GIVEN { - ASSUME(gMovesInfo[MOVE_SKY_UPPERCUT].power == 85); - ASSUME(gMovesInfo[MOVE_HOWL].effect == EFFECT_ATTACK_UP_USER_ALLY); - ASSUME(gMovesInfo[MOVE_CALM_MIND].effect == EFFECT_CALM_MIND); + ASSUME(GetMovePower(MOVE_SKY_UPPERCUT) == 85); + ASSUME(GetMoveEffect(MOVE_HOWL) == EFFECT_ATTACK_UP_USER_ALLY); + ASSUME(GetMoveEffect(MOVE_CALM_MIND) == EFFECT_CALM_MIND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_COMBUSKEN) { Speed(20); Moves(MOVE_DOUBLE_KICK, MOVE_CELEBRATE); }; OPPONENT(SPECIES_KANGASKHAN) { Speed(15); Moves(MOVE_CHIP_AWAY, MOVE_SWIFT, move); } @@ -62,9 +62,9 @@ AI_SINGLE_BATTLE_TEST("AI will correctly predict what move the opposing mon goin PARAMETRIZE { move = MOVE_CALM_MIND; } GIVEN { - ASSUME(gMovesInfo[MOVE_SKY_UPPERCUT].power == 85); - ASSUME(gMovesInfo[MOVE_HOWL].effect == EFFECT_ATTACK_UP_USER_ALLY); - ASSUME(gMovesInfo[MOVE_CALM_MIND].effect == EFFECT_CALM_MIND); + ASSUME(GetMovePower(MOVE_SKY_UPPERCUT) == 85); + ASSUME(GetMoveEffect(MOVE_HOWL) == EFFECT_ATTACK_UP_USER_ALLY); + ASSUME(GetMoveEffect(MOVE_CALM_MIND) == EFFECT_CALM_MIND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); PLAYER(SPECIES_COMBUSKEN) { Speed(15); Moves(MOVE_SKY_UPPERCUT, MOVE_DOUBLE_KICK, MOVE_FLAME_WHEEL, MOVE_CELEBRATE); }; OPPONENT(SPECIES_KANGASKHAN) { Speed(20); Moves(MOVE_CHIP_AWAY, MOVE_SWIFT, move); } @@ -77,10 +77,10 @@ AI_SINGLE_BATTLE_TEST("AI will correctly predict what move the opposing mon goin AI_SINGLE_BATTLE_TEST("AI will not use Throat Chop if opposing mon has a better move") { GIVEN { - ASSUME(gMovesInfo[MOVE_PSYCHIC_FANGS].power == 85); - ASSUME(gMovesInfo[MOVE_THROAT_CHOP].power == 80); - ASSUME(gMovesInfo[MOVE_DISARMING_VOICE].power == 40); - ASSUME(gMovesInfo[MOVE_FLAME_BURST].power == 70); + ASSUME(GetMovePower(MOVE_PSYCHIC_FANGS) == 85); + ASSUME(GetMovePower(MOVE_THROAT_CHOP) == 80); + ASSUME(GetMovePower(MOVE_DISARMING_VOICE) == 40); + ASSUME(GetMovePower(MOVE_FLAME_BURST) == 70); ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_REGIROCK) { Speed(15); Moves(MOVE_DISARMING_VOICE, MOVE_FLAME_BURST); }; @@ -96,10 +96,10 @@ AI_SINGLE_BATTLE_TEST("AI will select Throat Chop if the sound move is the best { GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_THROAT_CHOP, MOVE_EFFECT_THROAT_CHOP) == TRUE); - ASSUME(gMovesInfo[MOVE_PSYCHIC_FANGS].power == 85); - ASSUME(gMovesInfo[MOVE_THROAT_CHOP].power == 80); - ASSUME(gMovesInfo[MOVE_FLAME_BURST].power == 70); - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].power == 90); + ASSUME(GetMovePower(MOVE_PSYCHIC_FANGS) == 85); + ASSUME(GetMovePower(MOVE_THROAT_CHOP) == 80); + ASSUME(GetMovePower(MOVE_FLAME_BURST) == 70); + ASSUME(GetMovePower(MOVE_HYPER_VOICE) == 90); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_REGIROCK) { Speed(15); Moves(MOVE_HYPER_VOICE, MOVE_FLAME_BURST); }; OPPONENT(SPECIES_WOBBUFFET) { Speed(20); Moves(MOVE_THROAT_CHOP, MOVE_PSYCHIC_FANGS); } diff --git a/test/battle/ai/ai_check_viability.c b/test/battle/ai/ai_check_viability.c index 7279085ff2c3..2c20a08db639 100644 --- a/test/battle/ai/ai_check_viability.c +++ b/test/battle/ai/ai_check_viability.c @@ -15,7 +15,7 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Facade") PARAMETRIZE { status1 = STATUS1_BURN; expectedMove = MOVE_FACADE; } GIVEN { - ASSUME(gMovesInfo[MOVE_FACADE].effect == EFFECT_FACADE); + ASSUME(GetMoveEffect(MOVE_FACADE) == EFFECT_FACADE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(60); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_BODY_SLAM, MOVE_FACADE); Status1(status1); } @@ -36,8 +36,8 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Smelling Salt") GIVEN { ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); - ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument.status == STATUS1_PARALYSIS); + ASSUME(GetMoveEffect(MOVE_SMELLING_SALTS) == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(GetMoveEffectArg_Status(MOVE_SMELLING_SALTS) == STATUS1_PARALYSIS); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(60); Status1(status1); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_BODY_SLAM, MOVE_SMELLING_SALTS); } @@ -58,8 +58,8 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Wake Up Slap") GIVEN { ASSUME(B_UPDATED_MOVE_DATA >= GEN_6); - ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument.status == STATUS1_SLEEP); + ASSUME(GetMoveEffect(MOVE_WAKE_UP_SLAP) == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(GetMoveEffectArg_Status(MOVE_WAKE_UP_SLAP) == STATUS1_SLEEP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_MEGANIUM) { HP(35); Status1(status1); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_BODY_SLAM, MOVE_WAKE_UP_SLAP); } @@ -80,8 +80,8 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Grav Apple") PARAMETRIZE { movePlayer = MOVE_GRAVITY; expectedMove = MOVE_GRAV_APPLE; } GIVEN { - ASSUME(gMovesInfo[MOVE_GRAV_APPLE].effect == EFFECT_GRAV_APPLE); - ASSUME(gMovesInfo[MOVE_GRAV_APPLE].power == gMovesInfo[MOVE_DRUM_BEATING].power); + ASSUME(GetMoveEffect(MOVE_GRAV_APPLE) == EFFECT_GRAV_APPLE); + ASSUME(GetMovePower(MOVE_GRAV_APPLE) == GetMovePower(MOVE_DRUM_BEATING)); ASSUME(MoveHasAdditionalEffect(MOVE_DRUM_BEATING, MOVE_EFFECT_SPD_MINUS_1) == TRUE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(81); Speed(20); } @@ -103,7 +103,7 @@ AI_SINGLE_BATTLE_TEST("AI sees increased base power of Flail") PARAMETRIZE { hp = 5; expectedMove = MOVE_FLAIL; } GIVEN { - ASSUME(gMovesInfo[MOVE_FLAIL].effect == EFFECT_FLAIL); + ASSUME(GetMoveEffect(MOVE_FLAIL) == EFFECT_FLAIL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { Speed(10); } OPPONENT(SPECIES_WOBBUFFET) { HP(hp); MaxHP(490); Speed(20); Moves(MOVE_BODY_SLAM, MOVE_FLAIL); } @@ -134,8 +134,8 @@ AI_SINGLE_BATTLE_TEST("AI will only use Dream Eater if target is asleep") AI_SINGLE_BATTLE_TEST("AI sees increased base power of Spit Up") { GIVEN { - ASSUME(gMovesInfo[MOVE_STOCKPILE].effect == EFFECT_STOCKPILE); - ASSUME(gMovesInfo[MOVE_SPIT_UP].effect == EFFECT_SPIT_UP); + ASSUME(GetMoveEffect(MOVE_STOCKPILE) == EFFECT_STOCKPILE); + ASSUME(GetMoveEffect(MOVE_SPIT_UP) == EFFECT_SPIT_UP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(43); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STOCKPILE, MOVE_SPIT_UP, MOVE_TACKLE); } @@ -155,10 +155,10 @@ AI_SINGLE_BATTLE_TEST("AI can choose Counter or Mirror Coat if the predicted mov PARAMETRIZE { playerMove = MOVE_POWER_GEM; opponentMove = MOVE_MIRROR_COAT; } GIVEN { - ASSUME(gMovesInfo[MOVE_COUNTER].effect == EFFECT_COUNTER); - ASSUME(gMovesInfo[MOVE_MIRROR_COAT].effect == EFFECT_MIRROR_COAT); - ASSUME(gMovesInfo[MOVE_STRENGTH].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_POWER_GEM].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_COUNTER) == EFFECT_COUNTER); + ASSUME(GetMoveEffect(MOVE_MIRROR_COAT) == EFFECT_MIRROR_COAT); + ASSUME(GetMoveCategory(MOVE_STRENGTH) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_POWER_GEM) == DAMAGE_CATEGORY_SPECIAL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { HP(102); Speed(100); Moves(opponentMove, MOVE_STRENGTH); } @@ -202,7 +202,7 @@ AI_DOUBLE_BATTLE_TEST("AI chooses moves that cure self or partner") PARAMETRIZE { status1_0 = STATUS1_NONE; status1_1 = STATUS1_PARALYSIS; partnerAbility = ABILITY_SOUNDPROOF; } GIVEN { - ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_HEAL_BELL) == EFFECT_HEAL_BELL); ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_8); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); @@ -226,7 +226,7 @@ AI_SINGLE_BATTLE_TEST("AI chooses moves that cure inactive party members") PARAMETRIZE { status = STATUS1_TOXIC_POISON; ability = ABILITY_SOUNDPROOF; } GIVEN { - ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_HEAL_BELL) == EFFECT_HEAL_BELL); ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_5); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); @@ -243,8 +243,8 @@ AI_SINGLE_BATTLE_TEST("AI chooses moves that cure inactive party members") AI_DOUBLE_BATTLE_TEST("AI prioritizes Skill Swapping Contrary to allied mons that would benefit from it") { GIVEN { - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); - ASSUME(gMovesInfo[MOVE_OVERHEAT].additionalEffects[0].moveEffect == MOVE_EFFECT_SP_ATK_MINUS_2); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); + ASSUME(GetMoveAdditionalEffectById(MOVE_OVERHEAT, 0)->moveEffect == MOVE_EFFECT_SP_ATK_MINUS_2); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_DOUBLE_BATTLE); PLAYER(SPECIES_WOBBUFFET) { Speed(3); } PLAYER(SPECIES_WOBBUFFET) { Speed(3); } diff --git a/test/battle/ai/ai_choice.c b/test/battle/ai/ai_choice.c index c9992d2cab5f..f1f13a373ee8 100644 --- a/test/battle/ai/ai_choice.c +++ b/test/battle/ai/ai_choice.c @@ -25,8 +25,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon switch out after using a status move onc } GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveCategory(MOVE_YAWN) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_RHYDON) OPPONENT(SPECIES_LOPUNNY) { Moves(MOVE_YAWN, MOVE_TACKLE); Item(heldItem); Ability(ability); } @@ -60,7 +60,7 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use stat boosting moves") } GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].target == MOVE_TARGET_USER); + ASSUME(GetMoveTarget(MOVE_SWORDS_DANCE) == MOVE_TARGET_USER); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_RHYDON) OPPONENT(SPECIES_LOPUNNY) { Moves(MOVE_SWORDS_DANCE, MOVE_TACKLE); Item(heldItem); Ability(ability); } @@ -94,8 +94,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are the on } GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveCategory(MOVE_YAWN) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_RHYDON) OPPONENT(SPECIES_LOPUNNY) { Moves(MOVE_YAWN, MOVE_TACKLE); Item(heldItem); Ability(ability); } @@ -129,8 +129,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they don't have } GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveCategory(MOVE_YAWN) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_RHYDON) OPPONENT(SPECIES_LOPUNNY) { Moves(MOVE_YAWN, MOVE_TACKLE); Item(heldItem); Ability(ability); } @@ -164,8 +164,8 @@ AI_SINGLE_BATTLE_TEST("Choiced Pokémon won't use status move if they are trappe } GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveCategory(MOVE_YAWN) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(species) { Ability(playerAbility); } OPPONENT(SPECIES_LOPUNNY) { Moves(MOVE_YAWN, MOVE_TACKLE); Item(heldItem); Ability(aiAbility); } diff --git a/test/battle/ai/ai_double_ace.c b/test/battle/ai/ai_double_ace.c index aec37b9307e5..5e49c0d6e15e 100644 --- a/test/battle/ai/ai_double_ace.c +++ b/test/battle/ai/ai_double_ace.c @@ -2,8 +2,8 @@ #include "test/battle.h" ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_CRUNCH].type == TYPE_DARK); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveType(MOVE_CRUNCH) == TYPE_DARK); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC); } diff --git a/test/battle/ai/ai_flag_predict_ability.c b/test/battle/ai/ai_flag_predict_ability.c index ab934698b8a0..9d85773e3eaf 100644 --- a/test/battle/ai/ai_flag_predict_ability.c +++ b/test/battle/ai/ai_flag_predict_ability.c @@ -6,7 +6,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_WEIGH_ABILITY_PREDICTION: AI will predict opposin { PASSES_RANDOMLY(7, 14, RNG_AI_PREDICT_ABILITY); GIVEN { - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_WEIGH_ABILITY_PREDICTION); PLAYER(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); }; OPPONENT(SPECIES_LANTURN) { Moves(MOVE_THUNDERBOLT, MOVE_ICE_BEAM, MOVE_SURF); } diff --git a/test/battle/ai/ai_flag_predict_switch.c b/test/battle/ai/ai_flag_predict_switch.c new file mode 100644 index 000000000000..afed790a4175 --- /dev/null +++ b/test/battle/ai/ai_flag_predict_switch.c @@ -0,0 +1,139 @@ +#include "global.h" +#include "test/battle.h" +#include "battle_ai_util.h" + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI will predict use Pursuit on predicted switches") +{ + PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH); + PLAYER(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + PLAYER(SPECIES_CONKELDURR) { Moves(MOVE_HAMMER_ARM); } + OPPONENT(SPECIES_TYRANITAR) { Moves(MOVE_PURSUIT, MOVE_CRUNCH); } + } WHEN { + TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_PURSUIT); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in Pursuit scenario") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_TYRANITAR) { Moves(MOVE_PURSUIT, MOVE_CRUNCH); } + OPPONENT(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + OPPONENT(SPECIES_CONKELDURR) { Moves(MOVE_HAMMER_ARM); } + } WHEN { + TURN { MOVE(player, MOVE_PURSUIT); EXPECT_SWITCH(opponent, 1); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI will predict switches with Wonder Guard") +{ + PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH); + PLAYER(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + PLAYER(SPECIES_SWELLOW) { Moves(MOVE_PECK); } + OPPONENT(SPECIES_SHEDINJA) { Moves(MOVE_PURSUIT, MOVE_CRUNCH); } + } WHEN { + TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_PURSUIT); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in Wonder Guard scenario") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_SHEDINJA) { Moves(MOVE_PURSUIT, MOVE_CRUNCH); } + OPPONENT(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + OPPONENT(SPECIES_SWELLOW) { Moves(MOVE_PECK); } + } WHEN { + TURN { MOVE(player, MOVE_PURSUIT); EXPECT_SWITCH(opponent, 1); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI will use hit escape moves on predicted switches") +{ + PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH); + PLAYER(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + PLAYER(SPECIES_CONKELDURR) { Moves(MOVE_HAMMER_ARM); } + OPPONENT(SPECIES_TYRANITAR) { Moves(MOVE_U_TURN, MOVE_CRUNCH); } + OPPONENT(SPECIES_TYRANITAR) { Moves(MOVE_U_TURN, MOVE_CRUNCH); } + } WHEN { + TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_U_TURN); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in hit escape scenario") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_TYRANITAR) { Moves(MOVE_U_TURN, MOVE_CRUNCH); } + PLAYER(SPECIES_TYRANITAR) { Moves(MOVE_U_TURN, MOVE_CRUNCH); } + OPPONENT(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + OPPONENT(SPECIES_CONKELDURR) { Moves(MOVE_HAMMER_ARM); } + } WHEN { + TURN { EXPECT_SWITCH(opponent, 1); MOVE(player, MOVE_U_TURN); SEND_OUT(player, 1); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: Considers ShouldSwitch and GetMostSuitableMonToSwitchInto from player's perspective") +{ + // Switching in trapper is an advanced feature of ShouldSwitch that requires GetMostSuitableMonToSwitchInto to also return a specific mon; this passing means the AI can use both in prediction + PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH); + PLAYER(SPECIES_CACNEA) { Moves(MOVE_ABSORB); } + PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_ACROBATICS); } + OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); Moves(MOVE_PURSUIT, MOVE_BITE); } + OPPONENT(SPECIES_BRELOOM); + } WHEN { + TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_PURSUIT); } + TURN { MOVE(player, MOVE_ACROBATICS); EXPECT_MOVE(opponent, MOVE_BITE); EXPECT_SEND_OUT(opponent, 1); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in trapper-from-player's-perspective case") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_BRELOOM) { Speed(5); Ability(ABILITY_EFFECT_SPORE); Moves(MOVE_PURSUIT, MOVE_BITE); } + PLAYER(SPECIES_BRELOOM) { Speed(5); } + OPPONENT(SPECIES_CACNEA) { Speed(6); Moves(MOVE_ABSORB); } + OPPONENT(SPECIES_DUGTRIO) { Speed(6); Ability(ABILITY_ARENA_TRAP); Moves(MOVE_ACROBATICS); } + } WHEN { + TURN { MOVE(player, MOVE_PURSUIT); EXPECT_SWITCH(opponent, 1); } + TURN { EXPECT_MOVE(opponent, MOVE_ACROBATICS); MOVE(player, MOVE_BITE); SEND_OUT(player, 1); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI can use Focus Punch on predicted switches") +{ + PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH); + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH); + PLAYER(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + PLAYER(SPECIES_CONKELDURR) { Moves(MOVE_HAMMER_ARM); } + OPPONENT(SPECIES_TYRANITAR) { Moves(MOVE_FOCUS_PUNCH, MOVE_BRICK_BREAK); } + } WHEN { + TURN { SWITCH(player, 1); EXPECT_MOVE(opponent, MOVE_FOCUS_PUNCH); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in Focus Punch scenario") +{ + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_TYRANITAR) { Moves(MOVE_FOCUS_PUNCH, MOVE_BRICK_BREAK); } + OPPONENT(SPECIES_BRONZONG) { Moves(MOVE_PSYCHIC); } + OPPONENT(SPECIES_CONKELDURR) { Moves(MOVE_HAMMER_ARM); } + } WHEN { + TURN { EXPECT_SWITCH(opponent, 1); MOVE(player, MOVE_FOCUS_PUNCH); } + } +} + +// This will be for a follow-up PR +TO_DO_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI will score against predicted incoming mon when switch predicted") +TO_DO_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: AI would switch out in predicted-incoming-mon scenario"); diff --git a/test/battle/ai/ai_flag_risky.c b/test/battle/ai/ai_flag_risky.c index 87be344ab8d4..b725b0f444e9 100644 --- a/test/battle/ai/ai_flag_risky.c +++ b/test/battle/ai/ai_flag_risky.c @@ -9,7 +9,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Mirror Coat against specia PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; } GIVEN { - ASSUME(gMovesInfo[MOVE_MIRROR_COAT].effect == EFFECT_MIRROR_COAT); + ASSUME(GetMoveEffect(MOVE_MIRROR_COAT) == EFFECT_MIRROR_COAT); ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseSpAttack == 85); ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseAttack == 65); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); @@ -28,7 +28,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Counter against physical a PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; } GIVEN { - ASSUME(gMovesInfo[MOVE_COUNTER].effect == EFFECT_COUNTER); + ASSUME(GetMoveEffect(MOVE_COUNTER) == EFFECT_COUNTER); ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseAttack == 85); ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseSpAttack == 60); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); @@ -47,7 +47,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will prioritize Revenge if slower") PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; } GIVEN { - ASSUME(gMovesInfo[MOVE_REVENGE].effect == EFFECT_REVENGE); + ASSUME(GetMoveEffect(MOVE_REVENGE) == EFFECT_REVENGE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); PLAYER(SPECIES_GROVYLE) { Level(20); Speed(4); Moves(MOVE_ENERGY_BALL); } OPPONENT(SPECIES_CASTFORM) { Level(19); Speed(3); Moves(MOVE_TACKLE, MOVE_REVENGE); } @@ -74,12 +74,13 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: Mid-battle switches prioritize offensive o } } -AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI prefers high damage moves at the expense of accuracy regardless of KO thresholds") +AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY | AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE: AI prefers high damage moves at the expense of accuracy regardless of KO thresholds") { u32 aiRiskyFlag = 0; PARAMETRIZE { aiRiskyFlag = 0; } PARAMETRIZE { aiRiskyFlag = AI_FLAG_RISKY; } + PARAMETRIZE { aiRiskyFlag = AI_FLAG_PREFER_HIGHEST_DAMAGE_MOVE; } GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); diff --git a/test/battle/ai/ai_flag_sequence_switching.c b/test/battle/ai/ai_flag_sequence_switching.c index 8502efbba77c..56d7eb881f7e 100644 --- a/test/battle/ai/ai_flag_sequence_switching.c +++ b/test/battle/ai/ai_flag_sequence_switching.c @@ -48,8 +48,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: Roar and Dragon Tail still fo PASSES_RANDOMLY(1, 2, RNG_FORCE_RANDOM_SWITCH); GIVEN { - ASSUME(gMovesInfo[MOVE_ROAR].effect == EFFECT_ROAR); - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); AI_FLAGS(AI_FLAG_SEQUENCE_SWITCHING); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -82,10 +82,10 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch into lo } GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT); - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); - ASSUME(gMovesInfo[MOVE_CHILLY_RECEPTION].effect == EFFECT_CHILLY_RECEPTION); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_PARTING_SHOT) == EFFECT_PARTING_SHOT); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_CHILLY_RECEPTION) == EFFECT_CHILLY_RECEPTION); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSequenceSwitchingFlag); PLAYER(SPECIES_SWELLOW) { Level (50); } OPPONENT(SPECIES_MACHOP) { Level(1); Moves(move); } diff --git a/test/battle/ai/ai_powerful_status.c b/test/battle/ai/ai_powerful_status.c index 4a14c0bf8025..99aff1938404 100644 --- a/test/battle/ai/ai_powerful_status.c +++ b/test/battle/ai/ai_powerful_status.c @@ -5,8 +5,8 @@ AI_SINGLE_BATTLE_TEST("AI prefers to set up a powerful Status over fainting a target") { GIVEN { - ASSUME(gMovesInfo[MOVE_TRICK_ROOM].effect == EFFECT_TRICK_ROOM); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveEffect(MOVE_TRICK_ROOM) == EFFECT_TRICK_ROOM); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_POWERFUL_STATUS); PLAYER(SPECIES_WOBBUFFET) { HP(1); } PLAYER(SPECIES_WYNAUT); @@ -23,8 +23,8 @@ AI_SINGLE_BATTLE_TEST("AI will try to do damage on target instead of setting up { GIVEN { ASSUME(MoveHasAdditionalEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPID_SPIN) == TRUE); - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_POWERFUL_STATUS | AI_FLAG_OMNISCIENT); PLAYER(SPECIES_WOBBUFFET) { HP(1); Moves(MOVE_RAPID_SPIN, MOVE_DEFOG, MOVE_CELEBRATE); } PLAYER(SPECIES_WYNAUT); @@ -40,8 +40,8 @@ AI_SINGLE_BATTLE_TEST("AI will try to do damage on target instead of setting up AI_SINGLE_BATTLE_TEST("AI will not set up Rain if it is already raining") { GIVEN { - ASSUME(gMovesInfo[MOVE_RAIN_DANCE].effect == EFFECT_RAIN_DANCE); - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_POWERFUL_STATUS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index 00caff5932ff..a4cd20257469 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -93,7 +93,7 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spot AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: U-Turn will send out Ace Mon if it's the only one remaining") { GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_ACE_POKEMON); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_U_TURN); } @@ -168,11 +168,11 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemo PARAMETRIZE { speedAlakazm = 400; alakazamFirst = TRUE; aiSmartSwitchFlags = AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES; } // AI_FLAG_SMART_MON_CHOICES recognizes that Alakazam is faster and can KO, and will switch it in GIVEN { - ASSUME(gMovesInfo[MOVE_PSYCHIC].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_BUBBLE_BEAM].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_STRENGTH].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_PSYCHIC) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_FOCUS_BLAST) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_BUBBLE_BEAM) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_STRENGTH) == DAMAGE_CATEGORY_PHYSICAL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiSmartSwitchFlags); PLAYER(SPECIES_WEAVILE) { Speed(300); Ability(ABILITY_SHADOW_TAG); } // Weavile has Shadow Tag, so AI can't switch on the first turn, but has to do it after fainting. OPPONENT(SPECIES_KADABRA) { Speed(200); Moves(MOVE_PSYCHIC, MOVE_DISABLE, MOVE_TAUNT, MOVE_CALM_MIND); } @@ -250,7 +250,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize offensive options after slow U-Turn") { GIVEN { - ASSUME(gMovesInfo[MOVE_FALSE_SWIPE].effect == EFFECT_FALSE_SWIPE); + ASSUME(GetMoveEffect(MOVE_FALSE_SWIPE) == EFFECT_FALSE_SWIPE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_FALSE_SWIPE, MOVE_BOOMBURST); Speed(5); SpAttack(50); } OPPONENT(SPECIES_PONYTA) { Level(1); Moves(MOVE_U_TURN); Speed(4); } // Forces switchout @@ -265,7 +265,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize { GIVEN { ASSUME(gItemsInfo[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON); - ASSUME(gMovesInfo[MOVE_FALSE_SWIPE].effect == EFFECT_FALSE_SWIPE); + ASSUME(GetMoveEffect(MOVE_FALSE_SWIPE) == EFFECT_FALSE_SWIPE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_FALSE_SWIPE, MOVE_BOOMBURST); Speed(5); SpAttack(50); } OPPONENT(SPECIES_PONYTA) { Level(1); Item(ITEM_EJECT_BUTTON); Moves(MOVE_TACKLE); Speed(4); } // Forces switchout @@ -280,7 +280,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Mid-battle switches prioritize { GIVEN { ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK); - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_SWELLOW) { Level(30); Moves(MOVE_GROWL, MOVE_BOOMBURST); Speed(5); SpAttack(50); } OPPONENT(SPECIES_PONYTA) { Level(1); Item(ITEM_EJECT_PACK); Moves(MOVE_TACKLE); Speed(4); } // Forces switchout @@ -337,7 +337,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Post-KO switches prioritize of AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Post-KO switches factor in Trick Room for revenge killing") { GIVEN { - ASSUME(gMovesInfo[MOVE_TRICK_ROOM].effect == EFFECT_TRICK_ROOM); + ASSUME(GetMoveEffect(MOVE_TRICK_ROOM) == EFFECT_TRICK_ROOM); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_SWELLOW) { Level(30); Speed(10); Moves(MOVE_WING_ATTACK, MOVE_GROWL); } OPPONENT(SPECIES_BALTOY) { Level(1); Speed(10); Moves(MOVE_TRICK_ROOM); } @@ -371,10 +371,10 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will not switch out if Pokemo PARAMETRIZE { move1 = MOVE_RAPID_SPIN; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_RAPID_SPIN].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_HEADBUTT].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_RAPID_SPIN) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_HEADBUTT) == DAMAGE_CATEGORY_PHYSICAL); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_HITMONTOP) { Level(30); Moves(MOVE_CHARM, MOVE_TACKLE, MOVE_STEALTH_ROCK, MOVE_EARTHQUAKE); Ability(ABILITY_INTIMIDATE); Speed(5); } OPPONENT(SPECIES_GRIMER) { Level(30); Moves(MOVE_TACKLE); Item(ITEM_FOCUS_SASH); Speed(4); } @@ -462,8 +462,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if mon would ASSUME(gSpeciesInfo[SPECIES_RHYDON].types[0] == TYPE_GROUND); ASSUME(gSpeciesInfo[SPECIES_PELIPPER].types[0] == TYPE_WATER); ASSUME(gSpeciesInfo[SPECIES_PELIPPER].types[1] == TYPE_FLYING); - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].type == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_ELECTRODE) { Moves(MOVE_THUNDERBOLT, MOVE_THUNDER_WAVE, MOVE_THUNDER_SHOCK); } @@ -482,8 +482,8 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it can't deal damage to ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[0] == ABILITY_WONDER_GUARD); ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[1] == ABILITY_NONE); ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[2] == ABILITY_NONE); - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_SHADOW_BALL) == TYPE_GHOST); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_SHEDINJA) { Moves(MOVE_TACKLE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -501,8 +501,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it can't d ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[0] == ABILITY_WONDER_GUARD); ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[1] == ABILITY_NONE); ASSUME(gSpeciesInfo[SPECIES_SHEDINJA].abilities[2] == ABILITY_NONE); - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_SHADOW_BALL].type == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_SHADOW_BALL) == TYPE_GHOST); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_SHEDINJA) { Moves(MOVE_TACKLE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -519,7 +519,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee PARAMETRIZE { species = SPECIES_HARIYAMA, odds = 50; } PASSES_RANDOMLY(odds, 100, RNG_AI_SWITCH_BADLY_POISONED); GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_TOXIC, MOVE_AURA_SPHERE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -535,7 +535,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee { PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_CURSED); GIVEN { - ASSUME(gMovesInfo[MOVE_CURSE].effect == EFFECT_CURSE); + ASSUME(GetMoveEffect(MOVE_CURSE) == EFFECT_CURSE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_DUSCLOPS) { Moves(MOVE_FIRE_PUNCH, MOVE_CURSE); } PLAYER(SPECIES_MILOTIC) { Moves(MOVE_WATER_GUN); } @@ -551,7 +551,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee { PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_NIGHTMARE); GIVEN { - ASSUME(gMovesInfo[MOVE_NIGHTMARE].effect == EFFECT_NIGHTMARE); + ASSUME(GetMoveEffect(MOVE_NIGHTMARE) == EFFECT_NIGHTMARE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_GENGAR) { Moves(MOVE_NIGHTMARE); } OPPONENT(SPECIES_DUSCLOPS) { Moves(MOVE_SHADOW_BALL); Status1(STATUS1_SLEEP); } @@ -566,7 +566,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee { PASSES_RANDOMLY(25, 100, RNG_AI_SWITCH_SEEDED); GIVEN { - ASSUME(gMovesInfo[MOVE_LEECH_SEED].effect == EFFECT_LEECH_SEED); + ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_WHIMSICOTT) { Moves(MOVE_LEECH_SEED); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -580,7 +580,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been infatuated") { GIVEN { - ASSUME(gMovesInfo[MOVE_ATTRACT].effect == EFFECT_ATTRACT); + ASSUME(GetMoveEffect(MOVE_ATTRACT) == EFFECT_ATTRACT); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_LUVDISC) { Moves(MOVE_ATTRACT); Gender(MON_FEMALE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); Gender(MON_MALE); } @@ -597,7 +597,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee PARAMETRIZE { hp = 30; } PARAMETRIZE { hp = 10; } GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_SLAKOTH) { Moves(MOVE_TACKLE, MOVE_YAWN); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); HP(hp); MaxHP(30); } @@ -617,7 +617,7 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee PARAMETRIZE { hp = 30; } PARAMETRIZE { hp = 10; } GIVEN { - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_SLAKOTH) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_YAWN); } PLAYER(SPECIES_SLAKOTH) { Moves(MOVE_TACKLE, MOVE_CELEBRATE, MOVE_YAWN); } @@ -637,7 +637,7 @@ AI_DOUBLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is semi-invulnerable and it has an absorber") { GIVEN { - ASSUME(gMovesInfo[MOVE_DIVE].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_DIVE) == TYPE_WATER); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_LUVDISC) { Moves(MOVE_DIVE); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -652,7 +652,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an { PASSES_RANDOMLY(33, 100, RNG_AI_SWITCH_ABSORBING); GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_LUVDISC) { Moves(MOVE_WATER_GUN); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SHOCK_WAVE); } @@ -667,7 +667,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m { PASSES_RANDOMLY(100, 100, RNG_AI_SWITCH_ABSORBING); GIVEN { - ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].type == TYPE_GRASS); + ASSUME(GetMoveType(MOVE_SOLAR_BEAM) == TYPE_GRASS); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_BELLOSSOM) { Moves(MOVE_SOLAR_BEAM); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -681,7 +681,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has a good switchin immunity (type)") { GIVEN { - ASSUME(gMovesInfo[MOVE_DIG].type == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_DIG) == TYPE_GROUND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_SANDSHREW) { Moves(MOVE_DIG); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -695,7 +695,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's m AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if player's mon is charging and it has a good switchin immunity (ability)") { GIVEN { - ASSUME(gMovesInfo[MOVE_DIG].type == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_DIG) == TYPE_GROUND); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_SANDSHREW) { Moves(MOVE_DIG); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -723,7 +723,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has an PARAMETRIZE { aiMon = SPECIES_ELECTRODE; absorbingAbility = ABILITY_SOUNDPROOF; move = MOVE_HYPER_VOICE;} GIVEN { ASSUME(B_REDIRECT_ABILITY_IMMUNITY >= GEN_5); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_ZIGZAGOON) { Moves(move); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_TACKLE); } @@ -741,8 +741,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if opponent u PARAMETRIZE { move = MOVE_FLY; } GIVEN { - ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(gMovesInfo[MOVE_SKY_ATTACK].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveEffect(MOVE_SKY_ATTACK) == EFFECT_TWO_TURNS_ATTACK); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_SWELLOW) { Moves(move); } OPPONENT(SPECIES_MILOTIC) { Moves(MOVE_SURF); } @@ -783,7 +783,7 @@ AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch out if it has <= 66% HP remaini AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has been Encore'd into a status move") { GIVEN { - ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_AZURILL) { Moves(MOVE_TACKLE, MOVE_ENCORE); } OPPONENT(SPECIES_ODDISH) { Moves(MOVE_TOXIC, MOVE_SWEET_SCENT, MOVE_INGRAIN, MOVE_TACKLE); } @@ -797,7 +797,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if it has bee AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will stay in if Encore'd into super effective move") { GIVEN { - ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_AZURILL) { Moves(MOVE_TACKLE, MOVE_ENCORE); } OPPONENT(SPECIES_ODDISH) { Moves(MOVE_ACID); } @@ -813,7 +813,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if Encore'd i KNOWN_FAILING; // AI still switches even if ShouldSwitch is set to immediately return FALSE, something external seems to be triggering this PASSES_RANDOMLY(50, 100, RNG_AI_SWITCH_ENCORE); GIVEN { - ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_AZURILL) { Moves(MOVE_TACKLE, MOVE_ENCORE); } OPPONENT(SPECIES_ODDISH) { Moves(MOVE_TACKLE); } @@ -859,8 +859,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attac PARAMETRIZE {move = MOVE_EERIE_IMPULSE; aiSpecies = SPECIES_ESPEON; aiMove = MOVE_CONFUSION; }; GIVEN { - ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2); - ASSUME(gMovesInfo[MOVE_EERIE_IMPULSE].effect == EFFECT_SPECIAL_ATTACK_DOWN_2); + ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); + ASSUME(GetMoveEffect(MOVE_EERIE_IMPULSE) == EFFECT_SPECIAL_ATTACK_DOWN_2); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_ARON) { Moves(move, MOVE_TACKLE); } OPPONENT(aiSpecies) { Moves(aiMove); } @@ -880,8 +880,8 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attac PARAMETRIZE {move = MOVE_CONFIDE; move2 = MOVE_EERIE_IMPULSE; aiSpecies = SPECIES_ESPEON; aiMove = MOVE_STORED_POWER; }; GIVEN { - ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2); - ASSUME(gMovesInfo[MOVE_EERIE_IMPULSE].effect == EFFECT_SPECIAL_ATTACK_DOWN_2); + ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); + ASSUME(GetMoveEffect(MOVE_EERIE_IMPULSE) == EFFECT_SPECIAL_ATTACK_DOWN_2); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_SMART_SWITCHING); PLAYER(SPECIES_ARON) { Moves(move, move2, MOVE_TACKLE); } OPPONENT(aiSpecies) { Moves(aiMove); } @@ -924,3 +924,61 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI correctly handles abilities TURN { MOVE(player, MOVE_WATER_GUN); EXPECT_MOVE(opponent, MOVE_ABSORB); } } } + +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI won't switch out if Yawn'd with only Ace mon remaining") +{ + u32 aceFlag; + PARAMETRIZE{ aceFlag = 0; } + PARAMETRIZE{ aceFlag = AI_FLAG_ACE_POKEMON; } + GIVEN { + ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | aceFlag | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_SMART_SWITCHING); + PLAYER(SPECIES_SLOWKING) { Moves(MOVE_YAWN, MOVE_CONFUSION, MOVE_POWER_GEM, MOVE_WATER_PULSE); Item(ITEM_LEFTOVERS); } + OPPONENT(SPECIES_SCOLIPEDE) { Moves(MOVE_POISON_TAIL); } + OPPONENT(SPECIES_ABSOL) { Moves(MOVE_KNOCK_OFF, MOVE_CRUNCH); } + } WHEN { + TURN { MOVE(player, MOVE_YAWN); EXPECT_MOVE(opponent, MOVE_POISON_TAIL); } + if (aceFlag) + TURN { MOVE(player, MOVE_POWER_GEM); EXPECT_MOVE(opponent, MOVE_POISON_TAIL); } + else + TURN { MOVE(player, MOVE_POWER_GEM); EXPECT_SWITCH(opponent, 1); } + } +} + +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI won't switch in ace mon after U-Turn if other options available") +{ + u32 aceFlag; + PARAMETRIZE{ aceFlag = 0; } + PARAMETRIZE{ aceFlag = AI_FLAG_ACE_POKEMON; } + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | aceFlag | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_SMART_SWITCHING); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SURF); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_U_TURN); } + OPPONENT(SPECIES_NUMEL) { Level(5); Moves(MOVE_SPLASH); } + OPPONENT(SPECIES_SCIZOR) { Moves(MOVE_BUG_BITE); } + } WHEN { + if (aceFlag) + TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 1); MOVE(player, MOVE_SURF); } + else + TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 2); MOVE(player, MOVE_SURF); } + } +} + +AI_SINGLE_BATTLE_TEST("Switch AI: AI won't switch in ace mon after U-Turn if other options available") +{ + u32 aceFlag; + PARAMETRIZE{ aceFlag = 0; } + PARAMETRIZE{ aceFlag = AI_FLAG_ACE_POKEMON; } + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | aceFlag | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT); + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SURF); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_U_TURN); } + OPPONENT(SPECIES_NUMEL) { Level(5); Moves(MOVE_SPLASH); } + OPPONENT(SPECIES_SCIZOR) { Moves(MOVE_BUG_BITE); } + } WHEN { + if (aceFlag) + TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 1); MOVE(player, MOVE_SURF); } + else + TURN { EXPECT_MOVE(opponent, MOVE_U_TURN); EXPECT_SEND_OUT(opponent, 2); MOVE(player, MOVE_SURF); } + } +} diff --git a/test/battle/ai/ai_trytofaint.c b/test/battle/ai/ai_trytofaint.c index 10eca2d676b1..a1a23efdec04 100644 --- a/test/battle/ai/ai_trytofaint.c +++ b/test/battle/ai/ai_trytofaint.c @@ -5,7 +5,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers priority moves if it's slower and can kill target") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(100); } PLAYER(SPECIES_WOBBUFFET) { Speed(100); } @@ -20,7 +20,7 @@ AI_SINGLE_BATTLE_TEST("AI prefers priority moves if it's slower and can kill tar AI_SINGLE_BATTLE_TEST("AI will choose a random move if it's faster and can kill target") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(1); } PLAYER(SPECIES_WOBBUFFET) { Speed(1); } @@ -35,7 +35,7 @@ AI_SINGLE_BATTLE_TEST("AI will choose a random move if it's faster and can kill AI_SINGLE_BATTLE_TEST("AI will choose a priority move if it is slower then the target and will be killed") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { Speed(100); } OPPONENT(SPECIES_WOBBUFFET) { HP(60); Speed(1); Moves(MOVE_QUICK_ATTACK, MOVE_STRENGTH); } diff --git a/test/battle/crit_chance.c b/test/battle/crit_chance.c index 69086acbe31e..32c4c3380df9 100644 --- a/test/battle/crit_chance.c +++ b/test/battle/crit_chance.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Crit Chance: Side effected by Lucky Chant blocks critical hits") { GIVEN { - ASSUME(gMovesInfo[MOVE_LUCKY_CHANT].effect == EFFECT_LUCKY_CHANT); + ASSUME(GetMoveEffect(MOVE_LUCKY_CHANT) == EFFECT_LUCKY_CHANT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Crit Chance: Flag ignoresTargetAbility ignores Battle Armor PARAMETRIZE { species = SPECIES_ARMALDO; ability = ABILITY_BATTLE_ARMOR; } GIVEN { - ASSUME(gMovesInfo[MOVE_SUNSTEEL_STRIKE].ignoresTargetAbility == TRUE); + ASSUME(MoveIgnoresTargetAbility(MOVE_SUNSTEEL_STRIKE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { @@ -100,7 +100,7 @@ SINGLE_BATTLE_TEST("Crit Chance: Mold Breaker, Teravolt and Turboblaze ignore Ba SINGLE_BATTLE_TEST("Crit Chance: User effected by Laser Focus causes moves to result in a critical hit") { GIVEN { - ASSUME(gMovesInfo[MOVE_LASER_FOCUS].effect == EFFECT_LASER_FOCUS); + ASSUME(GetMoveEffect(MOVE_LASER_FOCUS) == EFFECT_LASER_FOCUS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -131,7 +131,7 @@ SINGLE_BATTLE_TEST("Crit Chance: Focus Energy increases the user's critical hit PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY); + ASSUME(GetMoveEffect(MOVE_FOCUS_ENERGY) == EFFECT_FOCUS_ENERGY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -149,7 +149,7 @@ SINGLE_BATTLE_TEST("Crit Chance: High crit rate increases the critical hit ratio PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); + ASSUME(GetMoveCriticalHitStage(MOVE_SLASH) == 1); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -195,7 +195,7 @@ SINGLE_BATTLE_TEST("Crit Chance: High crit rate, Super Luck and Scope Lens cause { GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); + ASSUME(GetMoveCriticalHitStage(MOVE_SLASH) == 1); ASSUME(gItemsInfo[ITEM_SCOPE_LENS].holdEffect == HOLD_EFFECT_SCOPE_LENS); PLAYER(SPECIES_TOGEKISS) { Ability(ABILITY_SUPER_LUCK); Item(ITEM_SCOPE_LENS); }; OPPONENT(SPECIES_WOBBUFFET); @@ -257,8 +257,8 @@ SINGLE_BATTLE_TEST("Crit Chance: Focus Energy increases critical hit ratio by tw PASSES_RANDOMLY(8, 8, RNG_CRITICAL_HIT); GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); - ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY); + ASSUME(GetMoveCriticalHitStage(MOVE_SLASH) == 1); + ASSUME(GetMoveEffect(MOVE_FOCUS_ENERGY) == EFFECT_FOCUS_ENERGY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -271,76 +271,3 @@ SINGLE_BATTLE_TEST("Crit Chance: Focus Energy increases critical hit ratio by tw MESSAGE("A critical hit!"); } } - -SINGLE_BATTLE_TEST("Crit Chance: Dragon Cheer fails in a single battle") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_DRAGON_CHEER); } - } SCENE { - MESSAGE("But it failed!"); - } -} - -DOUBLE_BATTLE_TEST("Crit Chance: Dragon Cheer increases critical hit ratio by one on non Dragon types") -{ - PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); - GIVEN { - ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0); - ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WYNAUT); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft); - MESSAGE("Wynaut is getting pumped!"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); - MESSAGE("A critical hit!"); - } -} - -DOUBLE_BATTLE_TEST("Crit Chance: Dragon Cheer increases critical hit ratio by two on Dragon types") -{ - PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); - GIVEN { - ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0); - ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_DRATINI); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft); - MESSAGE("Dratini is getting pumped!"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); - MESSAGE("A critical hit!"); - } -} - -DOUBLE_BATTLE_TEST("Crit Chance: Dragon Cheer fails if critical hit stage was already increased by Focus Energy") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); - ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY); - ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(playerLeft, MOVE_FOCUS_ENERGY); MOVE(playerRight, MOVE_DRAGON_CHEER, target: playerLeft); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, playerLeft); - MESSAGE("But it failed!"); - } -} diff --git a/test/battle/damage_formula.c b/test/battle/damage_formula.c index 049bbf4051fc..067972551018 100644 --- a/test/battle/damage_formula.c +++ b/test/battle/damage_formula.c @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+") PARAMETRIZE { expectedDamage = 168; } PARAMETRIZE { expectedDamage = 168; } GIVEN { - ASSUME(gMovesInfo[MOVE_ICE_FANG].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_ICE_FANG) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_GLACEON) { Level(75); Attack(123); } OPPONENT(SPECIES_GARCHOMP) { Defense(163); } } WHEN { @@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Muscle Band, crit)") PARAMETRIZE { expectedDamage = 276; } PARAMETRIZE { expectedDamage = 268; } GIVEN { - ASSUME(gMovesInfo[MOVE_ICE_FANG].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_ICE_FANG) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_GLACEON) { Level(75); Attack(123); Item(ITEM_MUSCLE_BAND); } OPPONENT(SPECIES_GARCHOMP) { Defense(163); } } WHEN { @@ -100,7 +100,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Marshadow vs Mawile)") PARAMETRIZE { expectedDamage = 124; } PARAMETRIZE { expectedDamage = 123; } GIVEN { - ASSUME(gMovesInfo[MOVE_SPECTRAL_THIEF].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SPECTRAL_THIEF) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_MARSHADOW) { Level(100); Attack(286); } OPPONENT(SPECIES_MAWILE) { Level(100); Defense(226); HP(241); } } WHEN { @@ -248,10 +248,10 @@ DOUBLE_BATTLE_TEST("Transistor Damage calculation", s16 damage) } } GIVEN { - ASSUME(gMovesInfo[MOVE_WILD_CHARGE].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_WILD_CHARGE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveType(MOVE_WILD_CHARGE) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetMoveCategory(MOVE_WILD_CHARGE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_THUNDER_SHOCK) == DAMAGE_CATEGORY_SPECIAL); ASSUME(NUM_DAMAGE_SPREADS == 16); PLAYER(SPECIES_REGIELEKI) { Ability(ABILITY_KLUTZ); } diff --git a/test/battle/form_change/mega_evolution.c b/test/battle/form_change/mega_evolution.c index 4c97c2c1519d..3d9d9cf5079b 100644 --- a/test/battle/form_change/mega_evolution.c +++ b/test/battle/form_change/mega_evolution.c @@ -108,7 +108,7 @@ SINGLE_BATTLE_TEST("Abilities replaced by Mega Evolution do not affect turn orde DOUBLE_BATTLE_TEST("Mega Evolution happens after switching, but before Focus Punch-like Moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_FOCUS_PUNCH].effect == EFFECT_FOCUS_PUNCH); + ASSUME(GetMoveEffect(MOVE_FOCUS_PUNCH) == EFFECT_FOCUS_PUNCH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_VENUSAUR) { Item(ITEM_VENUSAURITE); } OPPONENT(SPECIES_WYNAUT); @@ -157,7 +157,7 @@ SINGLE_BATTLE_TEST("Regular Mega Evolution and Fervent Wish Mega Evolution can h SINGLE_BATTLE_TEST("Mega Evolved Pokemon do not change abilities after fainting") { GIVEN { - ASSUME(gMovesInfo[MOVE_CRUNCH].makesContact == TRUE); + ASSUME(MoveMakesContact(MOVE_CRUNCH) == TRUE); ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[0] != ABILITY_ROUGH_SKIN); ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[1] != ABILITY_ROUGH_SKIN); ASSUME(gSpeciesInfo[SPECIES_GARCHOMP_MEGA].abilities[2] != ABILITY_ROUGH_SKIN); diff --git a/test/battle/form_change/primal_reversion.c b/test/battle/form_change/primal_reversion.c index d4e682e8de78..d7d956d64b82 100644 --- a/test/battle/form_change/primal_reversion.c +++ b/test/battle/form_change/primal_reversion.c @@ -120,7 +120,7 @@ DOUBLE_BATTLE_TEST("Primal reversion's order is determined by Speed - player fas SINGLE_BATTLE_TEST("Primal reversion happens after a mon is sent out after a mon is fainted") { GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET) {HP(1); } PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } OPPONENT(SPECIES_WOBBUFFET); @@ -156,7 +156,7 @@ SINGLE_BATTLE_TEST("Primal reversion happens after a mon is switched in") SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Eject Button") { GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); ASSUME(gItemsInfo[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON); PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_EJECT_BUTTON); } PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } @@ -177,7 +177,7 @@ SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Eject B SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Red Card") { GIVEN { - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); ASSUME(gItemsInfo[ITEM_RED_CARD].holdEffect == HOLD_EFFECT_RED_CARD); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } @@ -197,7 +197,7 @@ SINGLE_BATTLE_TEST("Primal reversion happens after a switch-in caused by Red Car SINGLE_BATTLE_TEST("Primal reversion happens after the entry hazards damage") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPIKES].effect == EFFECT_SPIKES); + ASSUME(GetMoveEffect(MOVE_SPIKES) == EFFECT_SPIKES); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } OPPONENT(SPECIES_WOBBUFFET); @@ -239,7 +239,7 @@ SINGLE_BATTLE_TEST("Primal reversion happens immediately if it was brought in by DOUBLE_BATTLE_TEST("Primal reversion triggers for multiple battlers if multiple fainted the previous turn") { GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_CATERPIE) { HP(1); } PLAYER(SPECIES_RESHIRAM); @@ -262,8 +262,8 @@ DOUBLE_BATTLE_TEST("Primal reversion triggers for multiple battlers if multiple DOUBLE_BATTLE_TEST("Primal reversion triggers for all battlers if multiple fainted the previous turn") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); - ASSUME(gMovesInfo[MOVE_EXPLOSION].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_CATERPIE) { HP(1); } PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } @@ -290,11 +290,11 @@ DOUBLE_BATTLE_TEST("Primal reversion triggers for all battlers if multiple faint DOUBLE_BATTLE_TEST("Primal reversion and other switch-in effects trigger for all battlers if multiple fainted the previous turn") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); - ASSUME(gMovesInfo[MOVE_EXPLOSION].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); - ASSUME(gMovesInfo[MOVE_SPIKES].effect == EFFECT_SPIKES); - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB); + ASSUME(GetMoveEffect(MOVE_SPIKES) == EFFECT_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_CATERPIE) { HP(1); } PLAYER(SPECIES_SCRAFTY) { Ability(ABILITY_INTIMIDATE); } diff --git a/test/battle/form_change/ultra_burst.c b/test/battle/form_change/ultra_burst.c index 8eb21866f334..640db3f881ab 100644 --- a/test/battle/form_change/ultra_burst.c +++ b/test/battle/form_change/ultra_burst.c @@ -74,7 +74,7 @@ SINGLE_BATTLE_TEST("Ultra Burst affects turn order") DOUBLE_BATTLE_TEST("Ultra Burst happens after switching, but before Focus Punch-like Moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_FOCUS_PUNCH].effect == EFFECT_FOCUS_PUNCH); + ASSUME(GetMoveEffect(MOVE_FOCUS_PUNCH) == EFFECT_FOCUS_PUNCH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); } OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/gimmick/dynamax.c b/test/battle/gimmick/dynamax.c index d76febbd0a9f..19cecdf8cb41 100644 --- a/test/battle/gimmick/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x", u16 hp) u32 dynamax; PARAMETRIZE { dynamax = GIMMICK_NONE; } PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } - GIVEN { // TODO: Dynamax level + GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -25,6 +25,49 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax increases HP and max HP by 1.5x", u16 hp) } } +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax Level increases HP and max HP multipliers by 0.05 for each level", u16 hp) +{ + u32 dynamax, level; + PARAMETRIZE { dynamax = GIMMICK_NONE; level = 0; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 0; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 1; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 2; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 3; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 4; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 5; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 6; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 7; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 8; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 9; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; level = 10; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { DynamaxLevel(level); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, gimmick: dynamax); MOVE(opponent, MOVE_CELEBRATE); } + } SCENE { + if (dynamax) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); + MESSAGE("Wobbuffet used Max Strike!"); + } + MESSAGE("The opposing Wobbuffet used Celebrate!"); + } THEN { + results[i].hp = player->hp; + } FINALLY { + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.5), results[1].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.55), results[2].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.6), results[3].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.65), results[4].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.7), results[5].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.75), results[6].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.8), results[7].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.85), results[8].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.9), results[9].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(1.95), results[10].hp); + EXPECT_MUL_EQ(results[0].hp, Q_4_12(2.0), results[11].hp); + } +} + SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp) { u32 dynamax; @@ -38,8 +81,8 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp) TURN { MOVE(player, MOVE_TACKLE); } // 2nd max move TURN { MOVE(player, MOVE_TACKLE); } // 3rd max move } SCENE { - int i; - for (i = 0; i < DYNAMAX_TURNS_COUNT; ++i) { + int j; + for (j = 0; j < DYNAMAX_TURNS_COUNT; ++j) { if (dynamax) MESSAGE("Wobbuffet used Max Strike!"); else @@ -55,10 +98,53 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns", u16 hp) } } +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamax expires after three turns and correctly converts HP according to Dynamax Level") +{ + u32 dynamaxLevel, dynamax; + u16 capturedHP, finalHP; + s16 capturedDamage; + PARAMETRIZE { dynamaxLevel = 0; dynamax = GIMMICK_NONE; } + PARAMETRIZE { dynamaxLevel = 0; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 1; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 2; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 3; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 4; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 5; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 6; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 7; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 8; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 9; dynamax = GIMMICK_DYNAMAX; } + PARAMETRIZE { dynamaxLevel = 10; dynamax = GIMMICK_DYNAMAX; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { DynamaxLevel(dynamaxLevel); HP(200); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: dynamax); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); } + TURN { } + } SCENE { + if (dynamax) + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + if (dynamax) + HP_BAR(player, captureHP: &capturedHP); + else + HP_BAR(player, captureDamage: &capturedDamage); + if (dynamax) + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } THEN { + finalHP = player->hp; + if (dynamax) + EXPECT_MUL_EQ(finalHP, GetDynamaxLevelHPMultiplier(dynamaxLevel, FALSE), capturedHP); + EXPECT_LE(finalHP, 200); + EXPECT_GE(finalHP, 200 - capturedDamage); + } +} + SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched") { GIVEN { - ASSUME(gMovesInfo[MOVE_FAKE_OUT].effect == EFFECT_FIRST_TURN_ONLY); + ASSUME(GetMoveEffect(MOVE_FAKE_OUT) == EFFECT_FIRST_TURN_ONLY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -73,7 +159,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be flinched") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be hit by weight-based moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_HEAVY_SLAM].effect == EFFECT_HEAT_CRASH); + ASSUME(GetMoveEffect(MOVE_HEAVY_SLAM) == EFFECT_HEAT_CRASH); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -89,7 +175,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be hit by weight-based mo SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be hit by OHKO moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_FISSURE].effect == EFFECT_OHKO); + ASSUME(GetMoveEffect(MOVE_FISSURE) == EFFECT_OHKO); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_MACHAMP) { Ability(ABILITY_NO_GUARD); } } WHEN { @@ -102,22 +188,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon cannot be hit by OHKO moves") } } -// can't be used at all in Raid, see "Documenting Dynamax" -SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Destiny Bond") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; - OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } - } WHEN { - TURN { MOVE(opponent, MOVE_DESTINY_BOND); MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); } - } SCENE { - MESSAGE("The opposing Wobbuffet used Destiny Bond!"); - MESSAGE("Wobbuffet used Max Strike!"); - MESSAGE("The opposing Wobbuffet fainted!"); - NONE_OF { HP_BAR(player); } - } -} - SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are affected by Grudge") { GIVEN { @@ -136,8 +206,8 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are affected by Grudge") SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by phazing moves, but still take damage") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); - ASSUME(gMovesInfo[MOVE_WHIRLWIND].effect == EFFECT_ROAR); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_WHIRLWIND) == EFFECT_ROAR); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -158,7 +228,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by phazing move SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by phazing moves but no block message is printed if they faint") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); PLAYER(SPECIES_WOBBUFFET) { HP(1); }; PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -243,41 +313,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can have their ability changed o } } -SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Encore") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); MOVE(opponent, MOVE_ENCORE); } - TURN { MOVE(player, MOVE_EMBER); } - } SCENE { - MESSAGE("Wobbuffet used Max Strike!"); - MESSAGE("The opposing Wobbuffet used Encore!"); - MESSAGE("But it failed!"); - MESSAGE("Wobbuffet used Max Flare!"); - } -} - -SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can be encored immediately after reverting") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; // yes, this speed is necessary - OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }; - } WHEN { - TURN { MOVE(player, MOVE_ARM_THRUST, gimmick: GIMMICK_DYNAMAX); } - TURN { MOVE(player, MOVE_ARM_THRUST); } - TURN { MOVE(player, MOVE_ARM_THRUST); } - TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_TACKLE); } - } SCENE { - MESSAGE("Wobbuffet used Max Knuckle!"); - MESSAGE("Wobbuffet used Max Knuckle!"); - MESSAGE("Wobbuffet used Max Knuckle!"); - MESSAGE("The opposing Wobbuffet used Encore!"); - MESSAGE("Wobbuffet used Arm Thrust!"); - } -} - // Max Moves don't make contact, so Cursed Body doesn't need to be tested, but it is coded for. SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon's Max Moves cannot be disabled") { @@ -362,21 +397,44 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon lose their substitutes") } } -SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon take double damage from Dynamax Cannon", s16 damage) +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon that changes forms does not gain HP") { - u32 dynamax; - PARAMETRIZE { dynamax = GIMMICK_NONE; } - PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } + u16 capturedHP, finalHP; GIVEN { - ASSUME(gMovesInfo[MOVE_DYNAMAX_CANNON].effect == EFFECT_DYNAMAX_DOUBLE_DMG); - PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_GRENINJA_BATTLE_BOND) { Ability(ABILITY_BATTLE_BOND); HP(100); Speed(100); } + OPPONENT(SPECIES_CATERPIE) { HP(1); Speed(1000); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureHP: &capturedHP); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAX_STRIKE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } THEN { + finalHP = player->hp; + EXPECT_EQ(capturedHP, finalHP); + } +} + +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon that changes forms does not gain HP unless the new form gains Max HP") +{ + u32 hp = 1, maxHP = 200; + u32 species; + PARAMETRIZE { species = SPECIES_ZYGARDE_10_POWER_CONSTRUCT; } + PARAMETRIZE { species = SPECIES_ZYGARDE_50_POWER_CONSTRUCT; } + GIVEN { + PLAYER(species) { Ability(ABILITY_POWER_CONSTRUCT); HP(hp); MaxHP(maxHP); DynamaxLevel(0); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_TACKLE, gimmick: dynamax); MOVE(opponent, MOVE_DYNAMAX_CANNON); } + TURN { MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); } } SCENE { - HP_BAR(player, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_DYNAMAX_GROWTH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAX_STRIKE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + } THEN { + EXPECT_MUL_EQ(maxHP - hp, GetDynamaxLevelHPMultiplier(0, FALSE), player->maxHP - player->hp); } } @@ -400,7 +458,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves deal 1/4 damage through protect", s16 da } } -// This test will fail if it's the first test a thread runs SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves don't bypass Max Guard") { GIVEN { @@ -531,7 +588,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Endeavor uses a Pokemon's non-Dynamax HP", s16 dam PARAMETRIZE { dynamax = GIMMICK_NONE; } PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } GIVEN { - ASSUME(gMovesInfo[MOVE_ENDEAVOR].effect == EFFECT_ENDEAVOR); + ASSUME(GetMoveEffect(MOVE_ENDEAVOR) == EFFECT_ENDEAVOR); PLAYER(SPECIES_WOBBUFFET) { Speed(50); } OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } } WHEN { @@ -550,7 +607,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Super Fang uses a Pokemon's non-Dynamax HP", s16 d PARAMETRIZE { dynamax = GIMMICK_NONE; } PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } GIVEN { - ASSUME(gMovesInfo[MOVE_SUPER_FANG].effect == EFFECT_SUPER_FANG); + ASSUME(GetMoveEffect(MOVE_SUPER_FANG) == EFFECT_SUPER_FANG); PLAYER(SPECIES_WOBBUFFET) { Speed(50); } OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } } WHEN { @@ -569,7 +626,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Pain Split uses a Pokemon's non-Dynamax HP", s16 d PARAMETRIZE { dynamax = GIMMICK_NONE; } PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } GIVEN { - ASSUME(gMovesInfo[MOVE_PAIN_SPLIT].effect == EFFECT_PAIN_SPLIT); + ASSUME(GetMoveEffect(MOVE_PAIN_SPLIT) == EFFECT_PAIN_SPLIT); PLAYER(SPECIES_WOBBUFFET) { Speed(50); } OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } } WHEN { @@ -608,7 +665,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Heal Pulse heals based on a Pokemon's non-Dynamax PARAMETRIZE { dynamax = GIMMICK_NONE; } PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } GIVEN { - ASSUME(gMovesInfo[MOVE_HEAL_PULSE].effect == EFFECT_HEAL_PULSE); + ASSUME(GetMoveEffect(MOVE_HEAL_PULSE) == EFFECT_HEAL_PULSE); PLAYER(SPECIES_WOBBUFFET) { HP(1); Speed(50); } OPPONENT(SPECIES_WOBBUFFET) { MaxHP(100); Speed(100); } } WHEN { @@ -626,7 +683,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") { GIVEN { // Fails?: ASSUME(GetMaxMove(B_POSITION_PLAYER_LEFT, MOVE_TACKLE) == MOVE_MAX_STRIKE); - ASSUME(gMovesInfo[MOVE_MAX_STRIKE].argument.maxEffect == MAX_EFFECT_LOWER_SPEED); + ASSUME(GetMoveMaxEffect(MOVE_MAX_STRIKE) == MAX_EFFECT_LOWER_SPEED); OPPONENT(SPECIES_WOBBUFFET) { Speed(100); } PLAYER(SPECIES_WOBBUFFET) { Speed(80); } } WHEN { @@ -650,7 +707,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers single opponent's speed") DOUBLE_BATTLE_TEST("(DYNAMAX) Max Strike lowers both opponents' speed") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_STRIKE].argument.maxEffect == MAX_EFFECT_LOWER_SPEED); + ASSUME(GetMoveMaxEffect(MOVE_MAX_STRIKE) == MAX_EFFECT_LOWER_SPEED); PLAYER(SPECIES_WOBBUFFET) { Speed(80); } PLAYER(SPECIES_WOBBUFFET) { Speed(79); } OPPONENT(SPECIES_WOBBUFFET) {Speed(100); } @@ -687,9 +744,9 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") { s16 damage[4]; GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_KNUCKLE].argument.maxEffect == MAX_EFFECT_RAISE_TEAM_ATTACK); - ASSUME(gMovesInfo[MOVE_CLOSE_COMBAT].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveMaxEffect(MOVE_MAX_KNUCKLE) == MAX_EFFECT_RAISE_TEAM_ATTACK); + ASSUME(GetMoveCategory(MOVE_CLOSE_COMBAT) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -729,7 +786,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) Max Knuckle raises both allies' attack") SINGLE_BATTLE_TEST("(DYNAMAX) Max Flare sets up sunlight") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_FLARE].argument.maxEffect == MAX_EFFECT_SUN); + ASSUME(GetMoveMaxEffect(MOVE_MAX_FLARE) == MAX_EFFECT_SUN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -745,7 +802,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Flare sets up sunlight") SINGLE_BATTLE_TEST("(DYNAMAX) Max Geyser sets up heavy rain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_GEYSER].argument.maxEffect == MAX_EFFECT_RAIN); + ASSUME(GetMoveMaxEffect(MOVE_MAX_GEYSER) == MAX_EFFECT_RAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -761,7 +818,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Geyser sets up heavy rain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Hailstorm sets up hail") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_HAILSTORM].argument.maxEffect == MAX_EFFECT_HAIL); + ASSUME(GetMoveMaxEffect(MOVE_MAX_HAILSTORM) == MAX_EFFECT_HAIL); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -777,7 +834,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Hailstorm sets up hail") SINGLE_BATTLE_TEST("(DYNAMAX) Max Rockfall sets up a sandstorm") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_ROCKFALL].argument.maxEffect == MAX_EFFECT_SANDSTORM); + ASSUME(GetMoveMaxEffect(MOVE_MAX_ROCKFALL) == MAX_EFFECT_SANDSTORM); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -794,7 +851,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Overgrowth sets up Grassy Terrain") { s32 maxHP = 490; // Because of recalculated stats upon Dynamaxing GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_OVERGROWTH].argument.maxEffect == MAX_EFFECT_GRASSY_TERRAIN); + ASSUME(GetMoveMaxEffect(MOVE_MAX_OVERGROWTH) == MAX_EFFECT_GRASSY_TERRAIN); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].baseHP == 190); OPPONENT(SPECIES_WOBBUFFET) { MaxHP(maxHP); HP(maxHP / 2); }; PLAYER(SPECIES_WOBBUFFET) { MaxHP(maxHP); HP(maxHP / 2); }; @@ -814,7 +871,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Overgrowth sets up Grassy Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Mindstorm sets up Psychic Terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_MINDSTORM].argument.maxEffect == MAX_EFFECT_PSYCHIC_TERRAIN); + ASSUME(GetMoveMaxEffect(MOVE_MAX_MINDSTORM) == MAX_EFFECT_PSYCHIC_TERRAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -831,7 +888,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Mindstorm sets up Psychic Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Lightning sets up Electric Terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_LIGHTNING].argument.maxEffect == MAX_EFFECT_ELECTRIC_TERRAIN); + ASSUME(GetMoveMaxEffect(MOVE_MAX_LIGHTNING) == MAX_EFFECT_ELECTRIC_TERRAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -846,7 +903,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Lightning sets up Electric Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) Max Starfall sets up Misty Terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_MAX_STARFALL].argument.maxEffect == MAX_EFFECT_MISTY_TERRAIN); + ASSUME(GetMoveMaxEffect(MOVE_MAX_STARFALL) == MAX_EFFECT_MISTY_TERRAIN); OPPONENT(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); } WHEN { @@ -861,7 +918,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Starfall sets up Misty Terrain") SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STONESURGE].argument.maxEffect == MAX_EFFECT_STEALTH_ROCK); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_STONESURGE) == MAX_EFFECT_STEALTH_ROCK); PLAYER(SPECIES_DREDNAW) { GigantamaxFactor(TRUE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -881,7 +938,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Stonesurge sets up Stealth Rocks") SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Steelsurge sets up sharp steel") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STEELSURGE].argument.maxEffect == MAX_EFFECT_STEELSURGE); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_STEELSURGE) == MAX_EFFECT_STEELSURGE); PLAYER(SPECIES_COPPERAJAH) { GigantamaxFactor(TRUE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_HATTERENE); @@ -912,7 +969,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Hydrosnipe has fixed power and ignores abili PARAMETRIZE { move = MOVE_WATER_GUN; } PARAMETRIZE { move = MOVE_HYDRO_CANNON; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_HYDROSNIPE].argument.maxEffect == MAX_EFFECT_FIXED_POWER); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_HYDROSNIPE) == MAX_EFFECT_FIXED_POWER); PLAYER(SPECIES_INTELEON) { GigantamaxFactor(TRUE); } OPPONENT(SPECIES_ARCTOVISH) { Ability(ABILITY_WATER_ABSORB); } } WHEN { @@ -928,7 +985,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) G-Max Hydrosnipe has fixed power and ignores abili DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Volt Crash paralyzes both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_VOLT_CRASH].argument.maxEffect == MAX_EFFECT_PARALYZE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_VOLT_CRASH) == MAX_EFFECT_PARALYZE_FOES); PLAYER(SPECIES_PIKACHU) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_PICHU); OPPONENT(SPECIES_WOBBUFFET); @@ -955,7 +1012,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponen PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = STATUS1_PARALYSIS; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STUN_SHOCK].argument.maxEffect == MAX_EFFECT_POISON_PARALYZE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_STUN_SHOCK) == MAX_EFFECT_POISON_PARALYZE_FOES); PLAYER(SPECIES_TOXTRICITY) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_TOXEL); OPPONENT(SPECIES_WOBBUFFET); @@ -992,7 +1049,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock paralyzes or poisons both opponen DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Stun Shock chooses statuses before considering immunities") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_STUN_SHOCK].argument.maxEffect == MAX_EFFECT_POISON_PARALYZE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_STUN_SHOCK) == MAX_EFFECT_POISON_PARALYZE_FOES); PLAYER(SPECIES_TOXTRICITY) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_TOXEL); OPPONENT(SPECIES_GARBODOR); @@ -1025,7 +1082,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Befuddle paralyzes, poisons, or sleeps both PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = STATUS1_POISON; } PARAMETRIZE { statusAnim = B_ANIM_STATUS_SLP; rng = STATUS1_SLEEP; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_BEFUDDLE].argument.maxEffect == MAX_EFFECT_EFFECT_SPORE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_BEFUDDLE) == MAX_EFFECT_EFFECT_SPORE_FOES); PLAYER(SPECIES_BUTTERFREE) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_CATERPIE); OPPONENT(SPECIES_WOBBUFFET); @@ -1069,7 +1126,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Befuddle paralyzes, poisons, or sleeps both DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Gold Rush confuses both opponents and generates money") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_GOLD_RUSH].argument.maxEffect == MAX_EFFECT_CONFUSE_FOES_PAY_DAY); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_GOLD_RUSH) == MAX_EFFECT_CONFUSE_FOES_PAY_DAY); PLAYER(SPECIES_MEOWTH) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_PERSIAN); OPPONENT(SPECIES_WOBBUFFET); @@ -1089,7 +1146,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Gold Rush confuses both opponents and genera DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Smite confuses both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_SMITE].argument.maxEffect == MAX_EFFECT_CONFUSE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_SMITE) == MAX_EFFECT_CONFUSE_FOES); PLAYER(SPECIES_HATTERENE) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_HATENNA); OPPONENT(SPECIES_WOBBUFFET); @@ -1108,7 +1165,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Smite confuses both opponents") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Cuddle infatuates both opponents, if possible") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_CUDDLE].argument.maxEffect == MAX_EFFECT_INFATUATE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_CUDDLE) == MAX_EFFECT_INFATUATE_FOES); PLAYER(SPECIES_EEVEE) { Gender(MON_MALE); GigantamaxFactor(TRUE); } PLAYER(SPECIES_EEVEE); OPPONENT(SPECIES_WOBBUFFET) { Gender(MON_FEMALE); } @@ -1129,7 +1186,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Cuddle infatuates both opponents, if possibl DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Terror traps both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_TERROR].argument.maxEffect == MAX_EFFECT_MEAN_LOOK); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_TERROR) == MAX_EFFECT_MEAN_LOOK); PLAYER(SPECIES_GENGAR) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_GASTLY); OPPONENT(SPECIES_WOBBUFFET); @@ -1150,7 +1207,7 @@ TO_DO_BATTLE_TEST("(DYNAMAX) Baton Pass passes G-Max Terror's escape prevention DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Meltdown torments both opponents for 3 turns") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_MELTDOWN].argument.maxEffect == MAX_EFFECT_TORMENT_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_MELTDOWN) == MAX_EFFECT_TORMENT_FOES); PLAYER(SPECIES_MELMETAL) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_MELTAN); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SPLASH, MOVE_CELEBRATE); } @@ -1187,7 +1244,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Wildfire sets a field effect that damages no { s16 damage; GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_WILDFIRE].argument.maxEffect == MAX_EFFECT_WILDFIRE); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_WILDFIRE) == MAX_EFFECT_WILDFIRE); PLAYER(SPECIES_CHARIZARD) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_CHARMANDER); OPPONENT(SPECIES_WOBBUFFET) { HP(600); MaxHP(600); } @@ -1233,7 +1290,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Replenish recycles allies' berries 50\% of t { PASSES_RANDOMLY(1, 2, RNG_G_MAX_REPLENISH); GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_REPLENISH].argument.maxEffect == MAX_EFFECT_RECYCLE_BERRIES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_REPLENISH) == MAX_EFFECT_RECYCLE_BERRIES); PLAYER(SPECIES_SNORLAX) { Item(ITEM_APICOT_BERRY); GigantamaxFactor(TRUE); } PLAYER(SPECIES_MUNCHLAX) { Item(ITEM_APICOT_BERRY); Ability(ABILITY_THICK_FAT); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_APICOT_BERRY); } @@ -1261,8 +1318,8 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Snooze makes only the target drowsy") { PASSES_RANDOMLY(1, 2, RNG_G_MAX_SNOOZE); GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_SNOOZE].argument.maxEffect == MAX_EFFECT_YAWN_FOE); - ASSUME(gMovesInfo[MOVE_DARK_PULSE].category == DAMAGE_CATEGORY_SPECIAL); // Otherwise, Blissey faints. + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_SNOOZE) == MAX_EFFECT_YAWN_FOE); + ASSUME(GetMoveCategory(MOVE_DARK_PULSE) == DAMAGE_CATEGORY_SPECIAL); // Otherwise, Blissey faints. PLAYER(SPECIES_GRIMMSNARL) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_IMPIDIMP); OPPONENT(SPECIES_BLISSEY); @@ -1285,7 +1342,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Finale heals allies by 1/6 of their health") { s16 damage1, damage2; GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_FINALE].argument.maxEffect == MAX_EFFECT_HEAL_TEAM); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_FINALE) == MAX_EFFECT_HEAL_TEAM); PLAYER(SPECIES_ALCREMIE) { HP(1); GigantamaxFactor(TRUE); } PLAYER(SPECIES_MILCERY) { HP(1); } OPPONENT(SPECIES_WOBBUFFET); @@ -1305,7 +1362,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Finale heals allies by 1/6 of their health") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Sweetness cures allies' status conditions") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_SWEETNESS].argument.maxEffect == MAX_EFFECT_AROMATHERAPY); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_SWEETNESS) == MAX_EFFECT_AROMATHERAPY); PLAYER(SPECIES_APPLETUN) { Status1(STATUS1_POISON); GigantamaxFactor(TRUE); } PLAYER(SPECIES_APPLIN) { Status1(STATUS1_POISON); } OPPONENT(SPECIES_WOBBUFFET); @@ -1325,7 +1382,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Sweetness cures allies' status conditions") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Centiferno traps both opponents in Fire Spin") { GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_CENTIFERNO].argument.maxEffect == MAX_EFFECT_FIRE_SPIN_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_CENTIFERNO) == MAX_EFFECT_FIRE_SPIN_FOES); PLAYER(SPECIES_CENTISKORCH) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_SIZZLIPEDE); PLAYER(SPECIES_SIZZLIPEDE); @@ -1354,7 +1411,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Chi Strike boosts allies' crit chance") u32 j; GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_6); - ASSUME(gMovesInfo[MOVE_G_MAX_CHI_STRIKE].argument.maxEffect == MAX_EFFECT_CRIT_PLUS); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_CHI_STRIKE) == MAX_EFFECT_CRIT_PLUS); PLAYER(SPECIES_MACHAMP) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_MACHOP); OPPONENT(SPECIES_WOBBUFFET); @@ -1385,8 +1442,8 @@ TO_DO_BATTLE_TEST("(DYNAMAX) Baton Pass doesn't pass G-Max Chi Strike's effect") DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Depletion takes away 2 PP from the target's last move") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_CLAW].category == DAMAGE_CATEGORY_PHYSICAL); // Otherwise Sableye faints. - ASSUME(gMovesInfo[MOVE_G_MAX_DEPLETION].argument.maxEffect == MAX_EFFECT_SPITE); + ASSUME(GetMoveCategory(MOVE_DRAGON_CLAW) == DAMAGE_CATEGORY_PHYSICAL); // Otherwise Sableye faints. + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_DEPLETION) == MAX_EFFECT_SPITE); PLAYER(SPECIES_DURALUDON) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_WYNAUT); // Dynamax behaves weird with test turn order because stats are recalculated. @@ -1408,7 +1465,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max One Blow bypasses Max Guard for full damage" PARAMETRIZE { protect = TRUE; } PARAMETRIZE { protect = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_G_MAX_ONE_BLOW].argument.maxEffect == MAX_EFFECT_BYPASS_PROTECT); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_ONE_BLOW) == MAX_EFFECT_BYPASS_PROTECT); PLAYER(SPECIES_URSHIFU) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_KUBFU); OPPONENT(SPECIES_WOBBUFFET); @@ -1466,7 +1523,7 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves don't execute effects on fainted battler SINGLE_BATTLE_TEST("(DYNAMAX) Moxie clones can be triggered by Max Moves fainting opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_WATERFALL].power > 0); + ASSUME(GetMovePower(MOVE_WATERFALL) > 0); PLAYER(SPECIES_GYARADOS) { Ability(ABILITY_MOXIE); } OPPONENT(SPECIES_WOBBUFFET) { HP(1); } OPPONENT(SPECIES_WYNAUT); @@ -1479,7 +1536,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Moxie clones can be triggered by Max Moves faintin } } -// This test will fail if it's the first test a thread runs SINGLE_BATTLE_TEST("(DYNAMAX) Max Attacks prints a message when hitting into Max Guard") { GIVEN { @@ -1508,11 +1564,11 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves don't bypass absorbing abilities") PARAMETRIZE { move = MOVE_VINE_WHIP; ability = ABILITY_SAP_SIPPER; species = SPECIES_MILTANK; } GIVEN { - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_SPARK].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_MUD_BOMB].type == TYPE_GROUND); - ASSUME(gMovesInfo[MOVE_VINE_WHIP].type == TYPE_GRASS); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + ASSUME(GetMoveType(MOVE_SPARK) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_MUD_BOMB) == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); PLAYER(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c index a9e8fca871d3..c9e51faa8b3b 100644 --- a/test/battle/gimmick/terastal.c +++ b/test/battle/gimmick/terastal.c @@ -92,7 +92,7 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing boosts moves of the same type to 60 BP PARAMETRIZE { tera = GIMMICK_NONE; } PARAMETRIZE { tera = GIMMICK_TERA; } GIVEN { - ASSUME(gMovesInfo[MOVE_ABSORB].power == 20); + ASSUME(GetMovePower(MOVE_ABSORB) == 20); PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GRASS); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor occurs after Technicia PARAMETRIZE { tera = GIMMICK_NONE; } PARAMETRIZE { tera = GIMMICK_TERA; } GIVEN { - ASSUME(gMovesInfo[MOVE_MEGA_DRAIN].power == 40); + ASSUME(GetMovePower(MOVE_MEGA_DRAIN) == 40); PLAYER(SPECIES_MR_MIME) { Ability(ABILITY_TECHNICIAN); TeraType(TYPE_GRASS); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -186,6 +186,25 @@ SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor does not apply to prio } } +SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor does not apply to dynamic base power moves", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = GIMMICK_NONE; } + PARAMETRIZE { tera = GIMMICK_TERA; } + GIVEN { + ASSUME(gMovesInfo[MOVE_WATER_SPOUT].effect == EFFECT_POWER_BASED_ON_USER_HP); + PLAYER(SPECIES_WOBBUFFET) { HP(1); TeraType(TYPE_WATER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_WATER_SPOUT, gimmick: tera); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_SPOUT, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + // Defensive Type Checks SINGLE_BATTLE_TEST("(TERA) Terastallization changes type effectiveness", s16 damage) @@ -393,7 +412,7 @@ SINGLE_BATTLE_TEST("(TERA) Double Shock does not remove the user's Electric type { s16 damage[4]; GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SHOCK) == EFFECT_FAIL_IF_NOT_ARG_TYPE); PLAYER(SPECIES_PICHU) { TeraType(TYPE_ELECTRIC); } PLAYER(SPECIES_WOBBUFFET) OPPONENT(SPECIES_WOBBUFFET); @@ -608,8 +627,8 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves { s16 damage[4]; GIVEN { - ASSUME(gMovesInfo[MOVE_MEGA_DRAIN].power == 40); - ASSUME(gMovesInfo[MOVE_BUBBLE].power == 40); + ASSUME(GetMovePower(MOVE_MEGA_DRAIN) == 40); + ASSUME(GetMovePower(MOVE_BUBBLE) == 40); PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -688,7 +707,7 @@ SINGLE_BATTLE_TEST("(TERA) Stellar type's one-time boost factors in dynamically- { s16 damage[4]; GIVEN { - ASSUME(gMovesInfo[MOVE_WEATHER_BALL].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_WEATHER_BALL) == TYPE_NORMAL); PLAYER(SPECIES_PELIPPER) { Ability(ABILITY_DRIZZLE); TeraType(TYPE_STELLAR); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -731,8 +750,8 @@ SINGLE_BATTLE_TEST("(TERA) Terapagos retains the Stellar type boost at all times PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_MACH_PUNCH; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_MACH_PUNCH].type != TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_MACH_PUNCH) != TYPE_NORMAL); PLAYER(SPECIES_TERAPAGOS); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/gimmick/zmove.c b/test/battle/gimmick/zmove.c index eb44184e5aed..358e38d031aa 100644 --- a/test/battle/gimmick/zmove.c +++ b/test/battle/gimmick/zmove.c @@ -6,7 +6,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves do not retain priority") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_QUICK_ATTACK) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -22,7 +22,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves do not retain priority") SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves are not affected by -ate abilities") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); ASSUME(gSpeciesInfo[SPECIES_SWELLOW].types[1] == TYPE_FLYING); PLAYER(SPECIES_AURORUS) { Ability(ABILITY_REFRIGERATE); Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_SWELLOW); @@ -38,8 +38,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves are not affected by -ate abilities") SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves are affected by Ion Deluge") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_ION_DELUGE].effect == EFFECT_ION_DELUGE); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMoveEffect(MOVE_ION_DELUGE) == EFFECT_ION_DELUGE); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_SWELLOW); } WHEN { @@ -57,8 +57,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves deal 1/4 damage through protect", s16 damag PARAMETRIZE { protected = TRUE; } PARAMETRIZE { protected = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_PROTECT].effect == EFFECT_PROTECT); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -77,7 +77,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves deal 1/4 damage through protect", s16 damag SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_RESET_STATS clears a battler's negative stat stages") { GIVEN { - ASSUME(gMovesInfo[MOVE_LEECH_SEED].zMove.effect == Z_EFFECT_RESET_STATS); + ASSUME(GetMoveZEffect(MOVE_LEECH_SEED) == Z_EFFECT_RESET_STATS); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_GRASSIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -96,8 +96,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_RESET_STATS clears a battler's negative st SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_ALL_STATS_UP raises all of a battler's stat stages by one") { GIVEN { - ASSUME(gMovesInfo[MOVE_CELEBRATE].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_CELEBRATE].zMove.effect == Z_EFFECT_ALL_STATS_UP_1); + ASSUME(GetMoveType(MOVE_CELEBRATE) == TYPE_NORMAL); + ASSUME(GetMoveZEffect(MOVE_CELEBRATE) == Z_EFFECT_ALL_STATS_UP_1); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -118,8 +118,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_BOOST_CRITS raises a battler's critical hi { PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { - ASSUME(gMovesInfo[MOVE_FORESIGHT].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_FORESIGHT].zMove.effect == Z_EFFECT_BOOST_CRITS); + ASSUME(GetMoveType(MOVE_FORESIGHT) == TYPE_NORMAL); + ASSUME(GetMoveZEffect(MOVE_FORESIGHT) == Z_EFFECT_BOOST_CRITS); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -136,8 +136,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_BOOST_CRITS raises a battler's critical hi DOUBLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_FOLLOW_ME redirects attacks to the user") { GIVEN { - ASSUME(gMovesInfo[MOVE_DESTINY_BOND].type == TYPE_GHOST); - ASSUME(gMovesInfo[MOVE_DESTINY_BOND].zMove.effect == Z_EFFECT_FOLLOW_ME); + ASSUME(GetMoveType(MOVE_DESTINY_BOND) == TYPE_GHOST); + ASSUME(GetMoveZEffect(MOVE_DESTINY_BOND) == Z_EFFECT_FOLLOW_ME); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_GHOSTIUM_Z); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -157,8 +157,8 @@ DOUBLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_FOLLOW_ME redirects attacks to the user") SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_RESTORE_REPLACEMENT_HP fully heals the replacement battler's HP") { GIVEN { - ASSUME(gMovesInfo[MOVE_PARTING_SHOT].type == TYPE_DARK); - ASSUME(gMovesInfo[MOVE_PARTING_SHOT].zMove.effect == Z_EFFECT_RESTORE_REPLACEMENT_HP); + ASSUME(GetMoveType(MOVE_PARTING_SHOT) == TYPE_DARK); + ASSUME(GetMoveZEffect(MOVE_PARTING_SHOT) == Z_EFFECT_RESTORE_REPLACEMENT_HP); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_DARKINIUM_Z); } PLAYER(SPECIES_WYNAUT) { HP(1); } OPPONENT(SPECIES_WOBBUFFET); @@ -181,11 +181,11 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_CURSE activates Z_EFFECT_RECOVER_HP or Z_E PARAMETRIZE { species = SPECIES_WOBBUFFET; } PARAMETRIZE { species = SPECIES_DUSCLOPS; } GIVEN { - ASSUME(gMovesInfo[MOVE_CURSE].type == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_CURSE) == TYPE_GHOST); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_GHOST); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_GHOST); ASSUME(gSpeciesInfo[SPECIES_DUSCLOPS].types[0] == TYPE_GHOST); - ASSUME(gMovesInfo[MOVE_CURSE].zMove.effect == Z_EFFECT_CURSE); + ASSUME(GetMoveZEffect(MOVE_CURSE) == Z_EFFECT_CURSE); PLAYER(species) { Item(ITEM_GHOSTIUM_Z); HP(1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -218,8 +218,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z_EFFECT_CURSE activates Z_EFFECT_RECOVER_HP or Z_E SINGLE_BATTLE_TEST("(Z-MOVE) Z-Mirror Move raises the user's attack by two stages and copies the last used non-status move as a Z-Move") { GIVEN { - ASSUME(gMovesInfo[MOVE_MIRROR_MOVE].type == TYPE_FLYING); - ASSUME(gMovesInfo[MOVE_MIRROR_MOVE].zMove.effect == Z_EFFECT_ATK_UP_2); + ASSUME(GetMoveType(MOVE_MIRROR_MOVE) == TYPE_FLYING); + ASSUME(GetMoveZEffect(MOVE_MIRROR_MOVE) == Z_EFFECT_ATK_UP_2); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_FLYINIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -240,8 +240,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Mirror Move raises the user's attack by two stage SINGLE_BATTLE_TEST("(Z-MOVE) Z-Mirror Move raises the user's attack by two stages and copies the last used status move regularly") { GIVEN { - ASSUME(gMovesInfo[MOVE_MIRROR_MOVE].type == TYPE_FLYING); - ASSUME(gMovesInfo[MOVE_MIRROR_MOVE].zMove.effect == Z_EFFECT_ATK_UP_2); + ASSUME(GetMoveType(MOVE_MIRROR_MOVE) == TYPE_FLYING); + ASSUME(GetMoveZEffect(MOVE_MIRROR_MOVE) == Z_EFFECT_ATK_UP_2); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_FLYINIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -259,8 +259,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Mirror Move raises the user's attack by two stage SINGLE_BATTLE_TEST("(Z-MOVE) Z-Copycat raises the user's accuracy by one stage and copies the last used non-status move as a Z-Move") { GIVEN { - ASSUME(gMovesInfo[MOVE_COPYCAT].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_COPYCAT].zMove.effect == Z_EFFECT_ACC_UP_1); + ASSUME(GetMoveType(MOVE_COPYCAT) == TYPE_NORMAL); + ASSUME(GetMoveZEffect(MOVE_COPYCAT) == Z_EFFECT_ACC_UP_1); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -281,8 +281,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Me First raises the user's speed by two stages an PARAMETRIZE { meFirst = TRUE; } PARAMETRIZE { meFirst = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_ME_FIRST].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_ME_FIRST].zMove.effect == Z_EFFECT_SPD_UP_2); + ASSUME(GetMoveType(MOVE_ME_FIRST) == TYPE_NORMAL); + ASSUME(GetMoveZEffect(MOVE_ME_FIRST) == Z_EFFECT_SPD_UP_2); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -313,7 +313,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Nature Power transforms into different Z-Moves ba PARAMETRIZE { terrainMove = MOVE_GRASSY_TERRAIN; zMove = gTypesInfo[TYPE_GRASS].zMove; } PARAMETRIZE { terrainMove = MOVE_MISTY_TERRAIN; zMove = gTypesInfo[TYPE_FAIRY].zMove; } GIVEN { - ASSUME(gMovesInfo[MOVE_NATURE_POWER].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_NATURE_POWER) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -334,7 +334,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Hidden Power always transforms into Breakneck Bli PARAMETRIZE { iv = 21; } PARAMETRIZE { iv = 31; } GIVEN { - ASSUME(gMovesInfo[MOVE_HIDDEN_POWER].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_HIDDEN_POWER) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); AttackIV(iv); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -354,7 +354,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Weather Ball transforms into different Z-Moves ba PARAMETRIZE { weatherMove = MOVE_SANDSTORM; zMove = gTypesInfo[TYPE_ROCK].zMove; } PARAMETRIZE { weatherMove = MOVE_HAIL; zMove = gTypesInfo[TYPE_ICE].zMove; } GIVEN { - ASSUME(gMovesInfo[MOVE_WEATHER_BALL].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_WEATHER_BALL) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -370,7 +370,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Weather Ball transforms into different Z-Moves ba SINGLE_BATTLE_TEST("(Z-MOVE) Z-Sleep Talk transforms a used non-status move into a Z-Move") { GIVEN { - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_SLEEP_TALK) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_ABSORB); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -385,7 +385,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Sleep Talk transforms a used non-status move into SINGLE_BATTLE_TEST("(Z-MOVE) Z-Sleep Talk turns Weather Ball into Breakneck Blitz even under rain") { GIVEN { - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_SLEEP_TALK) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); Status1(STATUS1_SLEEP); Moves(MOVE_SLEEP_TALK, MOVE_WEATHER_BALL); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -400,7 +400,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Sleep Talk turns Weather Ball into Breakneck Blit SINGLE_BATTLE_TEST("(Z-MOVE) Powder blocks Fire type Z-Moves and deals 25% of maximum HP to the user") { GIVEN { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_FIRIUM_Z); } OPPONENT(SPECIES_VIVILLON); } WHEN { @@ -417,8 +417,8 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Powder blocks Fire type Z-Moves and deals 25% of ma DOUBLE_BATTLE_TEST("(Z-MOVE) Powder blocks Fire type Z-Moves (from Z-Mirror Move)") { GIVEN { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_MIRROR_MOVE].type == TYPE_FLYING); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_MIRROR_MOVE) == TYPE_FLYING); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_FLYINIUM_Z); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -436,8 +436,8 @@ DOUBLE_BATTLE_TEST("(Z-MOVE) Powder blocks Fire type Z-Moves (from Z-Mirror Move SINGLE_BATTLE_TEST("(Z-MOVE) Powder blocks Fire type Z-Moves but not boosts granted") { GIVEN { - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].zMove.effect == Z_EFFECT_ATK_UP_1); + ASSUME(GetMoveType(MOVE_WILL_O_WISP) == TYPE_FIRE); + ASSUME(GetMoveZEffect(MOVE_WILL_O_WISP) == Z_EFFECT_ATK_UP_1); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_FIRIUM_Z); } OPPONENT(SPECIES_VIVILLON); } WHEN { @@ -455,7 +455,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Powder blocks Fire type Z-Moves but not boosts gran DOUBLE_BATTLE_TEST("(Z-MOVE) Instruct fails if the target last used a Z-Move") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -474,7 +474,7 @@ DOUBLE_BATTLE_TEST("(Z-MOVE) Instruct fails if the target last used a Z-Move") DOUBLE_BATTLE_TEST("(Z-MOVE) Dancer does not use a Z-Move if the battler has used a Z-Move the same turn") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_DANCER); Item(ITEM_NORMALIUM_Z); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -498,7 +498,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Light That Burns the Sky uses the battler's highest PARAMETRIZE { useSwordsDance = FALSE; } PARAMETRIZE { useSwordsDance = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_NECROZMA_DUSK_MANE) { Item(ITEM_ULTRANECROZIUM_Z); } OPPONENT(SPECIES_WOBBUFFET) { HP(1000); MaxHP(1000); }; // hits hard lol } WHEN { @@ -521,7 +521,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) 10,000,000 Volt Thunderbolt has an increased critic PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_6); - ASSUME(gMovesInfo[MOVE_10_000_000_VOLT_THUNDERBOLT].criticalHitStage == 2); + ASSUME(GetMoveCriticalHitStage(MOVE_10_000_000_VOLT_THUNDERBOLT) == 2); PLAYER(SPECIES_PIKACHU_PARTNER) { Item(ITEM_PIKASHUNIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -536,7 +536,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) 10,000,000 Volt Thunderbolt has an increased critic SINGLE_BATTLE_TEST("(Z-MOVE) Stoked Sparksurfer paralyzes the target") { GIVEN { - ASSUME(gMovesInfo[MOVE_STOKED_SPARKSURFER].additionalEffects[0].moveEffect == MOVE_EFFECT_PARALYSIS); + ASSUME(GetMoveAdditionalEffectById(MOVE_STOKED_SPARKSURFER, 0)->moveEffect == MOVE_EFFECT_PARALYSIS); PLAYER(SPECIES_RAICHU_ALOLA) { Item(ITEM_ALORAICHIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -551,7 +551,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Stoked Sparksurfer paralyzes the target") SINGLE_BATTLE_TEST("(Z-MOVE) Extreme Evoboost boosts all the user's stats by two stages") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXTREME_EVOBOOST].effect == EFFECT_EXTREME_EVOBOOST); + ASSUME(GetMoveEffect(MOVE_EXTREME_EVOBOOST) == EFFECT_EXTREME_EVOBOOST); PLAYER(SPECIES_EEVEE) { Item(ITEM_EEVIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -571,7 +571,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Extreme Evoboost boosts all the user's stats by two SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_GENESIS_SUPERNOVA].effect == EFFECT_HIT_SET_REMOVE_TERRAIN); + ASSUME(GetMoveEffect(MOVE_GENESIS_SUPERNOVA) == EFFECT_HIT_SET_REMOVE_TERRAIN); PLAYER(SPECIES_MEW) { Item(ITEM_MEWNIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -588,7 +588,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Genesis Supernova sets up psychic terrain") SINGLE_BATTLE_TEST("(Z-MOVE) Splintered Stormshards removes terrain") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPLINTERED_STORMSHARDS].effect == EFFECT_HIT_SET_REMOVE_TERRAIN); + ASSUME(GetMoveEffect(MOVE_SPLINTERED_STORMSHARDS) == EFFECT_HIT_SET_REMOVE_TERRAIN); PLAYER(SPECIES_LYCANROC_DUSK) { Item(ITEM_LYCANIUM_Z); } OPPONENT(SPECIES_TAPU_LELE) { Ability(ABILITY_PSYCHIC_SURGE); HP(1000); MaxHP(1000); } } WHEN { @@ -606,7 +606,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Splintered Stormshards removes terrain") SINGLE_BATTLE_TEST("(Z-MOVE) Clangorous Soulblaze boosts all the user's stats by one stage") { GIVEN { - ASSUME(gMovesInfo[MOVE_CLANGOROUS_SOULBLAZE].additionalEffects[0].moveEffect == MOVE_EFFECT_ALL_STATS_UP); + ASSUME(GetMoveAdditionalEffectById(MOVE_CLANGOROUS_SOULBLAZE, 0)->moveEffect == MOVE_EFFECT_ALL_STATS_UP); PLAYER(SPECIES_KOMMO_O) { Item(ITEM_KOMMONIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -626,7 +626,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Clangorous Soulblaze boosts all the user's stats by SINGLE_BATTLE_TEST("(Z-MOVE) Guardian of Alola deals 75\% of the target's current HP") { GIVEN { - ASSUME(gMovesInfo[MOVE_GUARDIAN_OF_ALOLA].effect == EFFECT_GUARDIAN_OF_ALOLA); + ASSUME(GetMoveEffect(MOVE_GUARDIAN_OF_ALOLA) == EFFECT_GUARDIAN_OF_ALOLA); PLAYER(SPECIES_TAPU_FINI) { Item(ITEM_TAPUNIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -662,7 +662,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Revelation Dance always transforms into Breakneck PARAMETRIZE { species = SPECIES_ORICORIO_POM_POM; } PARAMETRIZE { species = SPECIES_ORICORIO_SENSU; } GIVEN { - ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_REVELATION_DANCE) == TYPE_NORMAL); PLAYER(species) { Item(ITEM_NORMALIUM_Z); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/air_balloon.c b/test/battle/hold_effect/air_balloon.c index 293e1d80ca1f..302a0e63971d 100644 --- a/test/battle/hold_effect/air_balloon.c +++ b/test/battle/hold_effect/air_balloon.c @@ -4,9 +4,9 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_AIR_BALLOON].holdEffect == HOLD_EFFECT_AIR_BALLOON); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].type == TYPE_GROUND); - ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_GROUND); - ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_TACKLE) != TYPE_GROUND); + ASSUME(GetMoveEffect(MOVE_RECYCLE) == EFFECT_RECYCLE); } SINGLE_BATTLE_TEST("Air Balloon prevents the holder from taking damage from ground type moves") diff --git a/test/battle/hold_effect/attack_up.c b/test/battle/hold_effect/attack_up.c index d166d8ff2ca2..63203e588a6c 100644 --- a/test/battle/hold_effect/attack_up.c +++ b/test/battle/hold_effect/attack_up.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Liechi Berry raises the holder's Attack by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/berserk_gene.c b/test/battle/hold_effect/berserk_gene.c index 59f78c1a12f8..1ff601fc8358 100644 --- a/test/battle/hold_effect/berserk_gene.c +++ b/test/battle/hold_effect/berserk_gene.c @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of a single PARAMETRIZE { item = ITEM_NONE; } PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -37,7 +37,7 @@ DOUBLE_BATTLE_TEST("Berserk Gene sharply raises attack at the start of a double PARAMETRIZE { item = ITEM_NONE; } PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WYNAUT); PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); @@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Berserk Gene activates on switch in", s16 damage) PARAMETRIZE { item = ITEM_NONE; } PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WYNAUT); PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); @@ -91,7 +91,7 @@ SINGLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but s PARAMETRIZE { item = ITEM_NONE; } PARAMETRIZE { item = ITEM_BERSERK_GENE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_OWN_TEMPO); Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -122,7 +122,7 @@ DOUBLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but s PARAMETRIZE { item = ITEM_BERSERK_GENE; positionLeft = TRUE; } PARAMETRIZE { item = ITEM_BERSERK_GENE; positionLeft = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); if (positionLeft) { PLAYER(SPECIES_SLOWBRO) { Ability(ABILITY_OWN_TEMPO); Item(item); } PLAYER(SPECIES_WOBBUFFET); @@ -156,7 +156,7 @@ DOUBLE_BATTLE_TEST("Berserk Gene does not confuse a Pokemon with Own Tempo but s SINGLE_BATTLE_TEST("Berserk Gene does not confuse on Misty Terrain but still raises attack sharply") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_TAPU_FINI) { Ability(ABILITY_MISTY_SURGE); Item(ITEM_BERSERK_GENE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/blunder_policy.c b/test/battle/hold_effect/blunder_policy.c index 552ad2f6fbd5..e9215b3eb2f6 100644 --- a/test/battle/hold_effect/blunder_policy.c +++ b/test/battle/hold_effect/blunder_policy.c @@ -10,7 +10,7 @@ SINGLE_BATTLE_TEST("Blunder Policy raises the users speed by 2 stages if the use { PASSES_RANDOMLY(3, 10, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].accuracy == 70); + ASSUME(GetMoveAccuracy(MOVE_FOCUS_BLAST) == 70); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_BLUNDER_POLICY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -29,7 +29,7 @@ SINGLE_BATTLE_TEST("Blunder Policy will never trigger if the move fails due to a { PASSES_RANDOMLY(10, 10, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].accuracy == 70); + ASSUME(GetMoveAccuracy(MOVE_FOCUS_BLAST) == 70); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_BLUNDER_POLICY); } OPPONENT(SPECIES_GASTLY); } WHEN { @@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Blunder Policy will never trigger if the move fails due to P { PASSES_RANDOMLY(10, 10, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_FOCUS_BLAST].accuracy == 70); + ASSUME(GetMoveAccuracy(MOVE_FOCUS_BLAST) == 70); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_BLUNDER_POLICY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/booster_energy.c b/test/battle/hold_effect/booster_energy.c index 072eb8df60d0..f6f44a272cd8 100644 --- a/test/battle/hold_effect/booster_energy.c +++ b/test/battle/hold_effect/booster_energy.c @@ -143,7 +143,7 @@ SINGLE_BATTLE_TEST("Booster Energy increases special attack by 30% if it is the PARAMETRIZE { species = SPECIES_IRON_MOTH; ability = ABILITY_QUARK_DRIVE; item = ITEM_BOOSTER_ENERGY; } GIVEN { - ASSUME(gMovesInfo[MOVE_ROUND].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); PLAYER(species) { Attack(100); Defense(100); Speed(100); SpAttack(110); SpDefense(100); Ability(ability); Item(item); } OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }; } WHEN { @@ -169,7 +169,7 @@ SINGLE_BATTLE_TEST("Booster Energy increases special defense by 30% if it is the PARAMETRIZE { species = SPECIES_IRON_MOTH; ability = ABILITY_QUARK_DRIVE; item = ITEM_BOOSTER_ENERGY; } GIVEN { - ASSUME(gMovesInfo[MOVE_ROUND].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_ROUND) == DAMAGE_CATEGORY_SPECIAL); PLAYER(species) { Attack(100); Defense(100); Speed(100); SpAttack(100); SpDefense(110); Ability(ability); Item(item); } OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }; } WHEN { diff --git a/test/battle/hold_effect/clear_amulet.c b/test/battle/hold_effect/clear_amulet.c index d0666ff3a91a..cc143c51e1c2 100644 --- a/test/battle/hold_effect/clear_amulet.c +++ b/test/battle/hold_effect/clear_amulet.c @@ -42,13 +42,13 @@ SINGLE_BATTLE_TEST("Clear Amulet prevents stat reducing effects") PARAMETRIZE { move = MOVE_SAND_ATTACK; } GIVEN { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); - ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_FAKE_TEARS].effect == EFFECT_SPECIAL_DEFENSE_DOWN_2); - ASSUME(gMovesInfo[MOVE_SCARY_FACE].effect == EFFECT_SPEED_DOWN_2); - ASSUME(gMovesInfo[MOVE_SWEET_SCENT].effect == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_LEER) == EFFECT_DEFENSE_DOWN); + ASSUME(GetMoveEffect(MOVE_CONFIDE) == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_FAKE_TEARS) == EFFECT_SPECIAL_DEFENSE_DOWN_2); + ASSUME(GetMoveEffect(MOVE_SCARY_FACE) == EFFECT_SPEED_DOWN_2); + ASSUME(GetMoveEffect(MOVE_SWEET_SCENT) == (B_UPDATED_MOVE_DATA >= GEN_6 ? EFFECT_EVASION_DOWN_2 : EFFECT_EVASION_DOWN)); + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_CLEAR_AMULET); }; } WHEN { diff --git a/test/battle/hold_effect/covert_cloak.c b/test/battle/hold_effect/covert_cloak.c index b55b1492daff..183033cb7139 100644 --- a/test/battle/hold_effect/covert_cloak.c +++ b/test/battle/hold_effect/covert_cloak.c @@ -127,7 +127,6 @@ SINGLE_BATTLE_TEST("Covert Cloak does not block self-targeting effects, primary DOUBLE_BATTLE_TEST("Covert Cloak does or does not block Sparkling Aria depending on number of targets hit") { u32 moveToUse; - KNOWN_FAILING; PARAMETRIZE { moveToUse = MOVE_FINAL_GAMBIT; } PARAMETRIZE { moveToUse = MOVE_TACKLE; } GIVEN { @@ -151,9 +150,33 @@ DOUBLE_BATTLE_TEST("Covert Cloak does or does not block Sparkling Aria depending } } +DOUBLE_BATTLE_TEST("Covert Cloak does block Sparkling Aria when only one mon is hit") +{ + u32 move; + PARAMETRIZE { move = MOVE_PROTECT; } + PARAMETRIZE { move = MOVE_FLY; } + + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, move, target: playerLeft); + MOVE(playerRight, move, target: opponentRight); + MOVE(playerLeft, MOVE_SPARKLING_ARIA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, playerLeft); + NONE_OF { + MESSAGE("The opposing Wobbuffet's burn was cured!"); + STATUS_ICON(opponentLeft, none: TRUE); + } + } +} + SINGLE_BATTLE_TEST("Covert Cloak blocks Sparkling Aria in singles") { - KNOWN_FAILING; GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_COVERT_CLOAK); Status1(STATUS1_BURN); } diff --git a/test/battle/hold_effect/critical_hit_up.c b/test/battle/hold_effect/critical_hit_up.c index 7bfe4ed74f22..ee4cb6a7d286 100644 --- a/test/battle/hold_effect/critical_hit_up.c +++ b/test/battle/hold_effect/critical_hit_up.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_LANSAT_BERRY].holdEffect == HOLD_EFFECT_CRITICAL_UP); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Lansat Berry raises the holder's critical-hit-ratio by two stages when HP drops to 1/4 or below") @@ -52,7 +52,7 @@ SINGLE_BATTLE_TEST("Lansat Berry raises the holder's critical-hit-ratio by two s { PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0); + ASSUME(GetMoveCriticalHitStage(MOVE_TACKLE) == 0); ASSUME(B_CRIT_CHANCE >= GEN_6); PLAYER(SPECIES_WOBBUFFET) { MaxHP(160); HP(80); Item(ITEM_LANSAT_BERRY); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/hold_effect/defense_up.c b/test/battle/hold_effect/defense_up.c index 87f41be7b304..1812b96d33fc 100644 --- a/test/battle/hold_effect/defense_up.c +++ b/test/battle/hold_effect/defense_up.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_GANLON_BERRY].holdEffect == HOLD_EFFECT_DEFENSE_UP); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Ganlon Berry raises the holder's Defense by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/eject_pack.c b/test/battle/hold_effect/eject_pack.c index 9272a23a7cd7..bba874e1b387 100644 --- a/test/battle/hold_effect/eject_pack.c +++ b/test/battle/hold_effect/eject_pack.c @@ -76,12 +76,48 @@ SINGLE_BATTLE_TEST("Eject Pack will miss timing to switch out user if Emergency } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_OVERHEAT, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); - MESSAGE("Wobbuffet is switched out with the Eject Pack!"); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet is switched out with the Eject Pack!"); + } ABILITY_POPUP(opponent, ABILITY_EMERGENCY_EXIT); } THEN { EXPECT(player->species == SPECIES_WOBBUFFET); - EXPECT(player->item == ITEM_NONE); EXPECT(opponent->species == SPECIES_WYNAUT); } } + +SINGLE_BATTLE_TEST("Eject Pack activates once intimidate mon switches in") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); } + } WHEN { + TURN { SWITCH(opponent, 1); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet is switched out with the Eject Pack!"); + } +} + +SINGLE_BATTLE_TEST("Eject Pack will not activate if Parting Shot user can switch out") +{ + ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK); + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_PARTING_SHOT); SEND_OUT(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PARTING_SHOT, opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet is switched out with the Eject Pack!"); + } + } +} diff --git a/test/battle/hold_effect/jaboca_berry.c b/test/battle/hold_effect/jaboca_berry.c index 373780be712f..756b5adf3c75 100644 --- a/test/battle/hold_effect/jaboca_berry.c +++ b/test/battle/hold_effect/jaboca_berry.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_JABOCA_BERRY].holdEffect == HOLD_EFFECT_JABOCA_BERRY); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Jaboca Berry causes the attacker to lose 1/8 of its max HP if a physical move was used") @@ -16,7 +16,7 @@ SINGLE_BATTLE_TEST("Jaboca Berry causes the attacker to lose 1/8 of its max HP i PARAMETRIZE { move = MOVE_TACKLE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_JABOCA_BERRY); } } WHEN { @@ -44,7 +44,7 @@ SINGLE_BATTLE_TEST("Jaboca Berry tirggers before Bug Bite can steal it") { KNOWN_FAILING; GIVEN { - ASSUME(gMovesInfo[MOVE_BUG_BITE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_BUG_BITE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_JABOCA_BERRY); } } WHEN { diff --git a/test/battle/hold_effect/kee_berry.c b/test/battle/hold_effect/kee_berry.c index 26cd2152a188..33de8ee004f7 100644 --- a/test/battle/hold_effect/kee_berry.c +++ b/test/battle/hold_effect/kee_berry.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_KEE_BERRY].holdEffect == HOLD_EFFECT_KEE_BERRY); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Kee Berry raises the holder's Defense by one stage when hit by a physical move") @@ -15,7 +15,7 @@ SINGLE_BATTLE_TEST("Kee Berry raises the holder's Defense by one stage when hit PARAMETRIZE { move = MOVE_TACKLE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_KEE_BERRY); } } WHEN { diff --git a/test/battle/hold_effect/life_orb.c b/test/battle/hold_effect/life_orb.c new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/test/battle/hold_effect/maranga_berry.c b/test/battle/hold_effect/maranga_berry.c index 77cdaddf42f5..eeb1aacf94f8 100644 --- a/test/battle/hold_effect/maranga_berry.c +++ b/test/battle/hold_effect/maranga_berry.c @@ -12,8 +12,8 @@ SINGLE_BATTLE_TEST("Maranga Berry raises the holder's Sp. Def by one stage when PARAMETRIZE { move = MOVE_TACKLE; } PARAMETRIZE { move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_MARANGA_BERRY); } } WHEN { @@ -40,7 +40,7 @@ SINGLE_BATTLE_TEST("Maranga Berry raises the holder's Sp. Def by one stage when SINGLE_BATTLE_TEST("Maranga Berry raises the holder's Sp. Def by two stages with Ripen when hit by a special move") { GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_APPLIN) { Item(ITEM_MARANGA_BERRY); Ability(ABILITY_RIPEN); } } WHEN { diff --git a/test/battle/hold_effect/metronome.c b/test/battle/hold_effect/metronome.c index 21ad326cf1dd..f1d756b3a7b7 100644 --- a/test/battle/hold_effect/metronome.c +++ b/test/battle/hold_effect/metronome.c @@ -112,7 +112,7 @@ SINGLE_BATTLE_TEST("Metronome Item counts charging turn of moves for its attacki PARAMETRIZE {item = ITEM_NONE; } PARAMETRIZE {item = ITEM_METRONOME; } GIVEN { - ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); + ASSUME(GetMoveEffect(MOVE_SOLAR_BEAM) == EFFECT_SOLAR_BEAM); PLAYER(SPECIES_WOBBUFFET) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -134,7 +134,7 @@ SINGLE_BATTLE_TEST("Metronome Item doesn't increase damage per hit of multi-hit { s16 damage[3]; GIVEN { - ASSUME(gMovesInfo[MOVE_FURY_ATTACK].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_FURY_ATTACK) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_METRONOME); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/micle_berry.c b/test/battle/hold_effect/micle_berry.c index f196c67c967c..818eae09a664 100644 --- a/test/battle/hold_effect/micle_berry.c +++ b/test/battle/hold_effect/micle_berry.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_MICLE_BERRY].holdEffect == HOLD_EFFECT_MICLE_BERRY); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Micle Berry raises the holder's accuracy by 1.2 when HP drops to 1/4 or below") @@ -52,7 +52,7 @@ SINGLE_BATTLE_TEST("Micle Berry raises the holder's accuracy by 1.2") { PASSES_RANDOMLY(24, 25, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_SUBMISSION].accuracy == 80); + ASSUME(GetMoveAccuracy(MOVE_SUBMISSION) == 80); PLAYER(SPECIES_WOBBUFFET) { MaxHP(160); HP(80); Item(ITEM_MICLE_BERRY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -68,7 +68,7 @@ SINGLE_BATTLE_TEST("Micle Berry raises the holder's accuracy by 1.2") SINGLE_BATTLE_TEST("Micle Berry increases the accuracy of the next used move across turns") { GIVEN { - ASSUME(gMovesInfo[MOVE_ROCK_SLIDE].accuracy == 90); + ASSUME(GetMoveAccuracy(MOVE_ROCK_SLIDE) == 90); PASSES_RANDOMLY(100, 100, RNG_ACCURACY); PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(26); Item(ITEM_MICLE_BERRY); } OPPONENT(SPECIES_WOBBUFFET); @@ -85,7 +85,7 @@ SINGLE_BATTLE_TEST("Micle Berry increases the accuracy of the next used move acr SINGLE_BATTLE_TEST("Micle Berry increases the accuracy of the next used move the same turn the berry was triggered") { GIVEN { - ASSUME(gMovesInfo[MOVE_ROCK_SLIDE].accuracy == 90); + ASSUME(GetMoveAccuracy(MOVE_ROCK_SLIDE) == 90); PASSES_RANDOMLY(100, 100, RNG_ACCURACY); PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(26); Item(ITEM_MICLE_BERRY); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/hold_effect/mirror_herb.c b/test/battle/hold_effect/mirror_herb.c index 88a7467334d2..68294bee4312 100644 --- a/test/battle/hold_effect/mirror_herb.c +++ b/test/battle/hold_effect/mirror_herb.c @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Mirror Herb copies all of foe's positive stat changes in a t PARAMETRIZE { item = ITEM_NONE; } PARAMETRIZE { item = ITEM_MIRROR_HERB; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } OPPONENT(SPECIES_WOBBUFFET) { Speed(5); Item(item); } } WHEN { diff --git a/test/battle/hold_effect/ogerpon_mask.c b/test/battle/hold_effect/ogerpon_mask.c index 209b854d6639..919151684a54 100644 --- a/test/battle/hold_effect/ogerpon_mask.c +++ b/test/battle/hold_effect/ogerpon_mask.c @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("Ogerpon Masks increase the base power of moves by 20%", s16 PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE; item = ITEM_HEARTHFLAME_MASK; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].power > 0); + ASSUME(GetMovePower(MOVE_TACKLE) > 0); PLAYER(species) { Item(item); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/protective_pads.c b/test/battle/hold_effect/protective_pads.c index 95de944b814a..843d2fa003a1 100644 --- a/test/battle/hold_effect/protective_pads.c +++ b/test/battle/hold_effect/protective_pads.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_PROTECTIVE_PADS].holdEffect == HOLD_EFFECT_PROTECTIVE_PADS); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact == TRUE); + ASSUME(MoveMakesContact(MOVE_TACKLE) == TRUE); } SINGLE_BATTLE_TEST("Protective Pads protected moves still make direct contact", s16 damage) diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index aa312797b284..7b14d8748de9 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -383,7 +383,7 @@ SINGLE_BATTLE_TEST("Red Card does not activate if attacker's Sheer Force applied SINGLE_BATTLE_TEST("Red Card is consumed after dragged out replacement has its Speed lowered by Sticky Web") { GIVEN { - ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); + ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT) { Moves(MOVE_TACKLE); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } diff --git a/test/battle/hold_effect/restore_hp.c b/test/battle/hold_effect/restore_hp.c index 47f409ff84a7..ef96ead7e4b1 100644 --- a/test/battle/hold_effect/restore_hp.c +++ b/test/battle/hold_effect/restore_hp.c @@ -37,7 +37,7 @@ DOUBLE_BATTLE_TEST("Restore HP Item effects do not miss timing after a recoil mo PARAMETRIZE { item = ITEM_SITRUS_BERRY; } GIVEN { - ASSUME(gMovesInfo[MOVE_TAKE_DOWN].recoil == 25); + ASSUME(GetMoveRecoil(MOVE_TAKE_DOWN) == 25); ASSUME(gItemsInfo[ITEM_ORAN_BERRY].holdEffect == HOLD_EFFECT_RESTORE_HP); ASSUME(gItemsInfo[ITEM_BERRY_JUICE].holdEffect == HOLD_EFFECT_RESTORE_HP); ASSUME(gItemsInfo[ITEM_SITRUS_BERRY].holdEffect == HOLD_EFFECT_RESTORE_PCT_HP); diff --git a/test/battle/hold_effect/restore_stats.c b/test/battle/hold_effect/restore_stats.c index c0f888469cab..192ad2f65e0d 100644 --- a/test/battle/hold_effect/restore_stats.c +++ b/test/battle/hold_effect/restore_stats.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("White Herb restores stats when they're lowered") { GIVEN { - ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN); + ASSUME(GetMoveEffect(MOVE_LEER) == EFFECT_DEFENSE_DOWN); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -103,7 +103,7 @@ SINGLE_BATTLE_TEST("White Herb restores stats after all hits of a multi hit move PARAMETRIZE { species = SPECIES_DUGTRIO_ALOLA; ability = ABILITY_TANGLING_HAIR; } GIVEN { - ASSUME(gMovesInfo[MOVE_DUAL_WINGBEAT].strikeCount == 2); + ASSUME(GetMoveStrikeCount(MOVE_DUAL_WINGBEAT) == 2); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_WHITE_HERB); } OPPONENT(species) { Ability(ability); } } WHEN { @@ -133,7 +133,7 @@ SINGLE_BATTLE_TEST("White Herb wont have time to activate if it is knocked off o GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_THIEF, MOVE_EFFECT_STEAL_ITEM) == TRUE); - ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF); + ASSUME(GetMoveEffect(MOVE_KNOCK_OFF) == EFFECT_KNOCK_OFF); PLAYER(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); Item(ITEM_WHITE_HERB); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/hold_effect/room_service.c b/test/battle/hold_effect/room_service.c index 04b6450e0510..e775ca496cf5 100644 --- a/test/battle/hold_effect/room_service.c +++ b/test/battle/hold_effect/room_service.c @@ -9,9 +9,9 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Room Serive decreases the holder's seep by one stage") { GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_TRICK_ROOM].effect == EFFECT_TRICK_ROOM); - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_TRICK_ROOM) == EFFECT_TRICK_ROOM); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); Item(ITEM_ROOM_SERVICE); } OPPONENT(SPECIES_WYNAUT) { HP(1); } diff --git a/test/battle/hold_effect/rowap_berry.c b/test/battle/hold_effect/rowap_berry.c index 5dc85492c31a..2ad8b9d3009e 100644 --- a/test/battle/hold_effect/rowap_berry.c +++ b/test/battle/hold_effect/rowap_berry.c @@ -15,8 +15,8 @@ SINGLE_BATTLE_TEST("Rowap Berry causes the attacker to lose 1/8 of its max HP if PARAMETRIZE { move = MOVE_TACKLE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_ROWAP_BERRY); } } WHEN { @@ -43,7 +43,7 @@ SINGLE_BATTLE_TEST("Rowap Berry causes the attacker to lose 1/8 of its max HP if SINGLE_BATTLE_TEST("Rowap Berry is not triggered by a physical move") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_ROWAP_BERRY); } } WHEN { diff --git a/test/battle/hold_effect/safety_goggles.c b/test/battle/hold_effect/safety_goggles.c index ec66ad8bcddb..e2d329bcf603 100644 --- a/test/battle/hold_effect/safety_goggles.c +++ b/test/battle/hold_effect/safety_goggles.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Safety Goggles block powder and spore moves") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove); + ASSUME(IsPowderMove(MOVE_STUN_SPORE)); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ABRA) { Item(ITEM_SAFETY_GOGGLES); } } WHEN { diff --git a/test/battle/hold_effect/seeds.c b/test/battle/hold_effect/seeds.c new file mode 100644 index 000000000000..10a415bd6379 --- /dev/null +++ b/test/battle/hold_effect/seeds.c @@ -0,0 +1,62 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Electric Seed raises the holder's Defense on Electric Terrain") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_ELECTRIC_SEED); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Using Electric Seed, the Defense of Wobbuffet rose!"); + } +} + +SINGLE_BATTLE_TEST("Grassy Seed raises the holder's Defense on Grassy Terrain") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_GRASSY_TERRAIN); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_GRASSY_SEED); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GRASSY_TERRAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Using Grassy Seed, the Defense of Wobbuffet rose!"); + } +} + +SINGLE_BATTLE_TEST("Misty Seed raises the holder's Sp. Defense on Misty Terrain") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_MISTY_TERRAIN); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MISTY_SEED); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MISTY_TERRAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Using Misty Seed, the Sp. Def of Wobbuffet rose!"); + } +} + +SINGLE_BATTLE_TEST("Psychic Seed raises the holder's Sp. Defense on Psychic Terrain") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); + ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PSYCHIC_SEED); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Using Psychic Seed, the Sp. Def of Wobbuffet rose!"); + } +} diff --git a/test/battle/hold_effect/shell_bell.c b/test/battle/hold_effect/shell_bell.c new file mode 100644 index 000000000000..32a105e46f7d --- /dev/null +++ b/test/battle/hold_effect/shell_bell.c @@ -0,0 +1,202 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gItemsInfo[ITEM_SHELL_BELL].holdEffect == HOLD_EFFECT_SHELL_BELL); +} + +#define HITS 5 +SINGLE_BATTLE_TEST("Shell Bell recovers 1/8 of HP from after the last hit from all hits of a multi hit move") +{ + s16 multiHitDamage[HITS]; + s16 totalDamage = 0; + s16 shellBellRecovery = 0; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BULLET_SEED); } + } SCENE { + for (u32 i = 0; i < HITS; i++) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BULLET_SEED, player); + HP_BAR(opponent, captureDamage: &multiHitDamage[i]); + totalDamage += multiHitDamage[i]; + } + HP_BAR(player, captureDamage: &shellBellRecovery); + } THEN { + EXPECT_EQ(totalDamage / 8, -1 * shellBellRecovery); + } +} +#undef HITS + +SINGLE_BATTLE_TEST("Shell Bell recovers no HP if the move did no damage") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WOBBUFFET) { HP(1); }; + } WHEN { + TURN { MOVE(player, MOVE_FALSE_SWIPE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FALSE_SWIPE, player); + HP_BAR(opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player); + } + } +} + +SINGLE_BATTLE_TEST("Shell Bell activates if it hits a Substitute") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + // HP_BAR(opponent); // When you hit a sub the hp bar check doesn't work. Not sure if this is a bug + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Shell Bell activates after Absorb") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ABSORB); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + HP_BAR(opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Shell Bell activates after Rough Skin") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_GIBLE) { Ability(ABILITY_ROUGH_SKIN); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent); + HP_BAR(player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player); + } +} + +SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is on the field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_FUTURE_SIGHT); } + TURN {} + TURN {} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("The opposing Wynaut took the Future Sight attack!"); + HP_BAR(opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player); + } + } +} + +SINGLE_BATTLE_TEST("Shell Bell restores 1/8 HP of damage dealt") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); } + OPPONENT(SPECIES_WOBBUFFET) { Level(16); }; + } WHEN { + TURN { MOVE(player, MOVE_SEISMIC_TOSS); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SEISMIC_TOSS, player); + HP_BAR(opponent); + HP_BAR(player, damage: -2); + } +} + +SINGLE_BATTLE_TEST("Shell Bell doesn't restore HP for damage dealt by a foreseen move") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); + PLAYER(SPECIES_WOBBUFFET) { Level(16); Item(ITEM_SHELL_BELL); HP(10); } + OPPONENT(SPECIES_WOBBUFFET) { Level(16); }; + } WHEN { + TURN { MOVE(player, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("The opposing Wobbuffet took the Future Sight attack!"); + HP_BAR(opponent); + NONE_OF { + HP_BAR(player); + } + } +} + +SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is not on the field") +{ + GIVEN { + PLAYER(SPECIES_WYNAUT); + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_FUTURE_SIGHT); } + TURN { SWITCH(player, 1); } + TURN {} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("The opposing Wynaut took the Future Sight attack!"); + HP_BAR(opponent); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player); + } + } +} + + +SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is on the field") +{ + s16 damage = 0; + s16 healed = 0; + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_FUTURE_SIGHT); } + TURN {} + TURN {} + TURN { MOVE(player, MOVE_DRAGON_RAGE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("The opposing Wynaut took the Future Sight attack!"); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_RAGE, player); + HP_BAR(opponent, captureDamage: &damage); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + HP_BAR(player, captureDamage: &healed); + } THEN { + EXPECT_MUL_EQ(damage, Q_4_12(-0.25), healed); + } +} + +TO_DO_BATTLE_TEST("If a Pokémon steals a Shell Bell with Thief or Covet, it will recover HP for the use of that move that stole the Shell Bell") +TO_DO_BATTLE_TEST("If a Pokémon steals a Shell Bell with Magician, it will recover HP for the use of that move that stole the Shell Bell") diff --git a/test/battle/hold_effect/special_attack_up.c b/test/battle/hold_effect/special_attack_up.c index 9ae73340bf86..0199bab83cc1 100644 --- a/test/battle/hold_effect/special_attack_up.c +++ b/test/battle/hold_effect/special_attack_up.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_PETAYA_BERRY].holdEffect == HOLD_EFFECT_SP_ATTACK_UP); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Petaya Berry raises the holder's Sp. Atk by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/special_defense_up.c b/test/battle/hold_effect/special_defense_up.c index c96f1680b269..e075d05c49bd 100644 --- a/test/battle/hold_effect/special_defense_up.c +++ b/test/battle/hold_effect/special_defense_up.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_APICOT_BERRY].holdEffect == HOLD_EFFECT_SP_DEFENSE_UP); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Apicot Berry raises the holder's Sp. Def by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/speed_up.c b/test/battle/hold_effect/speed_up.c index a0e727fd4472..f31ee7e92409 100644 --- a/test/battle/hold_effect/speed_up.c +++ b/test/battle/hold_effect/speed_up.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_SALAC_BERRY].holdEffect == HOLD_EFFECT_SPEED_UP); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); } SINGLE_BATTLE_TEST("Salac Berry raises the holder's Speed by one stage when HP drops to 1/4 or below") diff --git a/test/battle/hold_effect/utility_umbrella.c b/test/battle/hold_effect/utility_umbrella.c index f04a77378990..67a3be4c7a15 100644 --- a/test/battle/hold_effect/utility_umbrella.c +++ b/test/battle/hold_effect/utility_umbrella.c @@ -5,8 +5,8 @@ ASSUMPTIONS { ASSUME(gItemsInfo[ITEM_UTILITY_UMBRELLA].holdEffect == HOLD_EFFECT_UTILITY_UMBRELLA); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); } SINGLE_BATTLE_TEST("Utility Umbrella blocks Sun damage modifiers", s16 damage) diff --git a/test/battle/item_effect/escape.c b/test/battle/item_effect/escape.c index bffa6e429261..dd27c425c244 100644 --- a/test/battle/item_effect/escape.c +++ b/test/battle/item_effect/escape.c @@ -21,7 +21,7 @@ WILD_BATTLE_TEST("Poke Toy lets the player escape from a wild battle") WILD_BATTLE_TEST("Poke Toy lets the player escape from a wild battle even if a move forbid them to") { GIVEN { - ASSUME(gMovesInfo[MOVE_MEAN_LOOK].effect == EFFECT_MEAN_LOOK); + ASSUME(GetMoveEffect(MOVE_MEAN_LOOK) == EFFECT_MEAN_LOOK); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/item_effect/increase_stat.c b/test/battle/item_effect/increase_stat.c index 9b3ced5759c6..2b9486e3a61a 100644 --- a/test/battle/item_effect/increase_stat.c +++ b/test/battle/item_effect/increase_stat.c @@ -8,7 +8,7 @@ SINGLE_BATTLE_TEST("X Attack sharply raises battler's Attack stat", s16 damage) PARAMETRIZE { useItem = TRUE; } GIVEN { ASSUME(gItemsInfo[ITEM_X_ATTACK].battleUsage == EFFECT_ITEM_INCREASE_STAT); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("X Defense sharply raises battler's Defense stat", s16 damage PARAMETRIZE { useItem = TRUE; } GIVEN { ASSUME(gItemsInfo[ITEM_X_DEFENSE].battleUsage == EFFECT_ITEM_INCREASE_STAT); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("X Sp. Atk sharply raises battler's Sp. Attack stat", s16 dam PARAMETRIZE { useItem = TRUE; } GIVEN { ASSUME(gItemsInfo[ITEM_X_SP_ATK].battleUsage == EFFECT_ITEM_INCREASE_STAT); - ASSUME(gMovesInfo[MOVE_DISARMING_VOICE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_DISARMING_VOICE) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -80,7 +80,7 @@ SINGLE_BATTLE_TEST("X Sp. Def sharply raises battler's Sp. Defense stat", s16 da PARAMETRIZE { useItem = TRUE; } GIVEN { ASSUME(gItemsInfo[ITEM_X_SP_DEF].battleUsage == EFFECT_ITEM_INCREASE_STAT); - ASSUME(gMovesInfo[MOVE_DISARMING_VOICE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_DISARMING_VOICE) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -134,11 +134,11 @@ SINGLE_BATTLE_TEST("X Speed sharply raises battler's Speed stat", s16 damage) SINGLE_BATTLE_TEST("X Accuracy sharply raises battler's Accuracy stat") { - ASSUME(gMovesInfo[MOVE_SING].accuracy == 55); + ASSUME(GetMoveAccuracy(MOVE_SING) == 55); if (B_X_ITEMS_BUFF >= GEN_7) - PASSES_RANDOMLY(gMovesInfo[MOVE_SING].accuracy * 5 / 3, 100, RNG_ACCURACY); + PASSES_RANDOMLY(GetMoveAccuracy(MOVE_SING) * 5 / 3, 100, RNG_ACCURACY); else - PASSES_RANDOMLY(gMovesInfo[MOVE_SING].accuracy * 4 / 3, 100, RNG_ACCURACY); + PASSES_RANDOMLY(GetMoveAccuracy(MOVE_SING) * 4 / 3, 100, RNG_ACCURACY); GIVEN { ASSUME(gItemsInfo[ITEM_X_ACCURACY].battleUsage == EFFECT_ITEM_INCREASE_STAT); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move.c b/test/battle/move.c index 9ee37391ec72..ff397575b5e2 100644 --- a/test/battle/move.c +++ b/test/battle/move.c @@ -9,8 +9,8 @@ SINGLE_BATTLE_TEST("Accuracy controls the proportion of misses") PARAMETRIZE { move = MOVE_HYDRO_PUMP; } PARAMETRIZE { move = MOVE_RAZOR_LEAF; } PARAMETRIZE { move = MOVE_SCRATCH; } - ASSUME(0 < gMovesInfo[move].accuracy && gMovesInfo[move].accuracy <= 100); - PASSES_RANDOMLY(gMovesInfo[move].accuracy, 100, RNG_ACCURACY); + ASSUME(0 < GetMoveAccuracy(move) && GetMoveAccuracy(move) <= 100); + PASSES_RANDOMLY(GetMoveAccuracy(move), 100, RNG_ACCURACY); GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -42,7 +42,7 @@ SINGLE_BATTLE_TEST("AdditionalEffect.chance controls the proportion of secondary SINGLE_BATTLE_TEST("Turn order is determined by priority") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority > gMovesInfo[MOVE_TACKLE].priority); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) > GetMovePriority(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -86,10 +86,10 @@ DOUBLE_BATTLE_TEST("Turn order is determined randomly if priority and Speed tie PASSES_RANDOMLY(24, 24, RNG_SPEED_TIE); GIVEN { - ASSUME(gMovesInfo[MOVE_ENDEAVOR].effect == EFFECT_ENDEAVOR); - ASSUME(gMovesInfo[MOVE_LIFE_DEW].effect == EFFECT_JUNGLE_HEALING); - ASSUME(gMovesInfo[MOVE_CRUSH_GRIP].effect == EFFECT_POWER_BASED_ON_TARGET_HP); - ASSUME(gMovesInfo[MOVE_SUPER_FANG].effect == EFFECT_SUPER_FANG); + ASSUME(GetMoveEffect(MOVE_ENDEAVOR) == EFFECT_ENDEAVOR); + ASSUME(GetMoveEffect(MOVE_LIFE_DEW) == EFFECT_JUNGLE_HEALING); + ASSUME(GetMoveEffect(MOVE_CRUSH_GRIP) == EFFECT_POWER_BASED_ON_TARGET_HP); + ASSUME(GetMoveEffect(MOVE_SUPER_FANG) == EFFECT_SUPER_FANG); PLAYER(SPECIES_WOBBUFFET) { MaxHP(480); HP(360); Defense(100); Speed(1); } PLAYER(SPECIES_WYNAUT) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Attack(100); Speed(1); } @@ -153,7 +153,7 @@ SINGLE_BATTLE_TEST("Slash's critical hits occur at a 1/8 rate") PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); + ASSUME(GetMoveCriticalHitStage(MOVE_SLASH) == 1); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -188,7 +188,7 @@ SINGLE_BATTLE_TEST("Critical hits do not ignore positive stat stages", s16 damag PARAMETRIZE { move = MOVE_HOWL; } PARAMETRIZE { move = MOVE_TAIL_WHIP; } GIVEN { - ASSUME(gMovesInfo[MOVE_SCRATCH].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -209,7 +209,7 @@ SINGLE_BATTLE_TEST("Critical hits ignore negative stat stages", s16 damage) PARAMETRIZE { move = MOVE_HARDEN; } PARAMETRIZE { move = MOVE_GROWL; } GIVEN { - ASSUME(gMovesInfo[MOVE_SCRATCH].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SCRATCH) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -255,7 +255,7 @@ DOUBLE_BATTLE_TEST("Moves do not fail if an alive partner is the target") DOUBLE_BATTLE_TEST("Moves fail if they target into a pokemon that was fainted by the previous move") { GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { HP(1); } OPPONENT(SPECIES_WOBBUFFET) { HP(1); } @@ -278,7 +278,7 @@ DOUBLE_BATTLE_TEST("Moves fail if they target into a pokemon that was fainted by DOUBLE_BATTLE_TEST("Moves that target the field are not going to fail if one mon fainted by the previous move") { GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { HP(1); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/absorb.c b/test/battle/move_effect/absorb.c index 6ed1403fee86..456c888cd483 100644 --- a/test/battle/move_effect/absorb.c +++ b/test/battle/move_effect/absorb.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ABSORB].effect == EFFECT_ABSORB); + ASSUME(GetMoveEffect(MOVE_ABSORB) == EFFECT_ABSORB); } SINGLE_BATTLE_TEST("Absorb recovers 50% of the damage dealt") @@ -24,25 +24,6 @@ SINGLE_BATTLE_TEST("Absorb recovers 50% of the damage dealt") } } -SINGLE_BATTLE_TEST("Absorb deals 50% of the damage dealt to user agains Liquid Ooze") -{ - s16 damage; - s16 healed; - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } - } WHEN { - TURN { MOVE(player, MOVE_ABSORB); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); - HP_BAR(opponent, captureDamage: &damage); - HP_BAR(player, captureDamage: &healed); - MESSAGE("Wobbuffet sucked up the liquid ooze!"); - } THEN { - EXPECT_MUL_EQ(damage, Q_4_12(0.5), healed); - } -} - SINGLE_BATTLE_TEST("Absorb fails if Heal Block applies") { GIVEN { @@ -69,7 +50,7 @@ DOUBLE_BATTLE_TEST("Matcha Gatcha recovers 50% of the damage dealt from both tar s16 healedRight; GIVEN { - ASSUME(gMovesInfo[MOVE_MATCHA_GOTCHA].effect == EFFECT_ABSORB); + ASSUME(GetMoveEffect(MOVE_MATCHA_GOTCHA) == EFFECT_ABSORB); PLAYER(SPECIES_PIKACHU) { HP(1); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_STARYU); @@ -88,25 +69,6 @@ DOUBLE_BATTLE_TEST("Matcha Gatcha recovers 50% of the damage dealt from both tar } } -DOUBLE_BATTLE_TEST("Matcha Gatcha will faint the pokemon if Liquid Ooze drain deals enough damage") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_MATCHA_GOTCHA].effect == EFFECT_ABSORB); - PLAYER(SPECIES_WOBBUFFET) { HP(1); } - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(playerLeft, MOVE_MATCHA_GOTCHA); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_MATCHA_GOTCHA, playerLeft); - HP_BAR(opponentLeft); - HP_BAR(playerLeft); - MESSAGE("Wobbuffet sucked up the liquid ooze!"); - MESSAGE("Wobbuffet fainted!"); - } -} - SINGLE_BATTLE_TEST("Draining Kiss recovers 75% of the damage dealt") { s16 damage; diff --git a/test/battle/move_effect/accuracy_down.c b/test/battle/move_effect/accuracy_down.c index f174a7f9463e..c11001928fa5 100644 --- a/test/battle/move_effect/accuracy_down.c +++ b/test/battle/move_effect/accuracy_down.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); } SINGLE_BATTLE_TEST("Sand Attack lowers Accuracy by 1 stage") { - PASSES_RANDOMLY(gMovesInfo[MOVE_SCRATCH].accuracy * 3 / 4, 100, RNG_ACCURACY); + PASSES_RANDOMLY(GetMoveAccuracy(MOVE_SCRATCH) * 3 / 4, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_SCRATCH].accuracy == 100); + ASSUME(GetMoveAccuracy(MOVE_SCRATCH) == 100); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/acrobatics.c b/test/battle/move_effect/acrobatics.c index 70953d0958d9..809b77f9487c 100644 --- a/test/battle/move_effect/acrobatics.c +++ b/test/battle/move_effect/acrobatics.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ACROBATICS].effect == EFFECT_ACROBATICS); - ASSUME(gMovesInfo[MOVE_ACROBATICS].type == TYPE_FLYING); + ASSUME(GetMoveEffect(MOVE_ACROBATICS) == EFFECT_ACROBATICS); + ASSUME(GetMoveType(MOVE_ACROBATICS) == TYPE_FLYING); } SINGLE_BATTLE_TEST("Acrobatics doubles in power if the user has no held item", s16 damage) diff --git a/test/battle/move_effect/after_you.c b/test/battle/move_effect/after_you.c index c1202f0f9cdd..42eb0f3ff9a1 100644 --- a/test/battle/move_effect/after_you.c +++ b/test/battle/move_effect/after_you.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_AFTER_YOU].effect == EFFECT_AFTER_YOU); + ASSUME(GetMoveEffect(MOVE_AFTER_YOU) == EFFECT_AFTER_YOU); } DOUBLE_BATTLE_TEST("After You makes the target move after user") @@ -112,7 +112,7 @@ DOUBLE_BATTLE_TEST("After You doesn't fail if the turn order remains the same af DOUBLE_BATTLE_TEST("After You ignores the effects of Quash") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUASH].effect == EFFECT_QUASH); + ASSUME(GetMoveEffect(MOVE_QUASH) == EFFECT_QUASH); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } PLAYER(SPECIES_WYNAUT) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } diff --git a/test/battle/move_effect/ally_switch.c b/test/battle/move_effect/ally_switch.c index 3846e03688e0..7222f3458772 100644 --- a/test/battle/move_effect/ally_switch.c +++ b/test/battle/move_effect/ally_switch.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ALLY_SWITCH].effect == EFFECT_ALLY_SWITCH); + ASSUME(GetMoveEffect(MOVE_ALLY_SWITCH) == EFFECT_ALLY_SWITCH); } SINGLE_BATTLE_TEST("Ally Switch fails in a single battle") @@ -41,8 +41,8 @@ DOUBLE_BATTLE_TEST("Ally Switch fails if there is no partner") DOUBLE_BATTLE_TEST("Ally Switch changes the position of battlers") { GIVEN { - ASSUME(gMovesInfo[MOVE_SCREECH].effect == EFFECT_DEFENSE_DOWN_2); - ASSUME(gMovesInfo[MOVE_SCREECH].target == MOVE_TARGET_SELECTED); + ASSUME(GetMoveEffect(MOVE_SCREECH) == EFFECT_DEFENSE_DOWN_2); + ASSUME(GetMoveTarget(MOVE_SCREECH) == MOVE_TARGET_SELECTED); PLAYER(SPECIES_WOBBUFFET) { Speed(5); } // Wobb is playerLeft, but it'll be Wynaut after Ally Switch PLAYER(SPECIES_WYNAUT) { Speed(4); } OPPONENT(SPECIES_KADABRA) { Speed(3); } @@ -72,7 +72,7 @@ DOUBLE_BATTLE_TEST("Ally Switch changes the position of battlers") DOUBLE_BATTLE_TEST("Ally Switch does not redirect the target of Snipe Shot") { GIVEN { - ASSUME(gMovesInfo[MOVE_SNIPE_SHOT].effect == EFFECT_SNIPE_SHOT); + ASSUME(GetMoveEffect(MOVE_SNIPE_SHOT) == EFFECT_SNIPE_SHOT); PLAYER(SPECIES_WOBBUFFET); // Wobb is playerLeft, but it'll be Wynaut after Ally Switch PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_KADABRA); @@ -207,7 +207,7 @@ DOUBLE_BATTLE_TEST("Ally switch swaps sky drop targets if being used by partner" { u8 visibility; GIVEN { - ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP); + ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP); PLAYER(SPECIES_FEAROW) { Speed(100); } PLAYER(SPECIES_XATU) { Speed(150); } OPPONENT(SPECIES_ARON) { Speed(25); Ability(ABILITY_STURDY); } @@ -244,7 +244,7 @@ DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is be { u8 visibility; GIVEN { - ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP); + ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP); PLAYER(SPECIES_ARON) { Speed(25); Ability(ABILITY_STURDY); } PLAYER(SPECIES_WYNAUT) { Speed(30); } OPPONENT(SPECIES_FEAROW) { Speed(100); } @@ -277,11 +277,13 @@ DOUBLE_BATTLE_TEST("Ally switch swaps opposing sky drop targets if partner is be } } +// Test passes in isolation but fails on CI +/* DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data") { KNOWN_FAILING; // Test passes in isolation but fails on CI GIVEN { - ASSUME(gMovesInfo[MOVE_ALLY_SWITCH].effect == EFFECT_ALLY_SWITCH); + ASSUME(GetMoveEffect(MOVE_ALLY_SWITCH) == EFFECT_ALLY_SWITCH); PLAYER(SPECIES_HOOPA); PLAYER(SPECIES_ZOROARK); PLAYER(SPECIES_MAMOSWINE); // the third member here is required for zoroark @@ -293,6 +295,7 @@ DOUBLE_BATTLE_TEST("Ally Switch swaps Illusion data") EXPECT(&gPlayerParty[2] == gBattleStruct->illusion[0].mon); } } +*/ // Triple Battles required to test //TO_DO_BATTLE_TEST("Ally Switch fails if the user is in the middle of the field in a Triple Battle"); diff --git a/test/battle/move_effect/aromatic_mist.c b/test/battle/move_effect/aromatic_mist.c index 516ed14f1694..130305cd99fe 100644 --- a/test/battle/move_effect/aromatic_mist.c +++ b/test/battle/move_effect/aromatic_mist.c @@ -1,5 +1,39 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Aromatic Mist raises Sp. Defense of a target ally by 1 stage"); -TO_DO_BATTLE_TEST("Aromatic Mist fails in Single Battles"); +DOUBLE_BATTLE_TEST("Aromatic Mist raises Sp. Defense of a target ally by 1 stage") +{ + GIVEN { + PLAYER(SPECIES_WEEZING_GALAR); + PLAYER(SPECIES_SYLVEON); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_AROMATIC_MIST); } + } SCENE { + MESSAGE("Weezing used Aromatic Mist!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight); + } THEN { + EXPECT_EQ(playerLeft->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(playerRight->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(opponentLeft->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponentRight->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + } +} + +SINGLE_BATTLE_TEST("Aromatic Mist fails in Single Battles") +{ + GIVEN { + PLAYER(SPECIES_WEEZING_GALAR); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_AROMATIC_MIST); } + } SCENE { + MESSAGE("Weezing used Aromatic Mist!"); + MESSAGE("But it failed!"); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE); + } +} diff --git a/test/battle/move_effect/assist.c b/test/battle/move_effect/assist.c index 0c9a0b612876..6036de8e8c9c 100644 --- a/test/battle/move_effect/assist.c +++ b/test/battle/move_effect/assist.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ASSIST].effect == EFFECT_ASSIST); + ASSUME(GetMoveEffect(MOVE_ASSIST) == EFFECT_ASSIST); } TO_DO_BATTLE_TEST("Assist randomly calls a move from any party member"); diff --git a/test/battle/move_effect/attack_accuracy_up.c b/test/battle/move_effect/attack_accuracy_up.c index 102f4d4d213b..25b09ab1c069 100644 --- a/test/battle/move_effect/attack_accuracy_up.c +++ b/test/battle/move_effect/attack_accuracy_up.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Hone Claws increases Attack and Accuracy by one stage each") { GIVEN { - ASSUME(gMovesInfo[MOVE_HONE_CLAWS].effect == EFFECT_ATTACK_ACCURACY_UP); + ASSUME(GetMoveEffect(MOVE_HONE_CLAWS) == EFFECT_ATTACK_ACCURACY_UP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/attack_down.c b/test/battle/move_effect/attack_down.c index e88ef43c26fb..eb562c0c6ac3 100644 --- a/test/battle/move_effect/attack_down.c +++ b/test/battle/move_effect/attack_down.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); } SINGLE_BATTLE_TEST("Growl lowers Attack by 1 stage", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Growl lowers Attack by 1 stage", s16 damage) PARAMETRIZE { lowerAttack = FALSE; } PARAMETRIZE { lowerAttack = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/attack_down_2.c b/test/battle/move_effect/attack_down_2.c index 6fefec5e45a0..896bbf947c1f 100644 --- a/test/battle/move_effect/attack_down_2.c +++ b/test/battle/move_effect/attack_down_2.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2); + ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); } SINGLE_BATTLE_TEST("Charm lowers Attack by 2 stages", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Charm lowers Attack by 2 stages", s16 damage) PARAMETRIZE { lowerAttack = FALSE; } PARAMETRIZE { lowerAttack = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/attack_spatk_up.c b/test/battle/move_effect/attack_spatk_up.c index b5aa2418a28c..671ed667a6e6 100644 --- a/test/battle/move_effect/attack_spatk_up.c +++ b/test/battle/move_effect/attack_spatk_up.c @@ -4,7 +4,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WORK_UP].effect == EFFECT_ATTACK_SPATK_UP); + ASSUME(GetMoveEffect(MOVE_WORK_UP) == EFFECT_ATTACK_SPATK_UP); } SINGLE_BATTLE_TEST("Work Up raises Attack and Sp. Attack by 1 stage each", s16 damage) @@ -16,8 +16,8 @@ SINGLE_BATTLE_TEST("Work Up raises Attack and Sp. Attack by 1 stage each", s16 d PARAMETRIZE { raiseStats = FALSE; move = MOVE_SWIFT; } PARAMETRIZE { raiseStats = TRUE; move = MOVE_SWIFT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/attack_up.c b/test/battle/move_effect/attack_up.c index da878fb60d49..1865c7f30e89 100644 --- a/test/battle/move_effect/attack_up.c +++ b/test/battle/move_effect/attack_up.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_MEDITATE].effect == EFFECT_ATTACK_UP); + ASSUME(GetMoveEffect(MOVE_MEDITATE) == EFFECT_ATTACK_UP); } SINGLE_BATTLE_TEST("Meditate raises Attack by 1 stage", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Meditate raises Attack by 1 stage", 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 { diff --git a/test/battle/move_effect/attack_up_2.c b/test/battle/move_effect/attack_up_2.c index 1f44efe9e3ff..fd247fad0106 100644 --- a/test/battle/move_effect/attack_up_2.c +++ b/test/battle/move_effect/attack_up_2.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); } SINGLE_BATTLE_TEST("Swords Dance raises Attack by 2 stages", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Swords Dance raises Attack by 2 stages", 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 { diff --git a/test/battle/move_effect/attack_up_user_ally.c b/test/battle/move_effect/attack_up_user_ally.c index 1d623c2bbd3c..8f9c4a338811 100644 --- a/test/battle/move_effect/attack_up_user_ally.c +++ b/test/battle/move_effect/attack_up_user_ally.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HOWL].effect == EFFECT_ATTACK_UP_USER_ALLY); + ASSUME(GetMoveEffect(MOVE_HOWL) == EFFECT_ATTACK_UP_USER_ALLY); } SINGLE_BATTLE_TEST("Howl raises user's Attack by 1 stage", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Howl raises user's Attack by 1 stage", 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 { @@ -37,7 +37,7 @@ DOUBLE_BATTLE_TEST("Howl raises user's and partner's Attack by 1 stage", s16 dam 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) { Speed(15); } PLAYER(SPECIES_WYNAUT) { Speed(10); } OPPONENT(SPECIES_WOBBUFFET) { Speed(13); } @@ -69,7 +69,7 @@ DOUBLE_BATTLE_TEST("Howl does not work on partner if it has Soundproof") s16 damage[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Speed(15); } PLAYER(SPECIES_VOLTORB) { Speed(10); Ability(ABILITY_SOUNDPROOF); } OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } diff --git a/test/battle/move_effect/aura_wheel.c b/test/battle/move_effect/aura_wheel.c index 3d601f3583a7..dfd31c878f00 100644 --- a/test/battle/move_effect/aura_wheel.c +++ b/test/battle/move_effect/aura_wheel.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffectSelf(MOVE_AURA_WHEEL, MOVE_EFFECT_SPD_PLUS_1) == TRUE); - ASSUME(gMovesInfo[MOVE_AURA_WHEEL].effect == EFFECT_AURA_WHEEL); + ASSUME(GetMoveEffect(MOVE_AURA_WHEEL) == EFFECT_AURA_WHEEL); } SINGLE_BATTLE_TEST("Aura Wheel raises Speed; fails if the user is not Morpeko") diff --git a/test/battle/move_effect/aurora_veil.c b/test/battle/move_effect/aurora_veil.c index f681e965d7ec..b57c85df0626 100644 --- a/test/battle/move_effect/aurora_veil.c +++ b/test/battle/move_effect/aurora_veil.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_AURORA_VEIL].effect == EFFECT_AURORA_VEIL); + ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL); } SINGLE_BATTLE_TEST("Aurora Veil can only be used in Hail and Snow") diff --git a/test/battle/move_effect/baton_pass.c b/test/battle/move_effect/baton_pass.c index b6a27179f323..cb6530ae898f 100644 --- a/test/battle/move_effect/baton_pass.c +++ b/test/battle/move_effect/baton_pass.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); } // This softlocked the game before. @@ -39,9 +39,6 @@ TO_DO_BATTLE_TEST("Baton Pass doesn't pass ability changes"); // TO_DO_BATTLE_TEST("Baton Pass passes confusion status"); // test/battle/status2/confusion.c -TO_DO_BATTLE_TEST("Baton Pass passes Cursed status"); // test/battle/move_effect/curse.c -TO_DO_BATTLE_TEST("Baton Pass doesn't pass Disable's effect"); // test/battle/move_effect/disable.c -TO_DO_BATTLE_TEST("Baton Pass passes Dragon Cheer's effect"); // test/battle/move_effect/dragon_cheer.c TO_DO_BATTLE_TEST("Baton Pass passes Fairy lock's escape prevention effect"); // test/battle/move_effect/fairy_lock.c TO_DO_BATTLE_TEST("Baton Pass passes Focus Energy's effect"); // test/battle/move_effect/focus_energy.c TO_DO_BATTLE_TEST("Baton Pass passes Heal Block's effect"); // test/battle/move_effect/heal_block.c diff --git a/test/battle/move_effect/beak_blast.c b/test/battle/move_effect/beak_blast.c index e716b7717fe0..92557ddee396 100644 --- a/test/battle/move_effect/beak_blast.c +++ b/test/battle/move_effect/beak_blast.c @@ -3,13 +3,13 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BEAK_BLAST].effect == EFFECT_BEAK_BLAST); + ASSUME(GetMoveEffect(MOVE_BEAK_BLAST) == EFFECT_BEAK_BLAST); } DOUBLE_BATTLE_TEST("Beak Blast's charging message is shown before other moves are used") { GIVEN { - ASSUME(gMovesInfo[MOVE_BEAK_BLAST].priority < 0); + ASSUME(GetMovePriority(MOVE_BEAK_BLAST) < 0); PLAYER(SPECIES_WYNAUT) { Speed(10); } PLAYER(SPECIES_WOBBUFFET) { Speed(5); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } @@ -36,8 +36,8 @@ DOUBLE_BATTLE_TEST("Beak Blast's charging message is shown before other moves ar DOUBLE_BATTLE_TEST("Beak Blast burns all who make contact with the pokemon") { GIVEN { - ASSUME(gMovesInfo[MOVE_BEAK_BLAST].priority < 0); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(GetMovePriority(MOVE_BEAK_BLAST) < 0); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_WYNAUT) { Speed(10); } PLAYER(SPECIES_WOBBUFFET) { Speed(5); } OPPONENT(SPECIES_WOBBUFFET) { Speed(3); } @@ -80,9 +80,9 @@ SINGLE_BATTLE_TEST("Beak Blast burns only when contact moves are used") PARAMETRIZE { move = MOVE_LEER; burn = FALSE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(!gMovesInfo[MOVE_WATER_GUN].makesContact); - ASSUME(!gMovesInfo[MOVE_LEER].makesContact); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(!MoveMakesContact(MOVE_WATER_GUN)); + ASSUME(!MoveMakesContact(MOVE_LEER)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -113,4 +113,5 @@ SINGLE_BATTLE_TEST("Beak Blast burns only when contact moves are used") } TO_DO_BATTLE_TEST("Beak Blast's charging message is shown regardless if it would've missed"); +TO_DO_BATTLE_TEST("Beak Blast fails if it's forced by Encore after choosing a different move"); TO_DO_BATTLE_TEST("Bulletproof is immune to Beak Blast but not to the burn it causes"); diff --git a/test/battle/move_effect/belch.c b/test/battle/move_effect/belch.c index f8e28929f963..1abcefb353c3 100644 --- a/test/battle/move_effect/belch.c +++ b/test/battle/move_effect/belch.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BELCH].effect == EFFECT_BELCH); - ASSUME(gMovesInfo[MOVE_MUD_SHOT].type == TYPE_GROUND); + ASSUME(GetMoveEffect(MOVE_BELCH) == EFFECT_BELCH); + ASSUME(GetMoveType(MOVE_MUD_SHOT) == TYPE_GROUND); ASSUME(gItemsInfo[ITEM_SHUCA_BERRY].holdEffect == HOLD_EFFECT_RESIST_BERRY); ASSUME(gItemsInfo[ITEM_SHUCA_BERRY].holdEffectParam == TYPE_GROUND); ASSUME(gItemsInfo[ITEM_SHUCA_BERRY].pocket == POCKET_BERRIES); @@ -56,7 +56,7 @@ SINGLE_BATTLE_TEST("Belch cannot be used if the user has not eaten a berry") SINGLE_BATTLE_TEST("Belch can still be used after switching out") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(GetMoveEffect(MOVE_STUFF_CHEEKS) == EFFECT_STUFF_CHEEKS); PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } PLAYER(SPECIES_SKWOVET); OPPONENT(SPECIES_WOBBUFFET); @@ -76,9 +76,9 @@ SINGLE_BATTLE_TEST("Belch can still be used after switching out") SINGLE_BATTLE_TEST("Belch can still be used after fainting") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); - ASSUME(gMovesInfo[MOVE_FISSURE].effect == EFFECT_OHKO); - ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING); + ASSUME(GetMoveEffect(MOVE_STUFF_CHEEKS) == EFFECT_STUFF_CHEEKS); + ASSUME(GetMoveEffect(MOVE_FISSURE) == EFFECT_OHKO); + ASSUME(GetMoveEffect(MOVE_REVIVAL_BLESSING) == EFFECT_REVIVAL_BLESSING); PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } PLAYER(SPECIES_SKWOVET); OPPONENT(SPECIES_WOBBUFFET); @@ -99,8 +99,8 @@ SINGLE_BATTLE_TEST("Belch can still be used after fainting") SINGLE_BATTLE_TEST("Belch can still be used after restoring the consumed berry") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); - ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + ASSUME(GetMoveEffect(MOVE_STUFF_CHEEKS) == EFFECT_STUFF_CHEEKS); + ASSUME(GetMoveEffect(MOVE_RECYCLE) == EFFECT_RECYCLE); PLAYER(SPECIES_GREEDENT) { Item(ITEM_ORAN_BERRY); } PLAYER(SPECIES_SKWOVET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/belly_drum.c b/test/battle/move_effect/belly_drum.c index bfc558a982db..e36689ac344e 100644 --- a/test/battle/move_effect/belly_drum.c +++ b/test/battle/move_effect/belly_drum.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BELLY_DRUM].effect == EFFECT_BELLY_DRUM); + ASSUME(GetMoveEffect(MOVE_BELLY_DRUM) == EFFECT_BELLY_DRUM); } SINGLE_BATTLE_TEST("Belly Drum cuts the user's HP in half") @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Belly Drum maximizes the user's Attack stat", 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 { @@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Belly Drum fails if user's current HP is half or less than h SINGLE_BATTLE_TEST("Belly Drum fails if the user's Attack is already at +6") { GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -111,7 +111,7 @@ SINGLE_BATTLE_TEST("Belly Drum minimizes the user's Attack stat with Contrary", 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) { Ability(ABILITY_CONTRARY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/bide.c b/test/battle/move_effect/bide.c index f99829d57c92..177b139d088e 100644 --- a/test/battle/move_effect/bide.c +++ b/test/battle/move_effect/bide.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BIDE].effect == EFFECT_BIDE); + ASSUME(GetMoveEffect(MOVE_BIDE) == EFFECT_BIDE); } SINGLE_BATTLE_TEST("Bide deals twice the taken damage over two turns") diff --git a/test/battle/move_effect/body_press.c b/test/battle/move_effect/body_press.c index 3a61c4d55dfc..d3aafa2d32b7 100644 --- a/test/battle/move_effect/body_press.c +++ b/test/battle/move_effect/body_press.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BODY_PRESS].effect == EFFECT_BODY_PRESS); - ASSUME(gMovesInfo[MOVE_BODY_PRESS].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_BODY_PRESS) == EFFECT_BODY_PRESS); + ASSUME(GetMoveCategory(MOVE_BODY_PRESS) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Body Press uses physical defense stat of target", s16 damage) @@ -15,8 +15,8 @@ SINGLE_BATTLE_TEST("Body Press uses physical defense stat of target", s16 damage PARAMETRIZE { move = MOVE_BODY_PRESS; } GIVEN { - ASSUME(gMovesInfo[MOVE_DRILL_PECK].power == gMovesInfo[MOVE_BODY_PRESS].power); - ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2); + ASSUME(GetMovePower(MOVE_DRILL_PECK) == GetMovePower(MOVE_BODY_PRESS)); + ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); PLAYER(SPECIES_MEW); OPPONENT(SPECIES_SHELLDER); } WHEN { @@ -55,8 +55,8 @@ SINGLE_BATTLE_TEST("Body Press's damage depends on the user's Defense and not At PARAMETRIZE { move = MOVE_SWORDS_DANCE; } PARAMETRIZE { move = MOVE_CELEBRATE; } // Nothing, stats are default GIVEN { - ASSUME(gMovesInfo[MOVE_IRON_DEFENSE].effect == EFFECT_DEFENSE_UP_2); - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_IRON_DEFENSE) == EFFECT_DEFENSE_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Attack(150); Defense(150); } } WHEN { @@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("Body Press uses Defense Stat even in Wonder Room", s16 damag PARAMETRIZE { move = MOVE_WONDER_ROOM; } PARAMETRIZE { move = MOVE_CELEBRATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_WONDER_ROOM].effect == EFFECT_WONDER_ROOM); + ASSUME(GetMoveEffect(MOVE_WONDER_ROOM) == EFFECT_WONDER_ROOM); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { SpDefense(50); Defense(150); } } WHEN { @@ -102,8 +102,8 @@ SINGLE_BATTLE_TEST("Body Press uses Special Defense stat Stages in Wonder Room", PARAMETRIZE { move = MOVE_AMNESIA; } PARAMETRIZE { move = MOVE_CELEBRATE; } // Nothing, stats are default GIVEN { - ASSUME(gMovesInfo[MOVE_IRON_DEFENSE].effect == EFFECT_DEFENSE_UP_2); - ASSUME(gMovesInfo[MOVE_AMNESIA].effect == EFFECT_SPECIAL_DEFENSE_UP_2); + ASSUME(GetMoveEffect(MOVE_IRON_DEFENSE) == EFFECT_DEFENSE_UP_2); + ASSUME(GetMoveEffect(MOVE_AMNESIA) == EFFECT_SPECIAL_DEFENSE_UP_2); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { SpDefense(150); Defense(150); } } WHEN { diff --git a/test/battle/move_effect/brick_break.c b/test/battle/move_effect/brick_break.c index 513369b5a1c5..a4aae1e68338 100644 --- a/test/battle/move_effect/brick_break.c +++ b/test/battle/move_effect/brick_break.c @@ -3,11 +3,11 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BRICK_BREAK].effect == EFFECT_BRICK_BREAK); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); - ASSUME(gMovesInfo[MOVE_LIGHT_SCREEN].effect == EFFECT_LIGHT_SCREEN); - ASSUME(gMovesInfo[MOVE_REFLECT].effect == EFFECT_REFLECT); - ASSUME(gMovesInfo[MOVE_AURORA_VEIL].effect == EFFECT_AURORA_VEIL); + ASSUME(GetMoveEffect(MOVE_BRICK_BREAK) == EFFECT_BRICK_BREAK); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN); + ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT); + ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL); } SINGLE_BATTLE_TEST("Brick Break removes Light Screen, Reflect and Aurora Veil from the target's side of the field") diff --git a/test/battle/move_effect/change_type_on_item.c b/test/battle/move_effect/change_type_on_item.c index 2824438634e3..f5c8f92376c1 100644 --- a/test/battle/move_effect/change_type_on_item.c +++ b/test/battle/move_effect/change_type_on_item.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TECHNO_BLAST].effect == EFFECT_CHANGE_TYPE_ON_ITEM); - ASSUME(gMovesInfo[MOVE_TECHNO_BLAST].argument.holdEffect == HOLD_EFFECT_DRIVE); + ASSUME(GetMoveEffect(MOVE_TECHNO_BLAST) == EFFECT_CHANGE_TYPE_ON_ITEM); + ASSUME(GetMoveEffectArg_HoldEffect(MOVE_TECHNO_BLAST) == HOLD_EFFECT_DRIVE); } SINGLE_BATTLE_TEST("Techno Blast changes type depending on the drive the user holds") diff --git a/test/battle/move_effect/charge.c b/test/battle/move_effect/charge.c index b057fa4753ad..bd84a9b4e2c0 100644 --- a/test/battle/move_effect/charge.c +++ b/test/battle/move_effect/charge.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(!IS_MOVE_STATUS(MOVE_THUNDERBOLT)); - ASSUME(gMovesInfo[MOVE_THUNDERBOLT].type == TYPE_ELECTRIC); + ASSUME(!IsBattleMoveStatus(MOVE_THUNDERBOLT)); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); } SINGLE_BATTLE_TEST("Charge doubles the damage of the next Electric move of the user") @@ -88,7 +88,7 @@ SINGLE_BATTLE_TEST("Charge's effect does not stack with Electromorphosis or Wind PARAMETRIZE { species = SPECIES_TADBULB; ability = ABILITY_ELECTROMORPHOSIS; } GIVEN { - ASSUME(gMovesInfo[MOVE_AIR_CUTTER].windMove == TRUE); + ASSUME(IsWindMove(MOVE_AIR_CUTTER)); PLAYER(species) { Ability(ability); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -114,8 +114,8 @@ SINGLE_BATTLE_TEST("Charge's effect is removed regardless if the next move is El s16 chargedUpDamage = 0; GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type != TYPE_ELECTRIC); - ASSUME(!IS_MOVE_STATUS(MOVE_TACKLE)); + ASSUME(GetMoveType(MOVE_TACKLE) != TYPE_ELECTRIC); + ASSUME(!IsBattleMoveStatus(MOVE_TACKLE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/chilly_reception.c b/test/battle/move_effect/chilly_reception.c index 7e821abe3d7e..9b464f0d03a9 100644 --- a/test/battle/move_effect/chilly_reception.c +++ b/test/battle/move_effect/chilly_reception.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_CHILLY_RECEPTION].effect == EFFECT_CHILLY_RECEPTION); + ASSUME(GetMoveEffect(MOVE_CHILLY_RECEPTION) == EFFECT_CHILLY_RECEPTION); } SINGLE_BATTLE_TEST("Chilly Reception sets up snow and switches the user out") diff --git a/test/battle/move_effect/coaching.c b/test/battle/move_effect/coaching.c index 451ac8049527..0cfc593d3529 100644 --- a/test/battle/move_effect/coaching.c +++ b/test/battle/move_effect/coaching.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_COACHING].effect == EFFECT_COACHING); + ASSUME(GetMoveEffect(MOVE_COACHING) == EFFECT_COACHING); } DOUBLE_BATTLE_TEST("Coaching raises Attack and Defense of ally by 1 stage each") @@ -25,7 +25,7 @@ DOUBLE_BATTLE_TEST("Coaching raises Attack and Defense of ally by 1 stage each") DOUBLE_BATTLE_TEST("Coaching bypasses Protect") { GIVEN { - ASSUME(gMovesInfo[MOVE_PROTECT].effect == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -42,7 +42,7 @@ DOUBLE_BATTLE_TEST("Coaching bypasses Protect") DOUBLE_BATTLE_TEST("Coaching bypasses Crafty Shield") { GIVEN { - ASSUME(gMovesInfo[MOVE_CRAFTY_SHIELD].effect == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_CRAFTY_SHIELD) == EFFECT_PROTECT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -60,7 +60,7 @@ DOUBLE_BATTLE_TEST("Coaching fails if all allies are is semi-invulnerable") { KNOWN_FAILING; // Coaching succeeds GIVEN { - ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_HAWLUCHA); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/collision_course.c b/test/battle/move_effect/collision_course.c index 9eeeda5b1e76..9933df0dc72f 100644 --- a/test/battle/move_effect/collision_course.c +++ b/test/battle/move_effect/collision_course.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_COLLISION_COURSE].effect == EFFECT_COLLISION_COURSE); + ASSUME(GetMoveEffect(MOVE_COLLISION_COURSE) == EFFECT_COLLISION_COURSE); } SINGLE_BATTLE_TEST("Collision Course damage is increased by 33 Percent if super effective", s16 damage) diff --git a/test/battle/move_effect/confuse.c b/test/battle/move_effect/confuse.c index 05338219724b..425adfc889ba 100644 --- a/test/battle/move_effect/confuse.c +++ b/test/battle/move_effect/confuse.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TEETER_DANCE].effect == EFFECT_CONFUSE); + ASSUME(GetMoveEffect(MOVE_TEETER_DANCE) == EFFECT_CONFUSE); } SINGLE_BATTLE_TEST("Teeter Dance confuses target") diff --git a/test/battle/move_effect/corrosive_gas.c b/test/battle/move_effect/corrosive_gas.c index cc4110a7e38b..84b7c1c70bba 100644 --- a/test/battle/move_effect/corrosive_gas.c +++ b/test/battle/move_effect/corrosive_gas.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_CORROSIVE_GAS].effect == EFFECT_CORROSIVE_GAS); + ASSUME(GetMoveEffect(MOVE_CORROSIVE_GAS) == EFFECT_CORROSIVE_GAS); } SINGLE_BATTLE_TEST("Corrosive Gas destroys the target's item or fails if the target has no item") @@ -53,7 +53,7 @@ SINGLE_BATTLE_TEST("Corrosive Gas doesn't destroy the item of a Pokemon with the SINGLE_BATTLE_TEST("Items lost to Corrosive Gas cannot be restored by Recycle") { GIVEN { - ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + ASSUME(GetMoveEffect(MOVE_RECYCLE) == EFFECT_RECYCLE); PLAYER(SPECIES_WOBBUFFET) {Speed(15); } OPPONENT(SPECIES_WOBBUFFET) {Item(ITEM_ORAN_BERRY); Speed(10); } } WHEN { diff --git a/test/battle/move_effect/cosmic_power.c b/test/battle/move_effect/cosmic_power.c index 3b52fbe0464e..5c8fe30f6752 100644 --- a/test/battle/move_effect/cosmic_power.c +++ b/test/battle/move_effect/cosmic_power.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_COSMIC_POWER].effect == EFFECT_COSMIC_POWER); + ASSUME(GetMoveEffect(MOVE_COSMIC_POWER) == EFFECT_COSMIC_POWER); } SINGLE_BATTLE_TEST("Cosmic Power increases the user's Defense and Sp. Defense by 1 stage each") diff --git a/test/battle/move_effect/court_change.c b/test/battle/move_effect/court_change.c index f3775d0af65a..817ab134caa8 100644 --- a/test/battle/move_effect/court_change.c +++ b/test/battle/move_effect/court_change.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_COURT_CHANGE].effect == EFFECT_COURT_CHANGE); + ASSUME(GetMoveEffect(MOVE_COURT_CHANGE) == EFFECT_COURT_CHANGE); } DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the opponent") @@ -106,7 +106,7 @@ DOUBLE_BATTLE_TEST("Court Change used by the player swaps Mist, Safeguard, Auror MESSAGE("The opposing Wobbuffet used Tailwind!"); MESSAGE("Wynaut used Court Change!"); MESSAGE("Wynaut swapped the battle effects affecting each side of the field!"); - // The effects now end for the player side. + // The effects now end for the player side. MESSAGE("Your team's Mist wore off!"); MESSAGE("Your team is no longer protected by Safeguard!"); MESSAGE("Your team's Reflect wore off!"); @@ -153,4 +153,66 @@ DOUBLE_BATTLE_TEST("Court Change used by the opponent swaps Mist, Safeguard, Aur } } -TO_DO_BATTLE_TEST("Court Change used by the player swaps G-Max Steelsurge, G-Max Vine Lash, G-Max Wildfire, G-Max Cannonade"); +DOUBLE_BATTLE_TEST("Court Change used by the player swaps G-Max Steelsurge") +{ + GIVEN { + PLAYER(SPECIES_COPPERAJAH) { GigantamaxFactor(TRUE); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(playerLeft, MOVE_IRON_HEAD, target: opponentRight, gimmick: GIMMICK_DYNAMAX); } + TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); } + TURN { SWITCH(opponentLeft, 2); SWITCH(playerLeft, 2); } + } SCENE { + MESSAGE("Copperajah used G-Max Steelsurge!"); + SEND_IN_MESSAGE("Wobbuffet"); + MESSAGE("The sharp steel bit into Wobbuffet!"); + NONE_OF { + MESSAGE("The sharp steel bit into the opposing Wynaut!"); + } + } +} + +DOUBLE_BATTLE_TEST("Court Change used by the player swaps G-Max Vine Lash, G-Max Wildfire, G-Max Cannonade") +{ + u32 species, move; + PARAMETRIZE { species = SPECIES_VENUSAUR; move = MOVE_VINE_WHIP; } + PARAMETRIZE { species = SPECIES_CHARIZARD; move = MOVE_EMBER; } + PARAMETRIZE { species = SPECIES_BLASTOISE; move = MOVE_WATER_GUN; } + GIVEN { + PLAYER(species) { GigantamaxFactor(TRUE); } + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(playerLeft, move, target: opponentRight, gimmick: GIMMICK_DYNAMAX); + MOVE(opponentLeft, MOVE_COURT_CHANGE); + } + } SCENE { + switch (species) { + case SPECIES_VENUSAUR: + MESSAGE("Venusaur used G-Max Vine Lash!"); + MESSAGE("Wobbuffet is hurt by G-Max Vine Lash's ferocious beating!"); + break; + case SPECIES_CHARIZARD: + MESSAGE("Charizard used G-Max Wildfire!"); + MESSAGE("Wobbuffet is burning up within G-Max Wildfire's flames!"); + break; + case SPECIES_BLASTOISE: + MESSAGE("Blastoise used G-Max Cannonade!"); + MESSAGE("Wobbuffet is hurt by G-Max Cannonade's vortex!"); + break; + } + NONE_OF { + MESSAGE("The opposing Wynaut is hurt by G-Max Vine Lash's ferocious beating!"); + MESSAGE("The opposing Wynaut is burning up within G-Max Wildfire's flames!"); + MESSAGE("The opposing Wynaut is hurt by G-Max Cannonade's vortex!"); + } + } +} diff --git a/test/battle/move_effect/curse.c b/test/battle/move_effect/curse.c index 0696dfc4cac2..868608caa8c3 100644 --- a/test/battle/move_effect/curse.c +++ b/test/battle/move_effect/curse.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_CURSE].effect == EFFECT_CURSE); + ASSUME(GetMoveEffect(MOVE_CURSE) == EFFECT_CURSE); } SINGLE_BATTLE_TEST("Curse lowers Speed, raises Attack, and raises Defense when used by non-Ghost-types") @@ -67,3 +67,5 @@ SINGLE_BATTLE_TEST("Curse applies to the opponent if user is afflicted by Trick- HP_BAR(opponent, damage: opponentMaxHP / 4); } } + +TO_DO_BATTLE_TEST("Baton Pass passes Cursed status"); diff --git a/test/battle/move_effect/dark_void.c b/test/battle/move_effect/dark_void.c new file mode 100644 index 000000000000..a69d7d6930d1 --- /dev/null +++ b/test/battle/move_effect/dark_void.c @@ -0,0 +1,42 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_DARK_VOID) == EFFECT_DARK_VOID); +} + +SINGLE_BATTLE_TEST("Dark Void inflicts 1-3 turns of sleep") +{ + u32 turns, count; + ASSUME(B_SLEEP_TURNS >= GEN_5); + PARAMETRIZE { turns = 1; } + PARAMETRIZE { turns = 2; } + PARAMETRIZE { turns = 3; } + PASSES_RANDOMLY(1, 3, RNG_SLEEP_TURNS); + GIVEN { + PLAYER(SPECIES_DARKRAI); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DARK_VOID); MOVE(opponent, MOVE_CELEBRATE); } + for (count = 0; count < turns; ++count) + TURN {} + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DARK_VOID, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent); + MESSAGE("The opposing Wobbuffet fell asleep!"); + STATUS_ICON(opponent, sleep: TRUE); + for (count = 0; count < turns; ++count) + { + if (count < turns - 1) + MESSAGE("The opposing Wobbuffet is fast asleep."); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent); + } + MESSAGE("The opposing Wobbuffet woke up!"); + STATUS_ICON(opponent, none: TRUE); + } +} + +TO_DO_BATTLE_TEST("Dark Void can only be used by Darkrai (Gen7+)"); +TO_DO_BATTLE_TEST("Dark Void can be used by Pokémon other than Darkrai (Gen4-6)"); +TO_DO_BATTLE_TEST("Dark Void can be used by a Pokémon transformed into Darkrai"); diff --git a/test/battle/move_effect/decorate.c b/test/battle/move_effect/decorate.c new file mode 100644 index 000000000000..5eef9dc305c7 --- /dev/null +++ b/test/battle/move_effect/decorate.c @@ -0,0 +1,5 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Decorate raises the target's Attack by 2 stages"); +TO_DO_BATTLE_TEST("Decorate raises the target's Sp. Attack by 2 stages"); diff --git a/test/battle/move_effect/defense_curl.c b/test/battle/move_effect/defense_curl.c new file mode 100644 index 000000000000..c8beffe1717c --- /dev/null +++ b/test/battle/move_effect/defense_curl.c @@ -0,0 +1,37 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_DEFENSE_CURL) == EFFECT_DEFENSE_CURL); +} + +SINGLE_BATTLE_TEST("Defense Curl raises Defense by 1 stage", s16 damage) +{ + bool32 raiseDefense; + PARAMETRIZE { raiseDefense = FALSE; } + PARAMETRIZE { raiseDefense = TRUE; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (raiseDefense) TURN { MOVE(player, MOVE_DEFENSE_CURL); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (raiseDefense) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DEFENSE_CURL, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Defense rose!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(1.5), results[0].damage); + } +} + +TO_DO_BATTLE_TEST("Defense Curl doubles the power of Rollout and Ice Ball"); +TO_DO_BATTLE_TEST("Defense Curl's effect cannot be stacked"); +TO_DO_BATTLE_TEST("Defense Curl's effect is removed when switching out"); +TO_DO_BATTLE_TEST("Baton Pass doesn't pass Defense Curl's effect"); diff --git a/test/battle/move_effect/defense_down.c b/test/battle/move_effect/defense_down.c index 0552a9c67e7e..9691b4a1c258 100644 --- a/test/battle/move_effect/defense_down.c +++ b/test/battle/move_effect/defense_down.c @@ -3,16 +3,16 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TAIL_WHIP].effect == EFFECT_DEFENSE_DOWN); + ASSUME(GetMoveEffect(MOVE_TAIL_WHIP) == EFFECT_DEFENSE_DOWN); } -SINGLE_BATTLE_TEST("Tail Whip lowers Defense", s16 damage) +SINGLE_BATTLE_TEST("Tail Whip lowers Defense by 1 stage", s16 damage) { bool32 lowerDefense; PARAMETRIZE { lowerDefense = FALSE; } PARAMETRIZE { lowerDefense = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/defense_down_2.c b/test/battle/move_effect/defense_down_2.c new file mode 100644 index 000000000000..961e2de02ffc --- /dev/null +++ b/test/battle/move_effect/defense_down_2.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_SCREECH) == EFFECT_DEFENSE_DOWN_2); +} + +SINGLE_BATTLE_TEST("Screech lowers Defense by 2 stages", s16 damage) +{ + bool32 lowerDefense; + PARAMETRIZE { lowerDefense = FALSE; } + PARAMETRIZE { lowerDefense = TRUE; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (lowerDefense) TURN { MOVE(player, MOVE_SCREECH); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + if (lowerDefense) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCREECH, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("The opposing Wobbuffet's Defense harshly fell!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} diff --git a/test/battle/move_effect/defense_up.c b/test/battle/move_effect/defense_up.c index 513d6e1c2980..c83f2c01c5b7 100644 --- a/test/battle/move_effect/defense_up.c +++ b/test/battle/move_effect/defense_up.c @@ -3,16 +3,16 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HARDEN].effect == EFFECT_DEFENSE_UP); + ASSUME(GetMoveEffect(MOVE_HARDEN) == EFFECT_DEFENSE_UP); } -SINGLE_BATTLE_TEST("Harden raises Defense", s16 damage) +SINGLE_BATTLE_TEST("Harden raises Defense by 1 stage", s16 damage) { bool32 raiseDefense; PARAMETRIZE { raiseDefense = FALSE; } PARAMETRIZE { raiseDefense = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/defense_up_2.c b/test/battle/move_effect/defense_up_2.c new file mode 100644 index 000000000000..59ca5c1af937 --- /dev/null +++ b/test/battle/move_effect/defense_up_2.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_IRON_DEFENSE) == EFFECT_DEFENSE_UP_2); +} + +SINGLE_BATTLE_TEST("Iron Defense raises Defense by 2 stages", s16 damage) +{ + bool32 raiseDefense; + PARAMETRIZE { raiseDefense = FALSE; } + PARAMETRIZE { raiseDefense = TRUE; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (raiseDefense) TURN { MOVE(player, MOVE_IRON_DEFENSE); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (raiseDefense) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Defense sharply rose!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(2.0), results[0].damage); + } +} diff --git a/test/battle/move_effect/defense_up_3.c b/test/battle/move_effect/defense_up_3.c new file mode 100644 index 000000000000..040537c1d4f5 --- /dev/null +++ b/test/battle/move_effect/defense_up_3.c @@ -0,0 +1,32 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_COTTON_GUARD) == EFFECT_DEFENSE_UP_3); +} + +SINGLE_BATTLE_TEST("Cotton Guard raises Defense by 3 stages", s16 damage) +{ + bool32 raiseDefense; + PARAMETRIZE { raiseDefense = FALSE; } + PARAMETRIZE { raiseDefense = TRUE; } + GIVEN { + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (raiseDefense) TURN { MOVE(player, MOVE_COTTON_GUARD); } + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (raiseDefense) { + ANIMATION(ANIM_TYPE_MOVE, MOVE_COTTON_GUARD, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Defense drastically rose!"); + } + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[1].damage, Q_4_12(2.5), results[0].damage); + } +} diff --git a/test/battle/move_effect/defog.c b/test/battle/move_effect/defog.c index d5838d7ffd08..3d0a46806ca5 100644 --- a/test/battle/move_effect/defog.c +++ b/test/battle/move_effect/defog.c @@ -3,23 +3,23 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DEFOG].effect == EFFECT_DEFOG); - ASSUME(gMovesInfo[MOVE_REFLECT].effect == EFFECT_REFLECT); - ASSUME(gMovesInfo[MOVE_LIGHT_SCREEN].effect == EFFECT_LIGHT_SCREEN); - ASSUME(gMovesInfo[MOVE_MIST].effect == EFFECT_MIST); - ASSUME(gMovesInfo[MOVE_SAFEGUARD].effect == EFFECT_SAFEGUARD); - ASSUME(gMovesInfo[MOVE_AURORA_VEIL].effect == EFFECT_AURORA_VEIL); - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK); - ASSUME(gMovesInfo[MOVE_SPIKES].effect == EFFECT_SPIKES); - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); - ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_SCREECH].effect == EFFECT_DEFENSE_DOWN_2); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveEffect(MOVE_DEFOG) == EFFECT_DEFOG); + ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT); + ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN); + ASSUME(GetMoveEffect(MOVE_MIST) == EFFECT_MIST); + ASSUME(GetMoveEffect(MOVE_SAFEGUARD) == EFFECT_SAFEGUARD); + ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL); + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); + ASSUME(GetMoveEffect(MOVE_SPIKES) == EFFECT_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_SCREECH) == EFFECT_DEFENSE_DOWN_2); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); } -SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1") +SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 stage") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -51,7 +51,8 @@ SINGLE_BATTLE_TEST("Defog does not lower evasiveness if target behind Substitute } } -DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Reflect and Light Screen from opponent's side", s16 damagePhysical, s16 damageSpecial) +TO_DO_BATTLE_TEST("Defog doesn't remove Reflect or Light Screen from the user's side"); +DOUBLE_BATTLE_TEST("Defog removes Reflect and Light Screen from target's side", s16 damagePhysical, s16 damageSpecial) { u16 move; @@ -71,8 +72,6 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Reflect and Light ANIMATION(ANIM_TYPE_MOVE, MOVE_LIGHT_SCREEN, opponentRight); ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); if (move == MOVE_DEFOG) { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); - MESSAGE("The opposing Wobbuffet's evasiveness fell!"); MESSAGE("The opposing team's Reflect wore off!"); MESSAGE("The opposing team's Light Screen wore off!"); } @@ -86,7 +85,8 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Reflect and Light } } -DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Mist and Safeguard from opponent's side") +TO_DO_BATTLE_TEST("Defog doesn't remove Mist or Safeguard from the user's side"); +DOUBLE_BATTLE_TEST("Defog removes Mist and Safeguard from target's side") { u16 move; @@ -105,7 +105,6 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Mist and Safeguard ANIMATION(ANIM_TYPE_MOVE, MOVE_MIST, opponentLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_SAFEGUARD, opponentRight); if (move == MOVE_DEFOG) { - MESSAGE("The opposing Wobbuffet is protected by the mist!"); ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); MESSAGE("The opposing team's Mist wore off!"); MESSAGE("The opposing team's Safeguard wore off!"); @@ -131,7 +130,9 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Mist and Safeguard } } -DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Stealth Rock and Sticky Web from player's side (Gen 6+)") +TO_DO_BATTLE_TEST("Defog removes Stealth Rock and Sticky Web from target's side"); +TO_DO_BATTLE_TEST("Defog doesn't remove Stealth Rock or Sticky Web from user's side (Gen 4-5)"); +DOUBLE_BATTLE_TEST("Defog removes Stealth Rock and Sticky Web from user's side (Gen 6+)") { u16 move; @@ -151,13 +152,9 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Stealth Rock and S ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft); ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentRight); ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); - if (move == MOVE_DEFOG) { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); - MESSAGE("The opposing Wobbuffet's evasiveness fell!"); - if (B_DEFOG_EFFECT_CLEARING >= GEN_6) { - MESSAGE("The pointed stones disappeared from around your team!"); - MESSAGE("The sticky web has disappeared from the ground around your team!"); - } + if (move == MOVE_DEFOG && B_DEFOG_EFFECT_CLEARING >= GEN_6) { + MESSAGE("The pointed stones disappeared from around your team!"); + MESSAGE("The sticky web has disappeared from the ground around your team!"); } // Switch happens SWITCH_OUT_MESSAGE("Wobbuffet"); @@ -181,7 +178,9 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Stealth Rock and S } } -SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Spikes from player's side") +TO_DO_BATTLE_TEST("Defog removes Spikes from target's side"); +TO_DO_BATTLE_TEST("Defog doesn't remove Spikes from user's side (Gen 4-5)"); +SINGLE_BATTLE_TEST("Defog removes Spikes from user's side (Gen 6+)") { u16 move; @@ -197,12 +196,8 @@ SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Spikes from player } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKES, opponent); ANIMATION(ANIM_TYPE_MOVE, move, player); - if (move == MOVE_DEFOG) { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("The opposing Wobbuffet's evasiveness fell!"); - if (B_DEFOG_EFFECT_CLEARING >= GEN_6) - MESSAGE("The spikes disappeared from the ground around your team!"); - } + if (move == MOVE_DEFOG && B_DEFOG_EFFECT_CLEARING >= GEN_6) + MESSAGE("The spikes disappeared from the ground around your team!"); // Switch happens SWITCH_OUT_MESSAGE("Wobbuffet"); SEND_IN_MESSAGE("Wobbuffet"); @@ -219,7 +214,8 @@ SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Spikes from player } } -SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes terrain (Gen 8+)") +TO_DO_BATTLE_TEST("Defog doesn't remove terrain (Gen 4-7)"); +SINGLE_BATTLE_TEST("Defog removes terrain (Gen 8+)") { u16 move; @@ -235,8 +231,6 @@ SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes terrain (Gen 8+)") } SCENE { ANIMATION(ANIM_TYPE_MOVE, move, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_DEFOG, opponent); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's evasiveness fell!"); if (B_DEFOG_EFFECT_CLEARING >= GEN_8) { if (move == MOVE_PSYCHIC_TERRAIN) { MESSAGE("The weirdness disappeared from the battlefield!"); @@ -263,7 +257,9 @@ SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes terrain (Gen 8+)") } } -SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Toxic Spikes from opponent's side") +TO_DO_BATTLE_TEST("Defog removes Toxic Spikes from target's side"); +TO_DO_BATTLE_TEST("Defog doesn't remove Toxic Spikes from user's side (Gen 4-5)"); +SINGLE_BATTLE_TEST("Defog removes Toxic Spikes from user's side (Gen 6+)") { u16 move; @@ -279,12 +275,8 @@ SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Toxic Spikes from } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, player); ANIMATION(ANIM_TYPE_MOVE, move, opponent); - if (move == MOVE_DEFOG) { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's evasiveness fell!"); - if (B_DEFOG_EFFECT_CLEARING >= GEN_6) - MESSAGE("The poison spikes disappeared from the ground around the opposing team!"); - } + if (move == MOVE_DEFOG && B_DEFOG_EFFECT_CLEARING >= GEN_6) + MESSAGE("The poison spikes disappeared from the ground around the opposing team!"); // Switch happens MESSAGE("2 sent out Wobbuffet!"); if (move != MOVE_DEFOG || B_DEFOG_EFFECT_CLEARING <= GEN_5) { @@ -302,14 +294,15 @@ SINGLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Toxic Spikes from } } -DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Aurora Veil from player's side", s16 damagePhysical, s16 damageSpecial) +TO_DO_BATTLE_TEST("Defog doesn't remove Aurora Veil from the user's side"); +DOUBLE_BATTLE_TEST("Defog removes Aurora Veil from target's side", s16 damagePhysical, s16 damageSpecial) { u16 move; PARAMETRIZE { move = MOVE_DEFOG; } PARAMETRIZE { move = MOVE_CELEBRATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); ASSUME(gSpeciesInfo[SPECIES_GLALIE].types[0] == TYPE_ICE); PLAYER(SPECIES_GLALIE) { Speed(4); } PLAYER(SPECIES_GLALIE) { Speed(3); } @@ -338,10 +331,10 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Aurora Veil from p } } -DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes everything it can") +DOUBLE_BATTLE_TEST("Defog removes everything it can") { GIVEN { - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); ASSUME(gSpeciesInfo[SPECIES_GLALIE].types[0] == TYPE_ICE); PLAYER(SPECIES_GLALIE) { Speed(4); } PLAYER(SPECIES_GLALIE) { Speed(3); } diff --git a/test/battle/move_effect/destiny_bond.c b/test/battle/move_effect/destiny_bond.c index 7291fe7fb3e4..ecb8b1d3ef2f 100644 --- a/test/battle/move_effect/destiny_bond.c +++ b/test/battle/move_effect/destiny_bond.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DESTINY_BOND].effect == EFFECT_DESTINY_BOND); + ASSUME(GetMoveEffect(MOVE_DESTINY_BOND) == EFFECT_DESTINY_BOND); } SINGLE_BATTLE_TEST("Destiny Bond faints the opposing mon if it fainted from the attack") @@ -77,3 +77,35 @@ SINGLE_BATTLE_TEST("Destiny Bond does not fail if used after failing in Gen 7+") ANIMATION(ANIM_TYPE_MOVE, MOVE_DESTINY_BOND, player); } } + +// can't be used at all in Raid, see "Documenting Dynamax" +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are not affected by Destiny Bond") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; + OPPONENT(SPECIES_WOBBUFFET) { HP(1); Speed(100); } + } WHEN { + TURN { MOVE(opponent, MOVE_DESTINY_BOND); MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); } + } SCENE { + MESSAGE("The opposing Wobbuffet used Destiny Bond!"); + MESSAGE("Wobbuffet used Max Strike!"); + MESSAGE("The opposing Wobbuffet fainted!"); + NONE_OF { HP_BAR(player); } + } +} + +TO_DO_BATTLE_TEST("Destiny Bond's effect disappears if the user takes a new turn - Move"); +TO_DO_BATTLE_TEST("Destiny Bond's effect disappears if the user takes a new turn - Sleep"); +TO_DO_BATTLE_TEST("Destiny Bond's effect disappears if the user takes a new turn - Paralysis"); +TO_DO_BATTLE_TEST("Destiny Bond's effect disappears if the user takes a new turn - Flinching"); +TO_DO_BATTLE_TEST("Destiny Bond's effect doesn't trigger on indirect damage - Sandstorm"); +TO_DO_BATTLE_TEST("Destiny Bond's effect doesn't trigger on indirect damage - Leech Seed"); +TO_DO_BATTLE_TEST("Destiny Bond's effect doesn't trigger on indirect damage - Future Sight"); +TO_DO_BATTLE_TEST("Destiny Bond's effect bypasses Focus Sash"); +TO_DO_BATTLE_TEST("Destiny Bond's effect bypasses Sturdy"); +TO_DO_BATTLE_TEST("Destiny Bond's effect bypasses Magic Guard"); +TO_DO_BATTLE_TEST("Destiny Bond's effect can trigger on the next turn if the user hasn't moved yet"); +TO_DO_BATTLE_TEST("Destiny Bond can be used multiple times in a row (Gen 2-6)"); +TO_DO_BATTLE_TEST("Destiny Bond always fails if it was successfully used the previous turn (Gen 7+)"); +TO_DO_BATTLE_TEST("Destiny Bond cannot be used in Raids"); + diff --git a/test/battle/move_effect/disable.c b/test/battle/move_effect/disable.c new file mode 100644 index 000000000000..9864b360e2e5 --- /dev/null +++ b/test/battle/move_effect/disable.c @@ -0,0 +1,20 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Disable prevents the target from using a random move (Gen 1)"); +TO_DO_BATTLE_TEST("Disable prevents the target from using the last move used (Gen 2+)"); +TO_DO_BATTLE_TEST("Disable fails if one of the target's moves is already disabled"); +TO_DO_BATTLE_TEST("Disable fails if the target haven't used a move yet (Gen 2+)"); +TO_DO_BATTLE_TEST("Disable fails if the last move used was Struggle (Gen 2+)"); +TO_DO_BATTLE_TEST("Disable fails if the last move used was a Max Move"); +TO_DO_BATTLE_TEST("Disabled moves can still be used via Sleep Talk"); +TO_DO_BATTLE_TEST("Disabled moves can still be used via Metronome"); +TO_DO_BATTLE_TEST("Disabled moves can still be used via Mirror Move"); +TO_DO_BATTLE_TEST("Disable lasts 0-7 turns (Gen 1)"); +TO_DO_BATTLE_TEST("Disable lasts 2-8 turns (Gen 2)"); +TO_DO_BATTLE_TEST("Disable lasts 2-5 turns (Gen 3)"); +TO_DO_BATTLE_TEST("Disable lasts 4-7 turns (Gen 4)"); +TO_DO_BATTLE_TEST("Disable lasts 4 turns (Gen 5+)"); +TO_DO_BATTLE_TEST("Disable's timer only counts down when trying to use a move (Gen 1-2)"); +TO_DO_BATTLE_TEST("Disable's timer counts down regardless of the action (Gen 3+)"); +TO_DO_BATTLE_TEST("Baton Pass doesn't pass Disable's effect"); diff --git a/test/battle/move_effect/do_nothing.c b/test/battle/move_effect/do_nothing.c new file mode 100644 index 000000000000..60ff198b522f --- /dev/null +++ b/test/battle/move_effect/do_nothing.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Splash does nothing"); diff --git a/test/battle/move_effect/doodle.c b/test/battle/move_effect/doodle.c index a43a149dc82c..af144ecee593 100644 --- a/test/battle/move_effect/doodle.c +++ b/test/battle/move_effect/doodle.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DOODLE].effect == EFFECT_DOODLE); + ASSUME(GetMoveEffect(MOVE_DOODLE) == EFFECT_DOODLE); } DOUBLE_BATTLE_TEST("Doodle gives the target's ability to user and ally") diff --git a/test/battle/move_effect_secondary/double_power_on_arg_status.c b/test/battle/move_effect/double_power_on_arg_status.c similarity index 84% rename from test/battle/move_effect_secondary/double_power_on_arg_status.c rename to test/battle/move_effect/double_power_on_arg_status.c index 1d3563c42708..d733d04c4fed 100644 --- a/test/battle/move_effect_secondary/double_power_on_arg_status.c +++ b/test/battle/move_effect/double_power_on_arg_status.c @@ -12,8 +12,8 @@ SINGLE_BATTLE_TEST("Hex deals double damage to foes with a status", s16 damage) PARAMETRIZE { status1 = STATUS1_PARALYSIS; } PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } GIVEN { - ASSUME(gMovesInfo[MOVE_HEX].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_HEX].argument.status == STATUS1_ANY); + ASSUME(GetMoveEffect(MOVE_HEX) == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(GetMoveEffectArg_Status(MOVE_HEX) == STATUS1_ANY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } } WHEN { @@ -36,8 +36,8 @@ SINGLE_BATTLE_TEST("Venoshock's power doubles if the target is poisoned/badly po PARAMETRIZE { status1 = STATUS1_POISON; } PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } GIVEN { - ASSUME(gMovesInfo[MOVE_VENOSHOCK].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_VENOSHOCK].argument.status == STATUS1_PSN_ANY); + ASSUME(GetMoveEffect(MOVE_VENOSHOCK) == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(GetMoveEffectArg_Status(MOVE_VENOSHOCK) == STATUS1_PSN_ANY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } } WHEN { diff --git a/test/battle/move_effect/dragon_cheer.c b/test/battle/move_effect/dragon_cheer.c new file mode 100644 index 000000000000..1e28c6d4b399 --- /dev/null +++ b/test/battle/move_effect/dragon_cheer.c @@ -0,0 +1,77 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Dragon Cheer fails in a single battle") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_DRAGON_CHEER) == EFFECT_DRAGON_CHEER); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DRAGON_CHEER); } + } SCENE { + MESSAGE("But it failed!"); + } +} + +DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by one on non-Dragon types") +{ + PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); + GIVEN { + ASSUME(B_CRIT_CHANCE >= GEN_7); + ASSUME(GetMoveCriticalHitStage(MOVE_TACKLE) == 0); + ASSUME(GetMoveEffect(MOVE_DRAGON_CHEER) == EFFECT_DRAGON_CHEER); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft); + MESSAGE("Wynaut is getting pumped!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); + MESSAGE("A critical hit!"); + } +} + +DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by two on Dragon types") +{ + PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); + GIVEN { + ASSUME(B_CRIT_CHANCE >= GEN_7); + ASSUME(GetMoveCriticalHitStage(MOVE_TACKLE) == 0); + ASSUME(GetMoveEffect(MOVE_DRAGON_CHEER) == EFFECT_DRAGON_CHEER); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_DRATINI); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft); + MESSAGE("Dratini is getting pumped!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); + MESSAGE("A critical hit!"); + } +} + +DOUBLE_BATTLE_TEST("Dragon Cheer fails if critical hit stage was already increased by Focus Energy") +{ + GIVEN { + ASSUME(GetMoveCriticalHitStage(MOVE_SLASH) == 1); + ASSUME(GetMoveEffect(MOVE_FOCUS_ENERGY) == EFFECT_FOCUS_ENERGY); + ASSUME(GetMoveEffect(MOVE_DRAGON_CHEER) == EFFECT_DRAGON_CHEER); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_FOCUS_ENERGY); MOVE(playerRight, MOVE_DRAGON_CHEER, target: playerLeft); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, playerLeft); + MESSAGE("But it failed!"); + } +} + +TO_DO_BATTLE_TEST("Baton Pass passes Dragon Cheer's effect"); diff --git a/test/battle/move_effect/dragon_dance.c b/test/battle/move_effect/dragon_dance.c new file mode 100644 index 000000000000..52587cc09840 --- /dev/null +++ b/test/battle/move_effect/dragon_dance.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Dragon Dance increases Attack and Speed by one stage each"); diff --git a/test/battle/move_effect/dragon_darts.c b/test/battle/move_effect/dragon_darts.c index dfe629896f41..9e178f67c83f 100644 --- a/test/battle/move_effect/dragon_darts.c +++ b/test/battle/move_effect/dragon_darts.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DRAGON_DARTS].effect == EFFECT_DRAGON_DARTS); + ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS); ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); } @@ -23,170 +23,148 @@ SINGLE_BATTLE_TEST("Dragon Darts strikes twice") DOUBLE_BATTLE_TEST("Dragon Darts strikes each opponent once in a double battle") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *secondaryTarget = NULL; + PARAMETRIZE { chosenTarget = opponentLeft; secondaryTarget = opponentRight; } + PARAMETRIZE { chosenTarget = opponentRight; secondaryTarget = opponentLeft; } + GIVEN { PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); + HP_BAR(chosenTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(secondaryTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } DOUBLE_BATTLE_TEST("Dragon Darts strikes the ally twice if the target protects") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *secondaryTarget = NULL; + PARAMETRIZE { chosenTarget = opponentLeft; secondaryTarget = opponentRight; } + PARAMETRIZE { chosenTarget = opponentRight; secondaryTarget = opponentLeft; } GIVEN { PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponentLeft, MOVE_PROTECT); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + TURN { MOVE(chosenTarget, MOVE_PROTECT); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, chosenTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(secondaryTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(secondaryTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } -DOUBLE_BATTLE_TEST("Dragon Darts strikes the right ally twice if the target is a fairy type") +DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is Fairy-type") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *finalTarget = NULL; + u32 speciesLeft, speciesRight; + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; } + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; } GIVEN { + ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_CLEFAIRY); - OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(speciesLeft); + OPPONENT(speciesRight); } WHEN { - TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } -DOUBLE_BATTLE_TEST("Dragon Darts strikes the left ally twice if the target is a fairy type") +DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if electrified and the other one has Volt Absorb") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *finalTarget = NULL; + u32 abilityLeft, abilityRight; + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; abilityLeft = ABILITY_WATER_ABSORB; abilityRight = ABILITY_VOLT_ABSORB; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; abilityLeft = ABILITY_WATER_ABSORB; abilityRight = ABILITY_VOLT_ABSORB; } + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; abilityLeft = ABILITY_VOLT_ABSORB; abilityRight = ABILITY_WATER_ABSORB; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; abilityLeft = ABILITY_VOLT_ABSORB; abilityRight = ABILITY_WATER_ABSORB; } GIVEN { + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_CLEFAIRY); - OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_LANTURN) { Ability(abilityLeft); }; + OPPONENT(SPECIES_LANTURN) { Ability(abilityRight); }; } WHEN { - TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); } + TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } -DOUBLE_BATTLE_TEST("Dragon Darts strikes left ally twice if electrified and right ally has Volt Absorb") +DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if electrified and the other one has Motor Drive") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *finalTarget = NULL; + u32 abilityLeft, abilityRight; + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_MOTOR_DRIVE; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; abilityLeft = ABILITY_VITAL_SPIRIT; abilityRight = ABILITY_MOTOR_DRIVE; } + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; abilityLeft = ABILITY_MOTOR_DRIVE; abilityRight = ABILITY_VITAL_SPIRIT; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; abilityLeft = ABILITY_MOTOR_DRIVE; abilityRight = ABILITY_VITAL_SPIRIT; } GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); }; + OPPONENT(SPECIES_ELECTIVIRE) { Ability(abilityLeft); }; + OPPONENT(SPECIES_ELECTIVIRE) { Ability(abilityRight); }; } WHEN { - TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); } + TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); + HP_BAR(finalTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); + HP_BAR(finalTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } -DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if electrified and left ally has Volt Absorb") +DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is in a semi-invulnerable turn") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *finalTarget = NULL; + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; } GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); + ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); }; OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); - MESSAGE("The Pokémon was hit 2 time(s)!"); - } -} - -DOUBLE_BATTLE_TEST("Dragon Darts strikes left ally twice if electrified and right ally has Motor Drive") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); }; } WHEN { - TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); } + TURN { MOVE(chosenTarget, MOVE_FLY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget); } } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLY, chosenTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); + HP_BAR(finalTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); - MESSAGE("The Pokémon was hit 2 time(s)!"); - } -} - -DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if electrified and left ally has Motor Drive") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); }; - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponentRight, MOVE_ELECTRIFY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); - MESSAGE("The Pokémon was hit 2 time(s)!"); - } -} - - -DOUBLE_BATTLE_TEST("Dragon Darts strikes the ally twice if the target is in a semi-invulnerable turn") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponentLeft, MOVE_FLY, target: playerLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_FLY, opponentLeft); - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); - ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } @@ -210,39 +188,49 @@ DOUBLE_BATTLE_TEST("Dragon Darts is not effected by Wide Guard") } } -DOUBLE_BATTLE_TEST("Dragon Darts strikes hit the ally if the target fainted") +DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is fainted") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *finalTarget = NULL; + u32 hpLeft, hpRight; + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; hpLeft = 1; hpRight = 101; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; hpLeft = 101; hpRight = 1; } GIVEN { PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { HP(1); } - OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(hpLeft); } + OPPONENT(SPECIES_WOBBUFFET) { HP(hpRight); } } WHEN { - TURN { MOVE(playerRight, MOVE_SONIC_BOOM, target: opponentLeft); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); } + TURN { MOVE(playerRight, MOVE_SONIC_BOOM, target: chosenTarget); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SONIC_BOOM, playerRight); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentRight); + HP_BAR(finalTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } DOUBLE_BATTLE_TEST("Dragon Darts strikes left ally twice if one strike misses") { + struct BattlePokemon *chosenTarget = NULL; + struct BattlePokemon *finalTarget = NULL; + u32 itemLeft, itemRight; + PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; itemLeft = ITEM_BRIGHT_POWDER; itemRight = ITEM_NONE; } + PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; itemLeft = ITEM_NONE; itemRight = ITEM_BRIGHT_POWDER; } GIVEN { PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BRIGHT_POWDER); }; + OPPONENT(SPECIES_WOBBUFFET) { Item(itemLeft); }; + OPPONENT(SPECIES_WOBBUFFET) { Item(itemRight); }; } WHEN { - TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentRight, hit: FALSE); } + TURN { MOVE(playerLeft, MOVE_DRAGON_DARTS, target: chosenTarget, hit: FALSE); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); + HP_BAR(finalTarget); ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_DARTS, playerLeft); - HP_BAR(opponentLeft); + HP_BAR(finalTarget); MESSAGE("The Pokémon was hit 2 time(s)!"); } } diff --git a/test/battle/move_effect/dream_eater.c b/test/battle/move_effect/dream_eater.c index 7dfa6525d9d7..b840e9860ccf 100644 --- a/test/battle/move_effect/dream_eater.c +++ b/test/battle/move_effect/dream_eater.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DREAM_EATER].effect == EFFECT_DREAM_EATER); + ASSUME(GetMoveEffect(MOVE_DREAM_EATER) == EFFECT_DREAM_EATER); } SINGLE_BATTLE_TEST("Dream Eater recovers 50% of the damage dealt") @@ -54,3 +54,7 @@ SINGLE_BATTLE_TEST("Dream Eater fails if Heal Block applies") } } } + +TO_DO_BATTLE_TEST("Dream Eater works on targets with Comatose"); +TO_DO_BATTLE_TEST("Dream Eater fails if the target is behind a Substitute (Gen 1-4)"); +TO_DO_BATTLE_TEST("Dream Eater works if the target is behind a Substitute (Gen 5+)"); diff --git a/test/battle/move_effect/dynamax_double_dmg.c b/test/battle/move_effect/dynamax_double_dmg.c new file mode 100644 index 000000000000..c19ba5ecbc4b --- /dev/null +++ b/test/battle/move_effect/dynamax_double_dmg.c @@ -0,0 +1,20 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Dynamax Cannon causes double damage to Dynamaxed Pokemon", s16 damage) +{ + u32 dynamax; + PARAMETRIZE { dynamax = GIMMICK_NONE; } + PARAMETRIZE { dynamax = GIMMICK_DYNAMAX; } + GIVEN { + ASSUME(GetMoveEffect(MOVE_DYNAMAX_CANNON) == EFFECT_DYNAMAX_DOUBLE_DMG); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TACKLE, gimmick: dynamax); MOVE(opponent, MOVE_DYNAMAX_CANNON); } + } SCENE { + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(2.0), results[1].damage); + } +} diff --git a/test/battle/move_effect/earthquake.c b/test/battle/move_effect/earthquake.c index 93955e15b47a..2cbf3b32c56a 100644 --- a/test/battle/move_effect/earthquake.c +++ b/test/battle/move_effect/earthquake.c @@ -10,8 +10,8 @@ SINGLE_BATTLE_TEST("Earthquake's and Bulldoze's damage is halved when Grassy Ter PARAMETRIZE { terrain = FALSE; move = MOVE_BULLDOZE; } // 2 PARAMETRIZE { terrain = TRUE; move = MOVE_BULLDOZE; } // 3 GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].effect == EFFECT_EARTHQUAKE); - ASSUME(gMovesInfo[MOVE_BULLDOZE].effect == EFFECT_EARTHQUAKE); + ASSUME(GetMoveEffect(MOVE_EARTHQUAKE) == EFFECT_EARTHQUAKE); + ASSUME(GetMoveEffect(MOVE_BULLDOZE) == EFFECT_EARTHQUAKE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/echoed_voice.c b/test/battle/move_effect/echoed_voice.c new file mode 100644 index 000000000000..3c362704548b --- /dev/null +++ b/test/battle/move_effect/echoed_voice.c @@ -0,0 +1,7 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Echoed Voice's power is multiplied for every consecutive turn used, capped at 5"); +TO_DO_BATTLE_TEST("Echoed Voice's power is reset when using a different move"); +TO_DO_BATTLE_TEST("Echoed Voice's power is increased even if it misses"); +TO_DO_BATTLE_TEST("Echoed Voice's power is increased even if it's blocked by Protect"); diff --git a/test/battle/terrain/electric.c b/test/battle/move_effect/electric_terrain.c similarity index 74% rename from test/battle/terrain/electric.c rename to test/battle/move_effect/electric_terrain.c index b3811d056c25..bf6d2536e61b 100644 --- a/test/battle/terrain/electric.c +++ b/test/battle/move_effect/electric_terrain.c @@ -19,25 +19,6 @@ SINGLE_BATTLE_TEST("Electric Terrain protects grounded battlers from falling asl } } -SINGLE_BATTLE_TEST("Electric Terrain activates Electric Seed and Mimicry") -{ - GIVEN { - ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); - ASSUME(gItemsInfo[ITEM_ELECTRIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_ELECTRIC_TERRAIN); - PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_ELECTRIC_SEED); } - OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } - } WHEN { - TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); } - } SCENE { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Using Electric Seed, the Defense of Wobbuffet rose!"); - ABILITY_POPUP(opponent); - MESSAGE("The opposing Stunfisk's type changed to Electric!"); - } THEN { - EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[0], TYPE_ELECTRIC); - } -} - SINGLE_BATTLE_TEST("Electric Terrain increases power of Electric-type moves by 30/50 percent", s16 damage) { bool32 terrain; diff --git a/test/battle/move_effect/electrify.c b/test/battle/move_effect/electrify.c new file mode 100644 index 000000000000..71373cdd5866 --- /dev/null +++ b/test/battle/move_effect/electrify.c @@ -0,0 +1,5 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Electrify makes the target's move Electric-type for the remainder of the turn"); +TO_DO_BATTLE_TEST("Electrify can change status moves to Electric-type"); // Test type immunity diff --git a/test/battle/move_effect/electro_ball.c b/test/battle/move_effect/electro_ball.c new file mode 100644 index 000000000000..a74445c00c14 --- /dev/null +++ b/test/battle/move_effect/electro_ball.c @@ -0,0 +1,5 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Electro Ball inflicts more damage the faster the user is compared to the target"); +TO_DO_BATTLE_TEST("Electro Ball considers speed modifiers"); // Stat modifiers, paralysis, Iron Ball, Abilities diff --git a/test/battle/move_effect/embargo.c b/test/battle/move_effect/embargo.c index 81939a6d567d..3e86b60b0b10 100644 --- a/test/battle/move_effect/embargo.c +++ b/test/battle/move_effect/embargo.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_EMBARGO].effect == EFFECT_EMBARGO); + ASSUME(GetMoveEffect(MOVE_EMBARGO) == EFFECT_EMBARGO); } SINGLE_BATTLE_TEST("Embargo blocks the effect of an affected Pokémon's held item") diff --git a/test/battle/move_effect/encore.c b/test/battle/move_effect/encore.c index ec68297ca0aa..2d1863da6b17 100644 --- a/test/battle/move_effect/encore.c +++ b/test/battle/move_effect/encore.c @@ -3,121 +3,127 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); } -SINGLE_BATTLE_TEST("Encore forces consecutive move uses for 3 turns for player: Encore used before move") +SINGLE_BATTLE_TEST("Encore forces consecutive move uses for 3 turns: Encore used before move") { + struct BattlePokemon *encoreUser = NULL; + struct BattlePokemon *encoreTarget = NULL; + u32 speedPlayer, speedOpponent; + PARAMETRIZE { encoreUser = opponent; encoreTarget = player; speedPlayer = 10; speedOpponent = 20; } + PARAMETRIZE { encoreUser = player; encoreTarget = opponent; speedPlayer = 20; speedOpponent = 10; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(10); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(20); } + PLAYER(SPECIES_WOBBUFFET) { Speed(speedPlayer); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(speedOpponent); } } WHEN { - TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE); } - TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_CELEBRATE); } - // TURN { FORCED_MOVE(player); } - TURN { FORCED_MOVE(player); } - TURN { FORCED_MOVE(player); } - TURN { MOVE(player, MOVE_SPLASH); } + TURN { MOVE(encoreUser, MOVE_CELEBRATE); MOVE(encoreTarget, MOVE_CELEBRATE); } + TURN { MOVE(encoreUser, MOVE_ENCORE); MOVE(encoreTarget, MOVE_CELEBRATE); } + TURN { FORCED_MOVE(encoreTarget); } + TURN { FORCED_MOVE(encoreTarget); } + TURN { MOVE(encoreTarget, MOVE_SPLASH); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SPLASH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreUser); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, encoreUser); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPLASH, encoreTarget); } } SINGLE_BATTLE_TEST("Encore forces consecutive move uses for 3 turns for player: Encore used after move") { + struct BattlePokemon *encoreUser = NULL; + struct BattlePokemon *encoreTarget = NULL; + u32 speedPlayer, speedOpponent; + PARAMETRIZE { encoreUser = opponent; encoreTarget = player; speedPlayer = 20; speedOpponent = 10; } + PARAMETRIZE { encoreUser = player; encoreTarget = opponent; speedPlayer = 10; speedOpponent = 20; } GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(20); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + PLAYER(SPECIES_WOBBUFFET) { Speed(speedPlayer); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(speedOpponent); } } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_ENCORE); } - TURN { FORCED_MOVE(player); } - TURN { FORCED_MOVE(player); } - TURN { FORCED_MOVE(player); } - TURN { MOVE(player, MOVE_SPLASH); } + TURN { MOVE(encoreTarget, MOVE_CELEBRATE); MOVE(encoreUser, MOVE_ENCORE); } + TURN { FORCED_MOVE(encoreTarget); } + TURN { FORCED_MOVE(encoreTarget); } + TURN { FORCED_MOVE(encoreTarget); } + TURN { MOVE(encoreTarget, MOVE_SPLASH); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SPLASH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, encoreUser); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, encoreTarget); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPLASH, encoreTarget); } } -SINGLE_BATTLE_TEST("Encore forces consecutive move uses for 3 turns for opponent: Encore used before move") +SINGLE_BATTLE_TEST("Encore has no effect if no previous move") { GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(20); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } - TURN { MOVE(player, MOVE_ENCORE); MOVE(opponent, MOVE_CELEBRATE); } - // TURN { FORCED_MOVE(opponent); } - TURN { FORCED_MOVE(opponent); } - TURN { FORCED_MOVE(opponent); } - TURN { MOVE(opponent, MOVE_SPLASH); } + TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_CELEBRATE); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SPLASH, opponent); + MESSAGE("The opposing Wobbuffet used Encore!"); + MESSAGE("But it failed!"); } } -SINGLE_BATTLE_TEST("Encore forces consecutive move uses for 3 turns for opponent: Encore used after move") +SINGLE_BATTLE_TEST("Encore overrides the chosen move if it occurs first") { GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Speed(10); } - OPPONENT(SPECIES_WOBBUFFET) { Speed(20); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_ENCORE); } - TURN { FORCED_MOVE(opponent); } - TURN { FORCED_MOVE(opponent); } - TURN { FORCED_MOVE(opponent); } - TURN { MOVE(opponent, MOVE_SPLASH); } + TURN { MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_SPLASH); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SPLASH, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); } } -SINGLE_BATTLE_TEST("Encore has no effect if no previous move") +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon are immune to Encore") { GIVEN { PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_TACKLE, gimmick: GIMMICK_DYNAMAX); MOVE(opponent, MOVE_ENCORE); } + TURN { MOVE(player, MOVE_EMBER); } } SCENE { + MESSAGE("Wobbuffet used Max Strike!"); MESSAGE("The opposing Wobbuffet used Encore!"); MESSAGE("But it failed!"); + MESSAGE("Wobbuffet used Max Flare!"); } } -SINGLE_BATTLE_TEST("Encore overrides the chosen move if it occurs first") +SINGLE_BATTLE_TEST("(DYNAMAX) Dynamaxed Pokemon can be encored immediately after reverting") { GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET) { Speed(50); }; // yes, this speed is necessary + OPPONENT(SPECIES_WOBBUFFET) { Speed(100); }; } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); } - TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_SPLASH); } + TURN { MOVE(player, MOVE_ARM_THRUST, gimmick: GIMMICK_DYNAMAX); } + TURN { MOVE(player, MOVE_ARM_THRUST); } + TURN { MOVE(player, MOVE_ARM_THRUST); } + TURN { MOVE(opponent, MOVE_ENCORE); MOVE(player, MOVE_TACKLE); } } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_ENCORE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + MESSAGE("Wobbuffet used Max Knuckle!"); + MESSAGE("Wobbuffet used Max Knuckle!"); + MESSAGE("Wobbuffet used Max Knuckle!"); + MESSAGE("The opposing Wobbuffet used Encore!"); + MESSAGE("Wobbuffet used Arm Thrust!"); } } + +TO_DO_BATTLE_TEST("Encore's effect ends if the encored move runs out of PP"); +TO_DO_BATTLE_TEST("Encore lasts for 2-6 turns (Gen 2-3)"); +TO_DO_BATTLE_TEST("Encore lasts for 4-8 turns (Gen 4)"); +TO_DO_BATTLE_TEST("Encore lasts for 3 turns (Gen 5+)"); +TO_DO_BATTLE_TEST("Encore randomly chooses an opponent target"); diff --git a/test/battle/move_effect/endeavor.c b/test/battle/move_effect/endeavor.c index 7080ee9c288f..43786c29b3d0 100644 --- a/test/battle/move_effect/endeavor.c +++ b/test/battle/move_effect/endeavor.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ENDEAVOR].effect == EFFECT_ENDEAVOR); + ASSUME(GetMoveEffect(MOVE_ENDEAVOR) == EFFECT_ENDEAVOR); } SINGLE_BATTLE_TEST("Endeavor causes the target's HP to equal the user's current HP") @@ -20,4 +20,4 @@ SINGLE_BATTLE_TEST("Endeavor causes the target's HP to equal the user's current } } TO_DO_BATTLE_TEST("Endeavor does not change HP if the target has less HP than the user, but still plays the animation") -TO_DO_BATTLE_TEST("Endeavor doesn't ignore type immunity") // Ghost types +TO_DO_BATTLE_TEST("Endeavor fails on Ghost-type Pokémon"); diff --git a/test/battle/move_effect/endure.c b/test/battle/move_effect/endure.c new file mode 100644 index 000000000000..54013211620d --- /dev/null +++ b/test/battle/move_effect/endure.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Endure allows the user to survive any attack with 1 HP left"); + +SINGLE_BATTLE_TEST("Endure does not prevent multiple hits and stat changes occur at the end of the turn") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_ENDURE) == EFFECT_ENDURE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + } WHEN { + TURN { MOVE(opponent, MOVE_ENDURE); MOVE(player, MOVE_SCALE_SHOT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); + MESSAGE("The Pokémon was hit 5 time(s)!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Defense fell!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Speed rose!"); + } +} + +TO_DO_BATTLE_TEST("Endure's success rate decreases for every consecutively used turn"); +TO_DO_BATTLE_TEST("Endure uses the same counter as Protect"); +TO_DO_BATTLE_TEST("Endure doesn't trigger effects that require damage to be done to the Pokémon (Gen 2-4)"); // Eg. Rough Skin +TO_DO_BATTLE_TEST("Endure triggers effects that require damage to be done to the Pokémon (Gen 5+)"); // Eg. Rough Skin +TO_DO_BATTLE_TEST("Endure doesn't protect against Future Sight (Gen 2-4)"); +TO_DO_BATTLE_TEST("Endure protects against Future Sight (Gen 5+)"); diff --git a/test/battle/move_effect/entrainment.c b/test/battle/move_effect/entrainment.c new file mode 100644 index 000000000000..b43f6dcbc159 --- /dev/null +++ b/test/battle/move_effect/entrainment.c @@ -0,0 +1,6 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Entrainment changes the target's Ability to match the user's"); +TO_DO_BATTLE_TEST("Entrainment fails if the user's ability has cantBeCopied flag"); +TO_DO_BATTLE_TEST("Entrainment fails if the targets's ability has cantBeOverwritten flag"); diff --git a/test/battle/move_effect/evasion_down.c b/test/battle/move_effect/evasion_down.c new file mode 100644 index 000000000000..ecc0db135be1 --- /dev/null +++ b/test/battle/move_effect/evasion_down.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Sweet Scent lowers evasion by 1 stage (Gen 2-5)"); diff --git a/test/battle/move_effect/evasion_down_2.c b/test/battle/move_effect/evasion_down_2.c new file mode 100644 index 000000000000..7584406e4cef --- /dev/null +++ b/test/battle/move_effect/evasion_down_2.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Sweet Scent lowers evasion by 1 stage (Gen 6+)"); diff --git a/test/battle/move_effect/evasion_up.c b/test/battle/move_effect/evasion_up.c index 7058694e9de4..529a32c4f12f 100644 --- a/test/battle/move_effect/evasion_up.c +++ b/test/battle/move_effect/evasion_up.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DOUBLE_TEAM].effect == EFFECT_EVASION_UP); + ASSUME(GetMoveEffect(MOVE_DOUBLE_TEAM) == EFFECT_EVASION_UP); } -SINGLE_BATTLE_TEST("Double Team raises Evasion") +SINGLE_BATTLE_TEST("Double Team raises Evasion by 1 stage") { - PASSES_RANDOMLY(gMovesInfo[MOVE_SCRATCH].accuracy * 3 / 4, 100, RNG_ACCURACY); + PASSES_RANDOMLY(GetMoveAccuracy(MOVE_SCRATCH) * 3 / 4, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_SCRATCH].accuracy == 100); + ASSUME(GetMoveAccuracy(MOVE_SCRATCH) == 100); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/evasion_up_2.c b/test/battle/move_effect/evasion_up_2.c new file mode 100644 index 000000000000..cd5cb543a9da --- /dev/null +++ b/test/battle/move_effect/evasion_up_2.c @@ -0,0 +1,28 @@ +#include "global.h" +#include "test/battle.h" + +// There's no move with EFFECT_EVASION_UP_2 effect. Below is a theoretical test. + +/* +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_X].effect == EFFECT_EVASION_UP_2); +} + +SINGLE_BATTLE_TEST("Double Team raises Evasion by 1 stage") +{ + PASSES_RANDOMLY(gMovesInfo[MOVE_SCRATCH].accuracy * 3 / 5, 100, RNG_ACCURACY); + GIVEN { + ASSUME(gMovesInfo[MOVE_SCRATCH].accuracy == 100); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_X); MOVE(opponent, MOVE_SCRATCH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_X, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's evasiveness sharply rose!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponent); + } +} +*/ diff --git a/test/battle/move_effect/expanding_force.c b/test/battle/move_effect/expanding_force.c new file mode 100644 index 000000000000..74b78fdd8635 --- /dev/null +++ b/test/battle/move_effect/expanding_force.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Expanding Force's power increases by 50% if the user is affected by Psychic Terrain"); diff --git a/test/battle/move_effect/explosion.c b/test/battle/move_effect/explosion.c index f383ecb1a262..52eec1a8e266 100644 --- a/test/battle/move_effect/explosion.c +++ b/test/battle/move_effect/explosion.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); } SINGLE_BATTLE_TEST("Explosion causes the user to faint") @@ -54,7 +54,7 @@ SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it misses") SINGLE_BATTLE_TEST("Explosion causes the user to faint even if it has no effect") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_EXPLOSION) == TYPE_NORMAL); ASSUME(gSpeciesInfo[SPECIES_GASTLY].types[0] == TYPE_GHOST); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GASTLY); diff --git a/test/battle/move_effect/extreme_evoboost.c b/test/battle/move_effect/extreme_evoboost.c new file mode 100644 index 000000000000..c43a6f737479 --- /dev/null +++ b/test/battle/move_effect/extreme_evoboost.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Extreme Evoboost increases the user's Attack, Defense, Special Attack, Special Defense, and Speed stats by 2 stages each"); diff --git a/test/battle/move_effect/fail_if_not_arg_type.c b/test/battle/move_effect/fail_if_not_arg_type.c index 4ded2d3a7f06..368c3410c0f8 100644 --- a/test/battle/move_effect/fail_if_not_arg_type.c +++ b/test/battle/move_effect/fail_if_not_arg_type.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type") { GIVEN { - ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_BURN_UP) == EFFECT_FAIL_IF_NOT_ARG_TYPE); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type") SINGLE_BATTLE_TEST("Burn Up fails if the user isn't a Fire-type") { GIVEN { - ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_BURN_UP) == EFFECT_FAIL_IF_NOT_ARG_TYPE); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET); @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Burn Up fails if the user isn't a Fire-type") SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type if enemy faints") { GIVEN { - ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_BURN_UP) == EFFECT_FAIL_IF_NOT_ARG_TYPE); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); @@ -59,7 +59,7 @@ SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type if enemy faints") SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SHOCK) == EFFECT_FAIL_IF_NOT_ARG_TYPE); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); @@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type") SINGLE_BATTLE_TEST("Double Shock fails if the user isn't an Electric-type") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SHOCK) == EFFECT_FAIL_IF_NOT_ARG_TYPE); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); @@ -96,7 +96,7 @@ SINGLE_BATTLE_TEST("Double Shock fails if the user isn't an Electric-type") SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type if enemy faints") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(GetMoveEffect(MOVE_DOUBLE_SHOCK) == EFFECT_FAIL_IF_NOT_ARG_TYPE); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); diff --git a/test/battle/move_effect/fickle_beam.c b/test/battle/move_effect/fickle_beam.c index ffbbe4d18dc5..0313823aa95c 100644 --- a/test/battle/move_effect/fickle_beam.c +++ b/test/battle/move_effect/fickle_beam.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FICKLE_BEAM].effect == EFFECT_FICKLE_BEAM); + ASSUME(GetMoveEffect(MOVE_FICKLE_BEAM) == EFFECT_FICKLE_BEAM); } SINGLE_BATTLE_TEST("Fickle Beam deals double damage 30% of the time") @@ -12,8 +12,8 @@ SINGLE_BATTLE_TEST("Fickle Beam deals double damage 30% of the time") PASSES_RANDOMLY(30, 100, RNG_FICKLE_BEAM); GIVEN { - ASSUME(gMovesInfo[MOVE_POWER_GEM].power == 80); - ASSUME(gMovesInfo[MOVE_FICKLE_BEAM].power == 80); + ASSUME(GetMovePower(MOVE_POWER_GEM) == 80); + ASSUME(GetMovePower(MOVE_FICKLE_BEAM) == 80); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/fillet_away.c b/test/battle/move_effect/fillet_away.c index de203dbc5a5b..f9b679bfe5bf 100644 --- a/test/battle/move_effect/fillet_away.c +++ b/test/battle/move_effect/fillet_away.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FILLET_AWAY].effect == EFFECT_FILLET_AWAY); + ASSUME(GetMoveEffect(MOVE_FILLET_AWAY) == EFFECT_FILLET_AWAY); } SINGLE_BATTLE_TEST("Fillet Away cuts the user's HP in half") diff --git a/test/battle/move_effect/fixed_damage_arg.c b/test/battle/move_effect/fixed_damage_arg.c index 1dae74e3f50c..8cb298707253 100644 --- a/test/battle/move_effect/fixed_damage_arg.c +++ b/test/battle/move_effect/fixed_damage_arg.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SONIC_BOOM].effect == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveEffect(MOVE_SONIC_BOOM) == EFFECT_FIXED_DAMAGE_ARG); } SINGLE_BATTLE_TEST("Sonic Boom deals fixed damage", s16 damage) @@ -13,7 +13,7 @@ SINGLE_BATTLE_TEST("Sonic Boom deals fixed damage", s16 damage) PARAMETRIZE { mon = SPECIES_ARON; } GIVEN { - ASSUME(gMovesInfo[MOVE_SONIC_BOOM].argument.fixedDamage == 20); + ASSUME(GetMoveFixedDamage(MOVE_SONIC_BOOM) == 20); PLAYER(SPECIES_WOBBUFFET); OPPONENT(mon); } WHEN { diff --git a/test/battle/move_effect/flame_burst.c b/test/battle/move_effect/flame_burst.c index 3597c8001450..df0199e11607 100644 --- a/test/battle/move_effect/flame_burst.c +++ b/test/battle/move_effect/flame_burst.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FLAME_BURST].additionalEffects->moveEffect == MOVE_EFFECT_FLAME_BURST); + ASSUME(GetMoveAdditionalEffectById(MOVE_FLAME_BURST, 0)->moveEffect == MOVE_EFFECT_FLAME_BURST); } // Flame Burst AoE is supposed to hit through Substitute DOUBLE_BATTLE_TEST("Flame Burst Substitute") { GIVEN { - ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE); + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c index 2bd1e824f1dd..b98020474b6d 100644 --- a/test/battle/move_effect/fling.c +++ b/test/battle/move_effect/fling.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING); + ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING); } SINGLE_BATTLE_TEST("Fling fails if pokemon holds no item") @@ -38,8 +38,8 @@ SINGLE_BATTLE_TEST("Fling fails if pokemon is under the effects of Embargo or Ma PARAMETRIZE {move = MOVE_MAGIC_ROOM; } GIVEN { - ASSUME(gMovesInfo[MOVE_EMBARGO].effect == EFFECT_EMBARGO); - ASSUME(gMovesInfo[MOVE_MAGIC_ROOM].effect == EFFECT_MAGIC_ROOM); + ASSUME(GetMoveEffect(MOVE_EMBARGO) == EFFECT_EMBARGO); + ASSUME(GetMoveEffect(MOVE_MAGIC_ROOM) == EFFECT_MAGIC_ROOM); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RAZOR_CLAW); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -83,7 +83,7 @@ SINGLE_BATTLE_TEST("Fling fails for pokemon with Klutz ability") SINGLE_BATTLE_TEST("Fling's thrown item can be regained with Recycle") { GIVEN { - ASSUME(gMovesInfo[MOVE_RECYCLE].effect == EFFECT_RECYCLE); + ASSUME(GetMoveEffect(MOVE_RECYCLE) == EFFECT_RECYCLE); PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_RAZOR_CLAW); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -106,7 +106,7 @@ SINGLE_BATTLE_TEST("Fling's thrown item can be regained with Recycle") SINGLE_BATTLE_TEST("Fling - Item is lost even when there is no target") { GIVEN { - ASSUME(gMovesInfo[MOVE_SELF_DESTRUCT].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_SELF_DESTRUCT) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_RAZOR_CLAW); Speed(2); } OPPONENT(SPECIES_WOBBUFFET) {Speed(5); } OPPONENT(SPECIES_WOBBUFFET) {Speed(5); } @@ -131,7 +131,7 @@ SINGLE_BATTLE_TEST("Fling - Item is lost even when there is no target") SINGLE_BATTLE_TEST("Fling - Item is lost when target protects itself") { GIVEN { - ASSUME(gMovesInfo[MOVE_PROTECT].effect == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); PLAYER(SPECIES_WOBBUFFET) {Item(ITEM_RAZOR_CLAW); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -362,7 +362,7 @@ SINGLE_BATTLE_TEST("Fling - thrown berry's effect activates for the target even PARAMETRIZE { item = ITEM_SALAC_BERRY; effect = HOLD_EFFECT_SPEED_UP; statId = STAT_SPEED; } GIVEN { - ASSUME(gMovesInfo[MOVE_FLING].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_FLING) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Item(item); Attack(1); } OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); HP(399); MaxHP(400); MovesWithPP({MOVE_CELEBRATE, 35}); } } WHEN { @@ -441,7 +441,7 @@ SINGLE_BATTLE_TEST("Fling deals damage based on items fling power") s16 damage[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_CRUNCH].power == 80); + ASSUME(GetMovePower(MOVE_CRUNCH) == 80); ASSUME(gItemsInfo[ITEM_VENUSAURITE].flingPower == 80); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_VENUSAURITE); } OPPONENT(SPECIES_REGIROCK); diff --git a/test/battle/move_effect/flower_shield.c b/test/battle/move_effect/flower_shield.c index e31fc9e5cd1a..784cce99f2c5 100644 --- a/test/battle/move_effect/flower_shield.c +++ b/test/battle/move_effect/flower_shield.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FLOWER_SHIELD].effect == EFFECT_FLOWER_SHIELD); + ASSUME(GetMoveEffect(MOVE_FLOWER_SHIELD) == EFFECT_FLOWER_SHIELD); } DOUBLE_BATTLE_TEST("Flower Shield raises the defense of all grass type pokemon") diff --git a/test/battle/move_effect/focus_punch.c b/test/battle/move_effect/focus_punch.c index e8f36d4ff13a..55854ee80e11 100644 --- a/test/battle/move_effect/focus_punch.c +++ b/test/battle/move_effect/focus_punch.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FOCUS_PUNCH].effect == EFFECT_FOCUS_PUNCH); + ASSUME(GetMoveEffect(MOVE_FOCUS_PUNCH) == EFFECT_FOCUS_PUNCH); } SINGLE_BATTLE_TEST("Focus Punch activates only if not damaged") diff --git a/test/battle/move_effect/foul_play.c b/test/battle/move_effect/foul_play.c index cc853b48de45..7df04201ef4e 100644 --- a/test/battle/move_effect/foul_play.c +++ b/test/battle/move_effect/foul_play.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FOUL_PLAY].effect == EFFECT_FOUL_PLAY); + ASSUME(GetMoveEffect(MOVE_FOUL_PLAY) == EFFECT_FOUL_PLAY); } SINGLE_BATTLE_TEST("Foul Play uses physical attack stat of target", s16 damage) @@ -14,8 +14,8 @@ SINGLE_BATTLE_TEST("Foul Play uses physical attack stat of target", s16 damage) PARAMETRIZE { move = MOVE_FOUL_PLAY; } GIVEN { - ASSUME(gMovesInfo[MOVE_HIGH_HORSEPOWER].power == gMovesInfo[MOVE_FOUL_PLAY].power); - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMovePower(MOVE_HIGH_HORSEPOWER) == GetMovePower(MOVE_FOUL_PLAY)); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_SHELLDER); OPPONENT(SPECIES_SHELLDER); } WHEN { diff --git a/test/battle/move_effect/fury_cutter.c b/test/battle/move_effect/fury_cutter.c index b193882d3702..10d9d8a64ed0 100644 --- a/test/battle/move_effect/fury_cutter.c +++ b/test/battle/move_effect/fury_cutter.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FURY_CUTTER].effect == EFFECT_FURY_CUTTER); + ASSUME(GetMoveEffect(MOVE_FURY_CUTTER) == EFFECT_FURY_CUTTER); } SINGLE_BATTLE_TEST("Fury Cutter power doubles with each use, up to 160 power") diff --git a/test/battle/move_effect/future_sight.c b/test/battle/move_effect/future_sight.c index e25fc750123e..3995e8479fb3 100644 --- a/test/battle/move_effect/future_sight.c +++ b/test/battle/move_effect/future_sight.c @@ -3,10 +3,10 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SEED_FLARE].power == gMovesInfo[MOVE_FUTURE_SIGHT].power); - ASSUME(gMovesInfo[MOVE_SEED_FLARE].category == gMovesInfo[MOVE_FUTURE_SIGHT].category); - ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].effect == EFFECT_FUTURE_SIGHT); - ASSUME(gMovesInfo[MOVE_FUTURE_SIGHT].power > 0); + ASSUME(GetMovePower(MOVE_SEED_FLARE) == GetMovePower(MOVE_FUTURE_SIGHT)); + ASSUME(GetMoveCategory(MOVE_SEED_FLARE) == GetMoveCategory(MOVE_FUTURE_SIGHT)); + ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT); + ASSUME(GetMovePower(MOVE_FUTURE_SIGHT) > 0); } SINGLE_BATTLE_TEST("Future Sight uses Sp. Atk stat of the original user without modifiers") @@ -159,7 +159,7 @@ SINGLE_BATTLE_TEST("Future Sight will miss timing if target faints by residual d SINGLE_BATTLE_TEST("Future Sight breaks Focus Sash and doesn't make the holder endure another move") { GIVEN { - ASSUME(gMovesInfo[MOVE_PSYCHIC].power > 0); + ASSUME(GetMovePower(MOVE_PSYCHIC) > 0); ASSUME(gItemsInfo[ITEM_FOCUS_SASH].holdEffect == HOLD_EFFECT_FOCUS_SASH); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_PIDGEY) { Level(1); Item(ITEM_FOCUS_SASH); } diff --git a/test/battle/move_effect/gastro_acid.c b/test/battle/move_effect/gastro_acid.c index b3ce3787948d..8cb0a7d4af90 100644 --- a/test/battle/move_effect/gastro_acid.c +++ b/test/battle/move_effect/gastro_acid.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_GASTRO_ACID].effect == EFFECT_GASTRO_ACID); + ASSUME(GetMoveEffect(MOVE_GASTRO_ACID) == EFFECT_GASTRO_ACID); } SINGLE_BATTLE_TEST("Gastro Acid fails if target has a banned ability") diff --git a/test/battle/move_effect/glaive_rush.c b/test/battle/move_effect/glaive_rush.c index 639756da44a7..bb5bb7aaf6a9 100644 --- a/test/battle/move_effect/glaive_rush.c +++ b/test/battle/move_effect/glaive_rush.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_GLAIVE_RUSH].effect == EFFECT_GLAIVE_RUSH); + ASSUME(GetMoveEffect(MOVE_GLAIVE_RUSH) == EFFECT_GLAIVE_RUSH); } SINGLE_BATTLE_TEST("If Glaive Rush is successful moves targeted at the user do not check accuracy") { PASSES_RANDOMLY(100, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_MEGA_PUNCH].accuracy == 85); + ASSUME(GetMoveAccuracy(MOVE_MEGA_PUNCH) == 85); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/terrain/grassy.c b/test/battle/move_effect/grassy_terrain.c similarity index 80% rename from test/battle/terrain/grassy.c rename to test/battle/move_effect/grassy_terrain.c index b247933dd2f1..90e878b6dd4a 100644 --- a/test/battle/terrain/grassy.c +++ b/test/battle/move_effect/grassy_terrain.c @@ -18,25 +18,6 @@ SINGLE_BATTLE_TEST("Grassy Terrain recovers 1/16th HP at end of turn") } } -SINGLE_BATTLE_TEST("Grassy Terrain activates Grassy Seed and Mimicry") -{ - GIVEN { - ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffect == HOLD_EFFECT_SEEDS); - ASSUME(gItemsInfo[ITEM_GRASSY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_GRASSY_TERRAIN); - PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_GRASSY_SEED); } - OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } - } WHEN { - TURN { MOVE(player, MOVE_GRASSY_TERRAIN); } - } SCENE { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Using Grassy Seed, the Defense of Wobbuffet rose!"); - ABILITY_POPUP(opponent); - MESSAGE("The opposing Stunfisk's type changed to Grass!"); - } THEN { - EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[0], TYPE_GRASS); - } -} - SINGLE_BATTLE_TEST("Grassy Terrain increases power of Grass-type moves by 30/50 percent", s16 damage) { bool32 terrain; diff --git a/test/battle/move_effect/gravity.c b/test/battle/move_effect/gravity.c index 4ccad08b5857..baac7a53eaf8 100644 --- a/test/battle/move_effect/gravity.c +++ b/test/battle/move_effect/gravity.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_GRAVITY].effect == EFFECT_GRAVITY); + ASSUME(GetMoveEffect(MOVE_GRAVITY) == EFFECT_GRAVITY); } DOUBLE_BATTLE_TEST("Gravity cancels fly and sky drop if they are in the air") diff --git a/test/battle/move_effect/guard_split.c b/test/battle/move_effect/guard_split.c index 3f012ab6e2e4..d7572c1431f8 100644 --- a/test/battle/move_effect/guard_split.c +++ b/test/battle/move_effect/guard_split.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_GUARD_SPLIT].effect == EFFECT_GUARD_SPLIT); + ASSUME(GetMoveEffect(MOVE_GUARD_SPLIT) == EFFECT_GUARD_SPLIT); } SINGLE_BATTLE_TEST("Guard Split averages users and targets Def and Sp. Def stats") diff --git a/test/battle/move_effect/haze.c b/test/battle/move_effect/haze.c index 0b28268ae929..3d0602bb73fe 100644 --- a/test/battle/move_effect/haze.c +++ b/test/battle/move_effect/haze.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HAZE].effect == EFFECT_HAZE); + ASSUME(GetMoveEffect(MOVE_HAZE) == EFFECT_HAZE); } SINGLE_BATTLE_TEST("Haze resets stat changes", s16 damage) @@ -12,8 +12,8 @@ SINGLE_BATTLE_TEST("Haze resets stat changes", s16 damage) PARAMETRIZE { haze = FALSE; } PARAMETRIZE { haze = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_MEDITATE].effect == EFFECT_ATTACK_UP); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveEffect(MOVE_MEDITATE) == EFFECT_ATTACK_UP); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/heal_bell.c b/test/battle/move_effect/heal_bell.c index 9b62a36f9be2..5c87171056b4 100644 --- a/test/battle/move_effect/heal_bell.c +++ b/test/battle/move_effect/heal_bell.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); - ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_HEAL_BELL) == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL); } DOUBLE_BATTLE_TEST("Heal Bell cures the entire party") diff --git a/test/battle/move_effect/heal_pulse.c b/test/battle/move_effect/heal_pulse.c index 95a2d75195ee..7c46cbf3448a 100644 --- a/test/battle/move_effect/heal_pulse.c +++ b/test/battle/move_effect/heal_pulse.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HEAL_PULSE].effect == EFFECT_HEAL_PULSE); + ASSUME(GetMoveEffect(MOVE_HEAL_PULSE) == EFFECT_HEAL_PULSE); } SINGLE_BATTLE_TEST("Heal Pulse heals the target by 1/2 of it's maxHP") @@ -68,7 +68,7 @@ SINGLE_BATTLE_TEST("Heal Pulse ignores accurace checks") SINGLE_BATTLE_TEST("Heal Pulse is blocked by Substitute") { GIVEN { - ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE); + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(50); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -86,8 +86,8 @@ SINGLE_BATTLE_TEST("Heal Pulse is blocked by Substitute") SINGLE_BATTLE_TEST("Floral Healing heals the target by 2/3rd of it's maxHP if Grassy Terrain is on the field") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLORAL_HEALING].argument.moveProperty == MOVE_EFFECT_FLORAL_HEALING); - ASSUME(gMovesInfo[MOVE_GRASSY_TERRAIN].effect == EFFECT_GRASSY_TERRAIN); + ASSUME(GetMoveEffectArg_MoveProperty(MOVE_FLORAL_HEALING) == MOVE_EFFECT_FLORAL_HEALING); + ASSUME(GetMoveEffect(MOVE_GRASSY_TERRAIN) == EFFECT_GRASSY_TERRAIN); PLAYER(SPECIES_WOBBUFFET) { MaxHP(100); HP(1); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/healing_wish.c b/test/battle/move_effect/healing_wish.c index a597d552ed5e..a29b04367cb1 100644 --- a/test/battle/move_effect/healing_wish.c +++ b/test/battle/move_effect/healing_wish.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HEALING_WISH].effect == EFFECT_HEALING_WISH); - ASSUME(gMovesInfo[MOVE_LUNAR_DANCE].effect == EFFECT_HEALING_WISH); + ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH); + ASSUME(GetMoveEffect(MOVE_LUNAR_DANCE) == EFFECT_HEALING_WISH); } SINGLE_BATTLE_TEST("Healing Wish causes the user to faint and fully heals the replacement") diff --git a/test/battle/move_effect/hidden_power.c b/test/battle/move_effect/hidden_power.c index 8ec63c21a7ec..7f2bb5f2b986 100644 --- a/test/battle/move_effect/hidden_power.c +++ b/test/battle/move_effect/hidden_power.c @@ -1,80 +1,107 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(gTypesInfo[TYPE_NONE].isHiddenPowerType == FALSE); + ASSUME(gTypesInfo[TYPE_NORMAL].isHiddenPowerType == FALSE); + ASSUME(gTypesInfo[TYPE_FIGHTING].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_FLYING].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_POISON].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_GROUND].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_ROCK].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_BUG].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_GHOST].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_STEEL].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_MYSTERY].isHiddenPowerType == FALSE); + ASSUME(gTypesInfo[TYPE_FIRE].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_WATER].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_GRASS].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_ELECTRIC].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_PSYCHIC].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_ICE].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_DRAGON].isHiddenPowerType == TRUE); + ASSUME(gTypesInfo[TYPE_DARK].isHiddenPowerType == TRUE); + // Any type after Dark shouldn't be part of Hidden Power officially. + for (u32 j = TYPE_DARK + 1; j < NUMBER_OF_MON_TYPES; j++) { + ASSUME(gTypesInfo[j].isHiddenPowerType == FALSE); + } +} + // IV combinations sourced from https://www.smogon.com/forums/threads/hidden-power-iv-combinations.78083/ SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs") { - u32 type, j, foeType, foeSpecies; + u32 type, j, foeType, foeSpecies, foeItem; u32 hp, atk, def, spAtk, spDef, speed; bool32 hidden; PARAMETRIZE { type = TYPE_NONE; hidden = FALSE; } PARAMETRIZE { type = TYPE_NORMAL; hidden = FALSE; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_REGISTEEL; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_ARBOK; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 30; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 31; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_BLASTOISE; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 30; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FIGHTING; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_CHOPLE_BERRY; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_FLYING; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_COBA_BERRY; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_POISON; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_KEBIA_BERRY; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GROUND; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; foeItem = ITEM_SHUCA_BERRY; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_ROCK; hidden = TRUE; foeType = TYPE_FIRE; foeSpecies = SPECIES_VULPIX; foeItem = ITEM_CHARTI_BERRY; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_BUG; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; foeItem = ITEM_TANGA_BERRY; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 30; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 15; def = 30; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_GHOST; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_KASIB_BERRY; hp = 31; atk = 31; def = 30; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_STEEL; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_BABIRI_BERRY; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 30; speed = 31; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 15; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_FIRE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_OCCA_BERRY; hp = 31; atk = 31; def = 30; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 2; def = 30; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 22; def = 30; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_WATER; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_PASSHO_BERRY; hp = 31; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 2; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 15; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 22; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_GRASS; hidden = TRUE; foeType = TYPE_ROCK; foeSpecies = SPECIES_NOSEPASS; foeItem = ITEM_RINDO_BERRY; hp = 30; atk = 31; def = 31; spAtk = 30; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 31; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 31; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ELECTRIC; hidden = TRUE; foeType = TYPE_WATER; foeSpecies = SPECIES_SQUIRTLE; foeItem = ITEM_WACAN_BERRY; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 31; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 31; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_PSYCHIC; hidden = TRUE; foeType = TYPE_POISON; foeSpecies = SPECIES_KOFFING; foeItem = ITEM_PAYAPA_BERRY; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 30; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 2; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 15; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 22; def = 30; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_ICE; hidden = TRUE; foeType = TYPE_GRASS; foeSpecies = SPECIES_TANGELA; foeItem = ITEM_YACHE_BERRY; hp = 30; atk = 31; def = 30; spAtk = 31; spDef = 31; speed = 31; } PARAMETRIZE { type = TYPE_MYSTERY; hidden = FALSE; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_STEEL; foeSpecies = SPECIES_KLINK; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 3; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 23; def = 31; spAtk = 31; spDef = 31; speed = 31; } - PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_DARK; foeSpecies = SPECIES_UMBREON; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 2; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 22; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DRAGON; hidden = TRUE; foeType = TYPE_DRAGON; foeSpecies = SPECIES_DRATINI; foeItem = ITEM_HABAN_BERRY; hp = 30; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 3; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 15; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 23; def = 31; spAtk = 31; spDef = 31; speed = 31; } + PARAMETRIZE { type = TYPE_DARK; hidden = TRUE; foeType = TYPE_PSYCHIC; foeSpecies = SPECIES_WOBBUFFET; foeItem = ITEM_COLBUR_BERRY; hp = 31; atk = 31; def = 31; spAtk = 31; spDef = 31; speed = 31; } // Any type after Dark shouldn't be part of Hidden Power officially. for (j = TYPE_DARK + 1; j < NUMBER_OF_MON_TYPES; j++) { @@ -83,22 +110,25 @@ SINGLE_BATTLE_TEST("Hidden Power's type is determined by IVs") GIVEN { if (hidden) { - ASSUME(gTypeEffectivenessTable[type][foeType] == UQ_4_12(0.5)); // Foe's Type resists + ASSUME(gTypeEffectivenessTable[type][foeType] == UQ_4_12(2.0)); // Foe's Type resists ASSUME(gSpeciesInfo[foeSpecies].types[0] == gSpeciesInfo[foeSpecies].types[1]); // Foe's pure type - ASSUME(gSpeciesInfo[foeSpecies].types[0] == foeType); // Foe is the resisted type + ASSUME(gSpeciesInfo[foeSpecies].types[0] == foeType); // Foe is the super-effective type + ASSUME(ItemId_GetHoldEffect(foeItem) == HOLD_EFFECT_RESIST_BERRY); // Item is resist berry + ASSUME(ItemId_GetHoldEffectParam(foeItem) == type); // Resist berry of type PLAYER(SPECIES_DUNSPARCE) { HPIV(hp); AttackIV(atk); DefenseIV(def); SpAttackIV(spAtk); SpDefenseIV(spDef); SpeedIV(speed); } } else { PLAYER(SPECIES_DUNSPARCE); } - OPPONENT(foeSpecies); + OPPONENT(foeSpecies) { Item(foeItem); } } WHEN { TURN { MOVE(player, MOVE_HIDDEN_POWER); } } SCENE { // Only test valid Hidden Power types if (hidden) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); // Check that the item is triggered ANIMATION(ANIM_TYPE_MOVE, MOVE_HIDDEN_POWER, player); HP_BAR(opponent); - MESSAGE("It's not very effective…"); + MESSAGE("It's super effective!"); } } } diff --git a/test/battle/move_effect/hit_escape.c b/test/battle/move_effect/hit_escape.c index 0a494cc667d4..83280f9f508c 100644 --- a/test/battle/move_effect/hit_escape.c +++ b/test/battle/move_effect/hit_escape.c @@ -3,10 +3,10 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); } -SINGLE_BATTLE_TEST("U-turn switches the user out") +SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -21,7 +21,7 @@ SINGLE_BATTLE_TEST("U-turn switches the user out") } } -SINGLE_BATTLE_TEST("U-turn does not switch the user out if the battle ends") +SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if the battle ends") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if the battle ends") } } -SINGLE_BATTLE_TEST("U-turn does not switch the user out if no replacements") +SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if no replacements") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -48,7 +48,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if no replacements") } } -SINGLE_BATTLE_TEST("U-turn does not switch the user out if replacements fainted") +SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if replacements fainted") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if replacements fainted" } } -SINGLE_BATTLE_TEST("U-turn does not switch the user out if Wimp Out activates") +SINGLE_BATTLE_TEST("Hit Escape: U-turn does not switch the user out if Wimp Out activates") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -79,7 +79,7 @@ SINGLE_BATTLE_TEST("U-turn does not switch the user out if Wimp Out activates") } } -SINGLE_BATTLE_TEST("U-turn switches the user out if Wimp Out fails to activate") +SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out if Wimp Out fails to activate") { GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -95,10 +95,10 @@ SINGLE_BATTLE_TEST("U-turn switches the user out if Wimp Out fails to activate") } } -SINGLE_BATTLE_TEST("U-turn switches the user out after Ice Face activates") +SINGLE_BATTLE_TEST("Hit Escape: U-turn switches the user out after Ice Face activates") { GIVEN { - ASSUME(gMovesInfo[MOVE_U_TURN].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_U_TURN) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_BEEDRILL); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_EISCUE) { Ability(ABILITY_ICE_FACE); } @@ -113,7 +113,7 @@ SINGLE_BATTLE_TEST("U-turn switches the user out after Ice Face activates") } } -SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: player side") +SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: player side") { GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; @@ -136,7 +136,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in } } -SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") +SINGLE_BATTLE_TEST("Hit Escape: Held items are consumed immediately after a mon switched in by U-turn and Intimidate activates after it: opposing side") { GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; @@ -159,7 +159,7 @@ SINGLE_BATTLE_TEST("Held items are consumed immediately after a mon switched in } } -SINGLE_BATTLE_TEST("Electric Seed boost is received by the right pokemon after U-turn and Intimidate") +SINGLE_BATTLE_TEST("Hit Escape: Electric Seed boost is received by the right pokemon after U-turn and Intimidate") { GIVEN { PLAYER(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); }; diff --git a/test/battle/move_effect/hit_set_remove_terrain.c b/test/battle/move_effect/hit_set_remove_terrain.c index a48d316d3f6a..9b9180d6e4a1 100644 --- a/test/battle/move_effect/hit_set_remove_terrain.c +++ b/test/battle/move_effect/hit_set_remove_terrain.c @@ -3,12 +3,12 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ELECTRIC_TERRAIN].effect == EFFECT_ELECTRIC_TERRAIN); - ASSUME(gMovesInfo[MOVE_PSYCHIC_TERRAIN].effect == EFFECT_PSYCHIC_TERRAIN); - ASSUME(gMovesInfo[MOVE_GRASSY_TERRAIN].effect == EFFECT_GRASSY_TERRAIN); - ASSUME(gMovesInfo[MOVE_MISTY_TERRAIN].effect == EFFECT_MISTY_TERRAIN); - ASSUME(gMovesInfo[MOVE_STEEL_ROLLER].effect == EFFECT_HIT_SET_REMOVE_TERRAIN); - ASSUME(gMovesInfo[MOVE_ICE_SPINNER].effect == EFFECT_HIT_SET_REMOVE_TERRAIN); + ASSUME(GetMoveEffect(MOVE_ELECTRIC_TERRAIN) == EFFECT_ELECTRIC_TERRAIN); + ASSUME(GetMoveEffect(MOVE_PSYCHIC_TERRAIN) == EFFECT_PSYCHIC_TERRAIN); + ASSUME(GetMoveEffect(MOVE_GRASSY_TERRAIN) == EFFECT_GRASSY_TERRAIN); + ASSUME(GetMoveEffect(MOVE_MISTY_TERRAIN) == EFFECT_MISTY_TERRAIN); + ASSUME(GetMoveEffect(MOVE_STEEL_ROLLER) == EFFECT_HIT_SET_REMOVE_TERRAIN); + ASSUME(GetMoveEffect(MOVE_ICE_SPINNER) == EFFECT_HIT_SET_REMOVE_TERRAIN); } SINGLE_BATTLE_TEST("Steel Roller and Ice Spinner can remove a terrain from the field") @@ -83,7 +83,7 @@ SINGLE_BATTLE_TEST("Ice Spinner doesn't fail if there is no terrain on the field } } -AI_SINGLE_BATTLE_TEST("Steel Roller will not be chosen by the AI if it might fail") +AI_SINGLE_BATTLE_TEST("AI will not choose Steel Roller if it might fail") { u32 move; @@ -104,7 +104,7 @@ AI_SINGLE_BATTLE_TEST("Steel Roller will not be chosen by the AI if it might fai } } -AI_SINGLE_BATTLE_TEST("Ice Spinner can be chosen by the AI regardless if there is a terrain or not") +AI_SINGLE_BATTLE_TEST("AI will can choose Ice Spinner regardless if there is a terrain or not") { u32 move; @@ -124,35 +124,3 @@ AI_SINGLE_BATTLE_TEST("Ice Spinner can be chosen by the AI regardless if there i } } } - -SINGLE_BATTLE_TEST("Steel Roller and Ice Spinner reverts typing on Mimicry users") -{ - u32 j; - static const u16 terrainMoves[] = - { - MOVE_ELECTRIC_TERRAIN, - MOVE_PSYCHIC_TERRAIN, - MOVE_GRASSY_TERRAIN, - MOVE_MISTY_TERRAIN, - }; - - u16 terrainMove = MOVE_NONE; - u16 removeTerrainMove = MOVE_NONE; - - for (j = 0; j < ARRAY_COUNT(terrainMoves); j++) - { - PARAMETRIZE { removeTerrainMove = MOVE_STEEL_ROLLER; terrainMove = terrainMoves[j]; } - PARAMETRIZE { removeTerrainMove = MOVE_ICE_SPINNER; terrainMove = terrainMoves[j]; } - } - - GIVEN { - ASSUME(gSpeciesInfo[SPECIES_STUNFISK_GALAR].types[1] == TYPE_STEEL); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } - } WHEN { - TURN { MOVE(opponent, terrainMove); MOVE(player, removeTerrainMove); } - TURN { MOVE(player, MOVE_TOXIC); } - } SCENE { - MESSAGE("It doesn't affect the opposing Stunfisk…"); - } -} diff --git a/test/battle/move_effect/hit_switch_target.c b/test/battle/move_effect/hit_switch_target.c index a899ae0b33fe..5a6e480f9374 100644 --- a/test/battle/move_effect/hit_switch_target.c +++ b/test/battle/move_effect/hit_switch_target.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET); - ASSUME(gMovesInfo[MOVE_LOCK_ON].effect == EFFECT_LOCK_ON); + ASSUME(GetMoveEffect(MOVE_DRAGON_TAIL) == EFFECT_HIT_SWITCH_TARGET); + ASSUME(GetMoveEffect(MOVE_LOCK_ON) == EFFECT_LOCK_ON); } SINGLE_BATTLE_TEST("Dragon Tail switches the target with a random non-fainted replacement") diff --git a/test/battle/move_effect/hold_hands.c b/test/battle/move_effect/hold_hands.c index bcdb6a952af5..fb1c498bd3f1 100644 --- a/test/battle/move_effect/hold_hands.c +++ b/test/battle/move_effect/hold_hands.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HOLD_HANDS].effect == EFFECT_HOLD_HANDS); + ASSUME(GetMoveEffect(MOVE_HOLD_HANDS) == EFFECT_HOLD_HANDS); } DOUBLE_BATTLE_TEST("Hold Hands is blocked by Crafty Shield") diff --git a/test/battle/move_effect/hydro_steam.c b/test/battle/move_effect/hydro_steam.c index a9c14c9acbba..cb19cc6ec128 100644 --- a/test/battle/move_effect/hydro_steam.c +++ b/test/battle/move_effect/hydro_steam.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HYDRO_STEAM].effect == EFFECT_HYDRO_STEAM); + ASSUME(GetMoveEffect(MOVE_HYDRO_STEAM) == EFFECT_HYDRO_STEAM); } SINGLE_BATTLE_TEST("Hydro Steam deals 1.5x damage under both Sunlight and Rain", s16 damage) diff --git a/test/battle/move_effect/instruct.c b/test/battle/move_effect/instruct.c index 59772ea944a8..248370cd6a49 100644 --- a/test/battle/move_effect/instruct.c +++ b/test/battle/move_effect/instruct.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_INSTRUCT].effect == EFFECT_INSTRUCT); + ASSUME(GetMoveEffect(MOVE_INSTRUCT) == EFFECT_INSTRUCT); } DOUBLE_BATTLE_TEST("Instruct fails if target hasn't made a move") @@ -24,7 +24,7 @@ DOUBLE_BATTLE_TEST("Instruct fails if target hasn't made a move") DOUBLE_BATTLE_TEST("Instruct fails if move is banned by Instruct") { GIVEN { - ASSUME(gMovesInfo[MOVE_BIDE].instructBanned == TRUE); + ASSUME(IsMoveInstructBanned(MOVE_BIDE)); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_BIDE); } OPPONENT(SPECIES_WOBBUFFET); @@ -60,7 +60,7 @@ DOUBLE_BATTLE_TEST("Instruct-called move targets the target of the move picked o DOUBLE_BATTLE_TEST("Instruct doesn't bypass sleep") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_GROWL); } OPPONENT(SPECIES_WOBBUFFET); @@ -79,7 +79,7 @@ DOUBLE_BATTLE_TEST("Instruct doesn't bypass sleep") DOUBLE_BATTLE_TEST("Instruct fails if target doesn't know the last move it used") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_DANCE].danceMove == TRUE); + ASSUME(IsDanceMove(MOVE_DRAGON_DANCE)); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_ORICORIO) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); @@ -100,7 +100,7 @@ DOUBLE_BATTLE_TEST("Instruct fails if target doesn't know the last move it used" DOUBLE_BATTLE_TEST("Instruct-called move fails if it can only be used on the first turn but consumes PP") { GIVEN { - ASSUME(gMovesInfo[MOVE_FAKE_OUT].effect == EFFECT_FIRST_TURN_ONLY); + ASSUME(GetMoveEffect(MOVE_FAKE_OUT) == EFFECT_FIRST_TURN_ONLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_FAKE_OUT); } OPPONENT(SPECIES_WOBBUFFET); @@ -112,14 +112,14 @@ DOUBLE_BATTLE_TEST("Instruct-called move fails if it can only be used on the fir ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerLeft); NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_FAKE_OUT, playerRight); } THEN { - EXPECT_EQ(playerRight->pp[3], gMovesInfo[MOVE_FAKE_OUT].pp - 2); + EXPECT_EQ(playerRight->pp[3], GetMovePP(MOVE_FAKE_OUT) - 2); } } DOUBLE_BATTLE_TEST("Instruct-called move doesn't fail if tormented") { GIVEN { - ASSUME(gMovesInfo[MOVE_TORMENT].effect == EFFECT_TORMENT); + ASSUME(GetMoveEffect(MOVE_TORMENT) == EFFECT_TORMENT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_FAKE_OUT); } OPPONENT(SPECIES_WOBBUFFET); @@ -138,7 +138,7 @@ DOUBLE_BATTLE_TEST("Instruct-called status moves don't fail if holding Assault V { GIVEN { ASSUME(gItemsInfo[ITEM_ASSAULT_VEST].holdEffect == HOLD_EFFECT_ASSAULT_VEST); - ASSUME(gMovesInfo[MOVE_TRICK].effect == EFFECT_TRICK); + ASSUME(GetMoveEffect(MOVE_TRICK) == EFFECT_TRICK); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_TRICK); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_ASSAULT_VEST); } @@ -155,7 +155,7 @@ DOUBLE_BATTLE_TEST("Instruct-called status moves don't fail if holding Assault V DOUBLE_BATTLE_TEST("Instruct-called status move fails if taunted") { GIVEN { - ASSUME(gMovesInfo[MOVE_TAUNT].effect == EFFECT_TAUNT); + ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_GROWL); } OPPONENT(SPECIES_WOBBUFFET); @@ -174,14 +174,14 @@ DOUBLE_BATTLE_TEST("Instruct-called status move fails if taunted") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); } } THEN { - EXPECT_EQ(playerRight->pp[3], gMovesInfo[MOVE_GROWL].pp - 1); + EXPECT_EQ(playerRight->pp[3], GetMovePP(MOVE_GROWL) - 1); } } DOUBLE_BATTLE_TEST("Instruct-called moves fail if disabled") { GIVEN { - ASSUME(gMovesInfo[MOVE_DISABLE].effect == EFFECT_DISABLE); + ASSUME(GetMoveEffect(MOVE_DISABLE) == EFFECT_DISABLE); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_GROWL); } OPPONENT(SPECIES_WOBBUFFET); @@ -194,15 +194,15 @@ DOUBLE_BATTLE_TEST("Instruct-called moves fail if disabled") ANIMATION(ANIM_TYPE_MOVE, MOVE_INSTRUCT, playerLeft); NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); } THEN { - EXPECT_EQ(playerRight->pp[0], gMovesInfo[MOVE_TACKLE].pp - 1); + EXPECT_EQ(playerRight->pp[0], GetMovePP(MOVE_TACKLE) - 1); } } DOUBLE_BATTLE_TEST("Instruct-called moves keep their priority") { GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); - ASSUME(gMovesInfo[MOVE_PSYCHIC_TERRAIN].effect == EFFECT_PSYCHIC_TERRAIN); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); + ASSUME(GetMoveEffect(MOVE_PSYCHIC_TERRAIN) == EFFECT_PSYCHIC_TERRAIN); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH, MOVE_QUICK_ATTACK); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/ion_deluge.c b/test/battle/move_effect/ion_deluge.c index d0862ee8b441..8147048527d0 100644 --- a/test/battle/move_effect/ion_deluge.c +++ b/test/battle/move_effect/ion_deluge.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ION_DELUGE].effect == EFFECT_ION_DELUGE); + ASSUME(GetMoveEffect(MOVE_ION_DELUGE) == EFFECT_ION_DELUGE); } // For some reason SINGLE_BATTLE_TEST didn't catch these two issues. @@ -51,7 +51,7 @@ WILD_BATTLE_TEST("Ion Deluge works the same way as always when used by a mon wit SINGLE_BATTLE_TEST("Ion Deluge makes Normal type moves Electric type") { GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TACKLE) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GOLBAT); } WHEN { diff --git a/test/battle/move_effect/ivy_cudgel.c b/test/battle/move_effect/ivy_cudgel.c index 095f4d8eff11..88d002ae3500 100644 --- a/test/battle/move_effect/ivy_cudgel.c +++ b/test/battle/move_effect/ivy_cudgel.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_IVY_CUDGEL].effect == EFFECT_IVY_CUDGEL); + ASSUME(GetMoveEffect(MOVE_IVY_CUDGEL) == EFFECT_IVY_CUDGEL); } SINGLE_BATTLE_TEST("Ivy Cudgel changes the move type depending on the form of Ogerpon") diff --git a/test/battle/move_effect/knock_off.c b/test/battle/move_effect/knock_off.c index 61bb062a2540..4eb12697170a 100644 --- a/test/battle/move_effect/knock_off.c +++ b/test/battle/move_effect/knock_off.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF); + ASSUME(GetMoveEffect(MOVE_KNOCK_OFF) == EFFECT_KNOCK_OFF); } SINGLE_BATTLE_TEST("Knock Off knocks a healing berry before it has the chance to activate") diff --git a/test/battle/move_effect/last_resort.c b/test/battle/move_effect/last_resort.c index a9660f2c0e42..50a0a315127a 100644 --- a/test/battle/move_effect/last_resort.c +++ b/test/battle/move_effect/last_resort.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_LAST_RESORT].effect == EFFECT_LAST_RESORT); + ASSUME(GetMoveEffect(MOVE_LAST_RESORT) == EFFECT_LAST_RESORT); } SINGLE_BATTLE_TEST("Last Resort always fails if it's the only known move") @@ -95,7 +95,7 @@ SINGLE_BATTLE_TEST("Last Resort works only when all of the known moves have been SINGLE_BATTLE_TEST("Last Resort works with Sleep Talk") { GIVEN { - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_LAST_RESORT, MOVE_SLEEP_TALK); Status1(STATUS1_SLEEP_TURN(3)); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/last_respects.c b/test/battle/move_effect/last_respects.c index 9b1f01f5fc9b..6ef4c73c2d81 100644 --- a/test/battle/move_effect/last_respects.c +++ b/test/battle/move_effect/last_respects.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_LAST_RESPECTS].effect == EFFECT_LAST_RESPECTS); + ASSUME(GetMoveEffect(MOVE_LAST_RESPECTS) == EFFECT_LAST_RESPECTS); } SINGLE_BATTLE_TEST("Last Respects power is multiplied by the amount of fainted mon in the user's side - Player", s16 damage) diff --git a/test/battle/move_effect/leech_seed.c b/test/battle/move_effect/leech_seed.c index 67e829cf8ad4..d363e9800982 100644 --- a/test/battle/move_effect/leech_seed.c +++ b/test/battle/move_effect/leech_seed.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_LEECH_SEED].effect == EFFECT_LEECH_SEED); + ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED); } SINGLE_BATTLE_TEST("Leech Seed doesn't affect Grass-type Pokémon") @@ -58,25 +58,6 @@ SINGLE_BATTLE_TEST("Leech Seed recovery is prevented by Heal Block") } } -SINGLE_BATTLE_TEST("Leech Seed recovery will drain the hp of user if leech seeded mon has Liquid Ooze") -{ - s16 damage; - s16 healed; - - GIVEN { - PLAYER(SPECIES_WYNAUT); - OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); } - } WHEN { - TURN { MOVE(player, MOVE_LEECH_SEED); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_LEECH_SEED, player); - HP_BAR(opponent, captureDamage: &damage); - HP_BAR(player, captureDamage: &healed); - } THEN { - EXPECT_EQ(damage, healed); - } -} - TO_DO_BATTLE_TEST("Leech Seed doesn't affect already seeded targets") TO_DO_BATTLE_TEST("Leech Seed's effect is paused until a new battler replaces the original user's position") // Faint, can't be replaced, then revived. TO_DO_BATTLE_TEST("Leech Seed's effect pause still prevents it from being seeded again") diff --git a/test/battle/move_effect/magic_coat.c b/test/battle/move_effect/magic_coat.c index 2e78967f3987..561d15a53230 100644 --- a/test/battle/move_effect/magic_coat.c +++ b/test/battle/move_effect/magic_coat.c @@ -3,13 +3,13 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); } SINGLE_BATTLE_TEST("Magic Coat prints the correct message when bouncing back a move") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_WYNAUT); } WHEN { diff --git a/test/battle/move_effect/max_hp_50_recoil.c b/test/battle/move_effect/max_hp_50_recoil.c index b35043014b35..3e54e05532cc 100644 --- a/test/battle/move_effect/max_hp_50_recoil.c +++ b/test/battle/move_effect/max_hp_50_recoil.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STEEL_BEAM].effect == EFFECT_MAX_HP_50_RECOIL); + ASSUME(GetMoveEffect(MOVE_STEEL_BEAM) == EFFECT_MAX_HP_50_RECOIL); } SINGLE_BATTLE_TEST("Steel Beam makes the user lose 1/2 of its Max HP") diff --git a/test/battle/move_effect/metronome.c b/test/battle/move_effect/metronome.c index 98e4bfd6187c..1a5d4aeb9d60 100644 --- a/test/battle/move_effect/metronome.c +++ b/test/battle/move_effect/metronome.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_METRONOME].effect == EFFECT_METRONOME); + ASSUME(GetMoveEffect(MOVE_METRONOME) == EFFECT_METRONOME); } SINGLE_BATTLE_TEST("Metronome picks a random move") @@ -25,9 +25,9 @@ SINGLE_BATTLE_TEST("Metronome picks a random move") SINGLE_BATTLE_TEST("Metronome's called powder move fails against Grass Types") { GIVEN { - ASSUME(gMovesInfo[MOVE_POISON_POWDER].powderMove); + ASSUME(IsPowderMove(MOVE_POISON_POWDER)); ASSUME(gSpeciesInfo[SPECIES_TANGELA].types[0] == TYPE_GRASS); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TANGELA); } WHEN { @@ -45,7 +45,7 @@ SINGLE_BATTLE_TEST("Metronome's called powder move fails against Grass Types") SINGLE_BATTLE_TEST("Metronome's called multi-hit move hits multiple times") { GIVEN { - ASSUME(gMovesInfo[MOVE_ROCK_BLAST].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_ROCK_BLAST) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/mind_blown.c b/test/battle/move_effect/mind_blown.c index 85e6a8fdbdd9..0a3419877773 100644 --- a/test/battle/move_effect/mind_blown.c +++ b/test/battle/move_effect/mind_blown.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_MIND_BLOWN].effect == EFFECT_MIND_BLOWN); + ASSUME(GetMoveEffect(MOVE_MIND_BLOWN) == EFFECT_MIND_BLOWN); } SINGLE_BATTLE_TEST("Mind Blown makes the user lose 1/2 of its Max HP") @@ -154,7 +154,7 @@ SINGLE_BATTLE_TEST("Mind Blown makes the user lose HP even if the opposing mon p SINGLE_BATTLE_TEST("Mind Blown makes the user lose HP even if it is absorbed by Flash Fire") { GIVEN { - ASSUME(gMovesInfo[MOVE_MIND_BLOWN].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_MIND_BLOWN) == TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_CYNDAQUIL) { Ability(ABILITY_FLASH_FIRE); } } WHEN { diff --git a/test/battle/move_effect/mirror_move.c b/test/battle/move_effect/mirror_move.c index 65c600fb1878..cc148eb97cef 100644 --- a/test/battle/move_effect/mirror_move.c +++ b/test/battle/move_effect/mirror_move.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_MIRROR_MOVE].effect == EFFECT_MIRROR_MOVE); + ASSUME(GetMoveEffect(MOVE_MIRROR_MOVE) == EFFECT_MIRROR_MOVE); } SINGLE_BATTLE_TEST("Mirror Move copies the last used move by the target") @@ -41,9 +41,9 @@ SINGLE_BATTLE_TEST("Mirror Move fails if no move was used before") SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove); + ASSUME(IsPowderMove(MOVE_STUN_SPORE)); ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS); - ASSUME(gMovesInfo[MOVE_STUN_SPORE].effect == EFFECT_PARALYZE); + ASSUME(GetMoveEffect(MOVE_STUN_SPORE) == EFFECT_PARALYZE); PLAYER(SPECIES_ODDISH); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -62,7 +62,7 @@ SINGLE_BATTLE_TEST("Mirror Move's called powder move fails against Grass Types") SINGLE_BATTLE_TEST("Mirror Move's called multi-hit move hits multiple times") { GIVEN { - ASSUME(gMovesInfo[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_BULLET_SEED) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/terrain/misty.c b/test/battle/move_effect/misty_terrain.c similarity index 78% rename from test/battle/terrain/misty.c rename to test/battle/move_effect/misty_terrain.c index e43cf4a2538b..b96f0c650d9f 100644 --- a/test/battle/terrain/misty.c +++ b/test/battle/move_effect/misty_terrain.c @@ -19,25 +19,6 @@ SINGLE_BATTLE_TEST("Misty Terrain protects grounded battlers from non-volatile s } } -SINGLE_BATTLE_TEST("Misty Terrain activates Misty Seed and Mimicry") -{ - GIVEN { - ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffect == HOLD_EFFECT_SEEDS); - ASSUME(gItemsInfo[ITEM_MISTY_SEED].holdEffectParam == HOLD_EFFECT_PARAM_MISTY_TERRAIN); - PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_MISTY_SEED); } - OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } - } WHEN { - TURN { MOVE(player, MOVE_MISTY_TERRAIN); } - } SCENE { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Using Misty Seed, the Sp. Def of Wobbuffet rose!"); - ABILITY_POPUP(opponent); - MESSAGE("The opposing Stunfisk's type changed to Fairy!"); - } THEN { - EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[0], TYPE_FAIRY); - } -} - SINGLE_BATTLE_TEST("Misty Terrain does not increase the power of Fairy-type moves", s16 damage) { bool32 terrain; diff --git a/test/battle/move_effect/moonlight.c b/test/battle/move_effect/moonlight.c index 41359ea97cd4..34baa31b14e7 100644 --- a/test/battle/move_effect/moonlight.c +++ b/test/battle/move_effect/moonlight.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_MOONLIGHT].effect == EFFECT_MOONLIGHT); + ASSUME(GetMoveEffect(MOVE_MOONLIGHT) == EFFECT_MOONLIGHT); } SINGLE_BATTLE_TEST("Moonlight recovers 1/2 of the user's max HP") diff --git a/test/battle/move_effect/morning_sun.c b/test/battle/move_effect/morning_sun.c index 3b57f895006c..64fb1b044ba5 100644 --- a/test/battle/move_effect/morning_sun.c +++ b/test/battle/move_effect/morning_sun.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_MORNING_SUN].effect == EFFECT_MORNING_SUN); + ASSUME(GetMoveEffect(MOVE_MORNING_SUN) == EFFECT_MORNING_SUN); } SINGLE_BATTLE_TEST("Morning Sun recovers 1/2 of the user's max HP") diff --git a/test/battle/move_effect/multi_hit.c b/test/battle/move_effect/multi_hit.c index e2331efbf743..da96c07c90d6 100644 --- a/test/battle/move_effect/multi_hit.c +++ b/test/battle/move_effect/multi_hit.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_BULLET_SEED) == EFFECT_MULTI_HIT); } SINGLE_BATTLE_TEST("Multi hit Moves hit the maximum amount with Skill Link") @@ -141,7 +141,7 @@ SINGLE_BATTLE_TEST("Multi hit Moves hit five times 50 Percent of the time with L SINGLE_BATTLE_TEST("Scale Shot decreases defense and increases speed after final hit") { GIVEN { - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -163,8 +163,8 @@ SINGLE_BATTLE_TEST("Scale Shot decreases defense and increases speed after final SINGLE_BATTLE_TEST("Scale Shot is immune to Fairy types and will end the move correctly") { GIVEN { - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].effect == EFFECT_MULTI_HIT); - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].type == TYPE_DRAGON); + ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); + ASSUME(GetMoveType(MOVE_SCALE_SHOT) == TYPE_DRAGON); ASSUME(gSpeciesInfo[SPECIES_CLEFAIRY].types[0] == TYPE_FAIRY || gSpeciesInfo[SPECIES_CLEFAIRY].types[1] == TYPE_FAIRY); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_CLEFAIRY) { HP(1); } @@ -179,7 +179,7 @@ SINGLE_BATTLE_TEST("Scale Shot is immune to Fairy types and will end the move co DOUBLE_BATTLE_TEST("Scale Shot does not corrupt the next turn move used") { GIVEN { - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -200,35 +200,11 @@ DOUBLE_BATTLE_TEST("Scale Shot does not corrupt the next turn move used") } } -SINGLE_BATTLE_TEST("Endure does not prevent multiple hits and stat changes occur at the end of the turn") -{ - GIVEN { - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].effect == EFFECT_MULTI_HIT); - ASSUME(gMovesInfo[MOVE_ENDURE].effect == EFFECT_ENDURE); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { HP(1); } - } WHEN { - TURN { MOVE(opponent, MOVE_ENDURE); MOVE(player, MOVE_SCALE_SHOT); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); - ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player); - MESSAGE("The Pokémon was hit 5 time(s)!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Defense fell!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Speed rose!"); - } -} - SINGLE_BATTLE_TEST("Scale Shot decreases defense and increases speed after the 4th hit of Loaded Dice") { PASSES_RANDOMLY(50, 100, RNG_LOADED_DICE); GIVEN { - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_LOADED_DICE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -253,7 +229,7 @@ SINGLE_BATTLE_TEST("Scale Shot decreases defense and increases speed after killi PARAMETRIZE { item = ITEM_LOADED_DICE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SCALE_SHOT].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT); PLAYER(SPECIES_BAGON) { Item(item); } OPPONENT(SPECIES_SLUGMA) { Ability(ABILITY_WEAK_ARMOR); } OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/ohko.c b/test/battle/move_effect/ohko.c index 8a8015309b87..11dbb78f1f3a 100644 --- a/test/battle/move_effect/ohko.c +++ b/test/battle/move_effect/ohko.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SHEER_COLD].effect == EFFECT_OHKO); + ASSUME(GetMoveEffect(MOVE_SHEER_COLD) == EFFECT_OHKO); } SINGLE_BATTLE_TEST("Sheer Cold doesn't affect Ice-type Pokémon") @@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Sheer Cold doesn't affect Ice-type Pokémon") SINGLE_BATTLE_TEST("OHKO moves can hit semi-invulnerable mons when the user has No-Guard") { GIVEN { - ASSUME(gMovesInfo[MOVE_SHEER_COLD].effect == EFFECT_OHKO); + ASSUME(GetMoveEffect(MOVE_SHEER_COLD) == EFFECT_OHKO); PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_NO_GUARD); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/photon_geyser.c b/test/battle/move_effect/photon_geyser.c index 986d3865aa5a..3f4bb10146ee 100644 --- a/test/battle/move_effect/photon_geyser.c +++ b/test/battle/move_effect/photon_geyser.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_PHOTON_GEYSER].effect == EFFECT_PHOTON_GEYSER); + ASSUME(GetMoveEffect(MOVE_PHOTON_GEYSER) == EFFECT_PHOTON_GEYSER); } SINGLE_BATTLE_TEST("Photon Geyser can be mirror coated if it is a special move") { GIVEN { // EFFECT_PHOTON_GEYSER requires the move data to be Special to work - ASSUME(gMovesInfo[MOVE_PHOTON_GEYSER].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_PHOTON_GEYSER) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET) { Attack(100); SpAttack(110); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/pledge.c b/test/battle/move_effect/pledge.c index 726adc81521f..a7935450b6c3 100644 --- a/test/battle/move_effect/pledge.c +++ b/test/battle/move_effect/pledge.c @@ -3,9 +3,9 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WATER_PLEDGE].effect == EFFECT_PLEDGE); - ASSUME(gMovesInfo[MOVE_FIRE_PLEDGE].effect == EFFECT_PLEDGE); - ASSUME(gMovesInfo[MOVE_GRASS_PLEDGE].effect == EFFECT_PLEDGE); + ASSUME(GetMoveEffect(MOVE_WATER_PLEDGE) == EFFECT_PLEDGE); + ASSUME(GetMoveEffect(MOVE_FIRE_PLEDGE) == EFFECT_PLEDGE); + ASSUME(GetMoveEffect(MOVE_GRASS_PLEDGE) == EFFECT_PLEDGE); } DOUBLE_BATTLE_TEST("Water and Fire Pledge create a rainbow on the user's side of the field for four turns") @@ -189,7 +189,7 @@ DOUBLE_BATTLE_TEST("The base power of a combined pledge move effect is 150") s16 combinedPledgeDamage; GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_BEAM].power == 150); + ASSUME(GetMovePower(MOVE_HYPER_BEAM) == 150); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } PLAYER(SPECIES_WYNAUT) { Speed(3); } OPPONENT(SPECIES_WOBBUFFET) { Speed(8); } @@ -313,7 +313,7 @@ DOUBLE_BATTLE_TEST("Damage calculation: Combined pledge move") PARAMETRIZE { expectedDamage = 136; } PARAMETRIZE { expectedDamage = 135; } GIVEN { - ASSUME(gMovesInfo[MOVE_GRASS_PLEDGE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_GRASS_PLEDGE) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET) { Speed(4); } PLAYER(SPECIES_WOBBUFFET) { HP(521); SpDefense(152); Speed(3); } OPPONENT(SPECIES_CHARIZARD) { Speed(8); } @@ -344,7 +344,7 @@ DOUBLE_BATTLE_TEST("Pledge move combo interactions with Powder are correct") PARAMETRIZE { moveLeft = MOVE_GRASS_PLEDGE; moveRight = MOVE_FIRE_PLEDGE; speedLeft = 4; speedRight = 3; } PARAMETRIZE { moveLeft = MOVE_GRASS_PLEDGE; moveRight = MOVE_FIRE_PLEDGE; speedLeft = 3; speedRight = 4; } // FAIL 2 GIVEN { - ASSUME(gMovesInfo[MOVE_FIRE_PLEDGE].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_FIRE_PLEDGE) == TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET) { Speed(speedLeft); } PLAYER(SPECIES_WYNAUT) { Speed(speedRight); } OPPONENT(SPECIES_WOBBUFFET) { Speed(8); } @@ -885,8 +885,8 @@ DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move - Electrify") { GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); - PLAYER(SPECIES_MAROWAK) { Ability(ABILITY_LIGHTNING_ROD); } + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); + PLAYER(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); @@ -1002,7 +1002,7 @@ DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move - Motor Drive") { GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); PLAYER(SPECIES_ELECTIVIRE) { Ability(ABILITY_MOTOR_DRIVE); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -1027,7 +1027,7 @@ DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move DOUBLE_BATTLE_TEST("Pledge move combo doesn't trigger on opponent's Pledge move - Volt Absorb") { GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); PLAYER(SPECIES_JOLTEON) { Ability(ABILITY_VOLT_ABSORB); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/population_bomb.c b/test/battle/move_effect/population_bomb.c index b3e2e4768e9b..54da0726ae61 100644 --- a/test/battle/move_effect/population_bomb.c +++ b/test/battle/move_effect/population_bomb.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Population Bomb can hit ten times") { GIVEN { - ASSUME(gMovesInfo[MOVE_POPULATION_BOMB].strikeCount == 10); + ASSUME(GetMoveStrikeCount(MOVE_POPULATION_BOMB) == 10); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/powder.c b/test/battle/move_effect/powder.c index 7701f4d3a2ae..aa789fb05f3e 100644 --- a/test/battle/move_effect/powder.c +++ b/test/battle/move_effect/powder.c @@ -3,9 +3,9 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_POWDER].effect == EFFECT_POWDER); - ASSUME(gMovesInfo[MOVE_POWDER].powderMove == TRUE); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(GetMoveEffect(MOVE_POWDER) == EFFECT_POWDER); + ASSUME(IsPowderMove(MOVE_POWDER)); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); } @@ -41,7 +41,7 @@ SINGLE_BATTLE_TEST("Powder blocks the target's Fire type moves and consumes PP") HP_BAR(opponent); } } THEN { - EXPECT_EQ(player->pp[0], gMovesInfo[MOVE_EMBER].pp - 1); + EXPECT_EQ(player->pp[0], GetMovePP(MOVE_EMBER) - 1); } } @@ -164,8 +164,8 @@ SINGLE_BATTLE_TEST("Powder fails if the target has Overcoat") DOUBLE_BATTLE_TEST("Powder still blocks the target's Fire type moves even if it was given Grass type") { GIVEN { - ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].effect == EFFECT_THIRD_TYPE); - ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].argument.type == TYPE_GRASS); + ASSUME(GetMoveEffect(MOVE_FORESTS_CURSE) == EFFECT_THIRD_TYPE); + ASSUME(GetMoveArgType(MOVE_FORESTS_CURSE) == TYPE_GRASS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_TREVENANT); @@ -185,7 +185,7 @@ DOUBLE_BATTLE_TEST("Powder still blocks the target's Fire type moves even if it DOUBLE_BATTLE_TEST("Powder still blocks the target's Fire type moves even if it was given Overcoat") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOODLE].effect == EFFECT_DOODLE); + ASSUME(GetMoveEffect(MOVE_DOODLE) == EFFECT_DOODLE); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_FORRETRESS) { Ability(ABILITY_OVERCOAT); } @@ -224,8 +224,8 @@ SINGLE_BATTLE_TEST("Powder prevents Protean from changing its user to Fire type" SINGLE_BATTLE_TEST("Powder doesn't prevent a Fire move from thawing its user out") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLAME_WHEEL].thawsUser); - ASSUME(gMovesInfo[MOVE_FLAME_WHEEL].type == TYPE_FIRE); + ASSUME(MoveThawsUser(MOVE_FLAME_WHEEL)); + ASSUME(GetMoveType(MOVE_FLAME_WHEEL) == TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } OPPONENT(SPECIES_VIVILLON); } WHEN { @@ -244,7 +244,7 @@ SINGLE_BATTLE_TEST("Powder doesn't prevent a Fire move from thawing its user out SINGLE_BATTLE_TEST("Powder doesn't consume Berry from Fire type Natural Gift but prevents using the move") { GIVEN { - ASSUME(gMovesInfo[MOVE_NATURAL_GIFT].effect == EFFECT_NATURAL_GIFT); + ASSUME(GetMoveEffect(MOVE_NATURAL_GIFT) == EFFECT_NATURAL_GIFT); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_CHERI_BERRY); } OPPONENT(SPECIES_VIVILLON); } WHEN { @@ -267,12 +267,12 @@ DOUBLE_BATTLE_TEST("Powder damages a target using Shell Trap even if it wasn't h PARAMETRIZE { move = MOVE_EMBER; } PARAMETRIZE { move = MOVE_TICKLE;} GIVEN { - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].effect == EFFECT_SHELL_TRAP); - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_EMBER].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_TICKLE].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_TICKLE].effect == EFFECT_TICKLE); + ASSUME(GetMoveEffect(MOVE_SHELL_TRAP) == EFFECT_SHELL_TRAP); + ASSUME(GetMoveType(MOVE_SHELL_TRAP) == TYPE_FIRE); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_EMBER) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TICKLE) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_TICKLE) == EFFECT_TICKLE); PLAYER(SPECIES_TURTONATOR); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); diff --git a/test/battle/move_effect/power_based_on_target_hp.c b/test/battle/move_effect/power_based_on_target_hp.c index 2cecf3ff7f1e..030418cd87a0 100644 --- a/test/battle/move_effect/power_based_on_target_hp.c +++ b/test/battle/move_effect/power_based_on_target_hp.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_CRUSH_GRIP].effect == EFFECT_POWER_BASED_ON_TARGET_HP); + ASSUME(GetMoveEffect(MOVE_CRUSH_GRIP) == EFFECT_POWER_BASED_ON_TARGET_HP); } SINGLE_BATTLE_TEST("Crush Grip's damage is affected by the target's current HP", s16 damage) diff --git a/test/battle/move_effect/power_based_on_user_hp.c b/test/battle/move_effect/power_based_on_user_hp.c index 1dfa70ddf968..622b19552526 100644 --- a/test/battle/move_effect/power_based_on_user_hp.c +++ b/test/battle/move_effect/power_based_on_user_hp.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ERUPTION].effect == EFFECT_POWER_BASED_ON_USER_HP); + ASSUME(GetMoveEffect(MOVE_ERUPTION) == EFFECT_POWER_BASED_ON_USER_HP); } SINGLE_BATTLE_TEST("Eruption's damage is affected by the user's current HP", s16 damage) diff --git a/test/battle/move_effect/power_split.c b/test/battle/move_effect/power_split.c index 70d1bfd5ea06..84c64b1d8990 100644 --- a/test/battle/move_effect/power_split.c +++ b/test/battle/move_effect/power_split.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_POWER_SPLIT].effect == EFFECT_POWER_SPLIT); + ASSUME(GetMoveEffect(MOVE_POWER_SPLIT) == EFFECT_POWER_SPLIT); } SINGLE_BATTLE_TEST("Power Split averages user and targets Atk and Sp. Atk stats") diff --git a/test/battle/move_effect/protect.c b/test/battle/move_effect/protect.c index dff486cb001e..84862bbcd4c5 100644 --- a/test/battle/move_effect/protect.c +++ b/test/battle/move_effect/protect.c @@ -3,21 +3,21 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_PROTECT].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_DETECT].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_KINGS_SHIELD].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_SILK_TRAP].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_SPIKY_SHIELD].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_WIDE_GUARD].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_QUICK_GUARD].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_CRAFTY_SHIELD].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_BANEFUL_BUNKER].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_BURNING_BULWARK].effect == EFFECT_PROTECT); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_LEER].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(!(gMovesInfo[MOVE_WATER_GUN].makesContact)); + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_DETECT) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_KINGS_SHIELD) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_SILK_TRAP) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_SPIKY_SHIELD) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_WIDE_GUARD) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_QUICK_GUARD) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_CRAFTY_SHIELD) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_BANEFUL_BUNKER) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_BURNING_BULWARK) == EFFECT_PROTECT); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(GetMoveCategory(MOVE_LEER) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(!(MoveMakesContact(MOVE_WATER_GUN))); } SINGLE_BATTLE_TEST("Protect, Detect, Spiky Shield, Baneful Bunker and Burning Bulwark protect from all moves") @@ -244,10 +244,10 @@ SINGLE_BATTLE_TEST("Recoil damage is not applied if target was protected") GIVEN { - ASSUME(gMovesInfo[MOVE_VOLT_TACKLE].recoil > 0); - ASSUME(gMovesInfo[MOVE_HEAD_SMASH].recoil > 0); - ASSUME(gMovesInfo[MOVE_TAKE_DOWN].recoil > 0); - ASSUME(gMovesInfo[MOVE_DOUBLE_EDGE].recoil > 0); + ASSUME(GetMoveRecoil(MOVE_VOLT_TACKLE) > 0); + ASSUME(GetMoveRecoil(MOVE_HEAD_SMASH) > 0); + ASSUME(GetMoveRecoil(MOVE_TAKE_DOWN) > 0); + ASSUME(GetMoveRecoil(MOVE_DOUBLE_EDGE) > 0); PLAYER(SPECIES_RAPIDASH); OPPONENT(SPECIES_BEAUTIFLY); } WHEN { @@ -282,7 +282,7 @@ SINGLE_BATTLE_TEST("Multi-hit moves don't hit a protected target and fail only o PARAMETRIZE { move = MOVE_SPIKY_SHIELD; } GIVEN { - ASSUME(gMovesInfo[MOVE_ARM_THRUST].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_ARM_THRUST) == EFFECT_MULTI_HIT); PLAYER(SPECIES_RAPIDASH); OPPONENT(SPECIES_BEAUTIFLY); } WHEN { @@ -325,9 +325,9 @@ DOUBLE_BATTLE_TEST("Wide Guard protects self and ally from multi-target moves") PARAMETRIZE { move = MOVE_HYPER_VOICE; } // 2 foes GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].target == MOVE_TARGET_SELECTED); - ASSUME(gMovesInfo[MOVE_SURF].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_TACKLE) == MOVE_TARGET_SELECTED); + ASSUME(GetMoveTarget(MOVE_SURF) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -364,7 +364,7 @@ DOUBLE_BATTLE_TEST("Wide Guard can not fail on consecutive turns") PASSES_RANDOMLY(2, 2); GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -397,8 +397,8 @@ DOUBLE_BATTLE_TEST("Quick Guard protects self and ally from priority moves") PARAMETRIZE { move = MOVE_QUICK_ATTACK; targetOpponent = opponentRight; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].priority == 0); - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); + ASSUME(GetMovePriority(MOVE_TACKLE) == 0); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -427,7 +427,7 @@ DOUBLE_BATTLE_TEST("Quick Guard can not fail on consecutive turns") PASSES_RANDOMLY(2, 2); GIVEN { - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -457,9 +457,9 @@ DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from status moves") PARAMETRIZE { move = MOVE_TACKLE; targetOpponent = opponentRight; } GIVEN { - ASSUME(gMovesInfo[MOVE_LEER].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveTarget(MOVE_LEER) == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); + ASSUME(GetMoveCategory(MOVE_HYPER_VOICE) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -494,10 +494,10 @@ SINGLE_BATTLE_TEST("Protect does not block Confide or Decorate") PARAMETRIZE { move = MOVE_DECORATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_CONFIDE].ignoresProtect == TRUE); - ASSUME(gMovesInfo[MOVE_DECORATE].effect == EFFECT_DECORATE); - ASSUME(gMovesInfo[MOVE_DECORATE].ignoresProtect == TRUE); + ASSUME(GetMoveEffect(MOVE_CONFIDE) == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(MoveIgnoresProtect(MOVE_CONFIDE)); + ASSUME(GetMoveEffect(MOVE_DECORATE) == EFFECT_DECORATE); + ASSUME(MoveIgnoresProtect(MOVE_DECORATE)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -516,10 +516,10 @@ DOUBLE_BATTLE_TEST("Crafty Shield protects self and ally from Confide and Decora PARAMETRIZE { move = MOVE_DECORATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); - ASSUME(gMovesInfo[MOVE_CONFIDE].ignoresProtect == TRUE); - ASSUME(gMovesInfo[MOVE_DECORATE].effect == EFFECT_DECORATE); - ASSUME(gMovesInfo[MOVE_DECORATE].ignoresProtect == TRUE); + ASSUME(GetMoveEffect(MOVE_CONFIDE) == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(MoveIgnoresProtect(MOVE_CONFIDE)); + ASSUME(GetMoveEffect(MOVE_DECORATE) == EFFECT_DECORATE); + ASSUME(MoveIgnoresProtect(MOVE_DECORATE)); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/terrain/psychic.c b/test/battle/move_effect/psychic_terrain.c similarity index 84% rename from test/battle/terrain/psychic.c rename to test/battle/move_effect/psychic_terrain.c index 9ac88f29dad8..b85653a0bef0 100644 --- a/test/battle/terrain/psychic.c +++ b/test/battle/move_effect/psychic_terrain.c @@ -18,25 +18,6 @@ SINGLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority mov } } -SINGLE_BATTLE_TEST("Psychic Terrain activates Psychic Seed and Mimicry") -{ - GIVEN { - ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffect == HOLD_EFFECT_SEEDS); - ASSUME(gItemsInfo[ITEM_PSYCHIC_SEED].holdEffectParam == HOLD_EFFECT_PARAM_PSYCHIC_TERRAIN); - PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_PSYCHIC_SEED); } - OPPONENT(SPECIES_STUNFISK_GALAR) { Ability(ABILITY_MIMICRY); } - } WHEN { - TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } - } SCENE { - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Using Psychic Seed, the Sp. Def of Wobbuffet rose!"); - ABILITY_POPUP(opponent); - MESSAGE("The opposing Stunfisk's type changed to Psychic!"); - } THEN { - EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].types[0], TYPE_PSYCHIC); - } -} - SINGLE_BATTLE_TEST("Psychic Terrain increases power of Psychic-type moves by 30/50 percent", s16 damage) { bool32 terrain; diff --git a/test/battle/move_effect/pursuit.c b/test/battle/move_effect/pursuit.c index a20b1ed1d129..ea64813e68bd 100644 --- a/test/battle/move_effect/pursuit.c +++ b/test/battle/move_effect/pursuit.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_PURSUIT].effect == EFFECT_PURSUIT); + ASSUME(GetMoveEffect(MOVE_PURSUIT) == EFFECT_PURSUIT); } SINGLE_BATTLE_TEST("Pursuit attacks a switching foe") @@ -29,9 +29,9 @@ SINGLE_BATTLE_TEST("Pursuit attacks a foe using Volt Switch / U-Turn / Parting S PARAMETRIZE { move = MOVE_U_TURN; } PARAMETRIZE { move = MOVE_PARTING_SHOT; } GIVEN { - ASSUME(gMovesInfo[MOVE_VOLT_SWITCH].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE); - ASSUME(gMovesInfo[MOVE_PARTING_SHOT].effect == EFFECT_PARTING_SHOT); + ASSUME(GetMoveEffect(MOVE_VOLT_SWITCH) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_U_TURN) == EFFECT_HIT_ESCAPE); + ASSUME(GetMoveEffect(MOVE_PARTING_SHOT) == EFFECT_PARTING_SHOT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_WYNAUT); @@ -51,9 +51,9 @@ DOUBLE_BATTLE_TEST("Pursuit doesn't attack a foe using Teleport / Baton Pass to PARAMETRIZE { move = MOVE_TELEPORT; } PARAMETRIZE { move = MOVE_BATON_PASS; } GIVEN { - ASSUME(gMovesInfo[MOVE_QUASH].effect == EFFECT_QUASH); - ASSUME(gMovesInfo[MOVE_TELEPORT].effect == EFFECT_TELEPORT); - ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS); + ASSUME(GetMoveEffect(MOVE_QUASH) == EFFECT_QUASH); + ASSUME(GetMoveEffect(MOVE_TELEPORT) == EFFECT_TELEPORT); + ASSUME(GetMoveEffect(MOVE_BATON_PASS) == EFFECT_BATON_PASS); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_NIDOKING); PLAYER(SPECIES_ZIGZAGOON); @@ -115,8 +115,8 @@ SINGLE_BATTLE_TEST("Pursuit ignores accuracy checks when attacking a switching t { PASSES_RANDOMLY(100, 100, RNG_ACCURACY); GIVEN { - ASSUME(gMovesInfo[MOVE_SAND_ATTACK].effect == EFFECT_ACCURACY_DOWN); - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_SAND_ATTACK) == EFFECT_ACCURACY_DOWN); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); PLAYER(SPECIES_GLACEON) { Ability(ABILITY_SNOW_CLOAK); } PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_WOBBUFFET); @@ -340,7 +340,7 @@ SINGLE_BATTLE_TEST("Pursuit attacks a switching foe and takes Life Orb damage") DOUBLE_BATTLE_TEST("Pursuit attacks a switching foe but isn't affected by Follow Me") { GIVEN { - ASSUME(gMovesInfo[MOVE_FOLLOW_ME].effect == EFFECT_FOLLOW_ME); + ASSUME(GetMoveEffect(MOVE_FOLLOW_ME) == EFFECT_FOLLOW_ME); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_CLEFABLE); PLAYER(SPECIES_ZIGZAGOON); @@ -422,7 +422,7 @@ SINGLE_BATTLE_TEST("Pursuit user terastalizes before attacking a switching foe a DOUBLE_BATTLE_TEST("Pursuit affected by Electrify fails against immune target") { GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); PLAYER(SPECIES_DONPHAN); PLAYER(SPECIES_HELIOLISK); PLAYER(SPECIES_ZIGZAGOON); @@ -441,7 +441,7 @@ DOUBLE_BATTLE_TEST("Pursuit affected by Electrify fails against immune target") DOUBLE_BATTLE_TEST("Pursuit affected by Electrify fails against target with Volt Absorb") { GIVEN { - ASSUME(gMovesInfo[MOVE_ELECTRIFY].effect == EFFECT_ELECTRIFY); + ASSUME(GetMoveEffect(MOVE_ELECTRIFY) == EFFECT_ELECTRIFY); PLAYER(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); } PLAYER(SPECIES_HELIOLISK); PLAYER(SPECIES_ZIGZAGOON); diff --git a/test/battle/move_effect/quash.c b/test/battle/move_effect/quash.c index b342eafd74ae..1d2f89230c11 100644 --- a/test/battle/move_effect/quash.c +++ b/test/battle/move_effect/quash.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_QUASH].effect == EFFECT_QUASH); + ASSUME(GetMoveEffect(MOVE_QUASH) == EFFECT_QUASH); } DOUBLE_BATTLE_TEST("Quash-affected target will move last in the priority bracket") @@ -27,7 +27,7 @@ DOUBLE_BATTLE_TEST("Quash is not affected by dynamic speed") { GIVEN { ASSUME(B_RECALC_TURN_AFTER_ACTIONS >= GEN_8); - ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND); + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); PLAYER(SPECIES_VOLBEAT) { Speed(10); Ability(ABILITY_PRANKSTER); } PLAYER(SPECIES_WOBBUFFET) { Speed(30); } OPPONENT(SPECIES_TORCHIC) { Speed(50); } @@ -113,8 +113,8 @@ DOUBLE_BATTLE_TEST("Quash-affected mon that acted early via After You is not aff { GIVEN { ASSUME(B_RECALC_TURN_AFTER_ACTIONS >= GEN_8); - ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND); - ASSUME(gMovesInfo[MOVE_AFTER_YOU].effect == EFFECT_AFTER_YOU); + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); + ASSUME(GetMoveEffect(MOVE_AFTER_YOU) == EFFECT_AFTER_YOU); PLAYER(SPECIES_VOLBEAT) { Speed(20); Ability(ABILITY_PRANKSTER); } PLAYER(SPECIES_WOBBUFFET) { Speed(30); } OPPONENT(SPECIES_TORCHIC) { Speed(10); } diff --git a/test/battle/move_effect/rage_fist.c b/test/battle/move_effect/rage_fist.c index 7bc349cef03e..7a87f3e34d28 100644 --- a/test/battle/move_effect/rage_fist.c +++ b/test/battle/move_effect/rage_fist.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_RAGE_FIST].effect == EFFECT_RAGE_FIST); - ASSUME(gMovesInfo[MOVE_RAGE_FIST].power == 50); + ASSUME(GetMoveEffect(MOVE_RAGE_FIST) == EFFECT_RAGE_FIST); + ASSUME(GetMovePower(MOVE_RAGE_FIST) == 50); } SINGLE_BATTLE_TEST("Rage Fist base power is increased by 50 if the user takes damage") @@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Rage Fist base power is increased by each multi hit") s16 timesGotHit[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_BULLET_SEED].effect == EFFECT_MULTI_HIT); + ASSUME(GetMoveEffect(MOVE_BULLET_SEED) == EFFECT_MULTI_HIT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_REGIROCK); } WHEN { @@ -130,7 +130,7 @@ SINGLE_BATTLE_TEST("Rage Fist base power is not increased if a substitute was hi s16 timesGotHit[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_CRUNCH].category == DAMAGE_CATEGORY_PHYSICAL); // Substitute doesn't fade otherwise + ASSUME(GetMoveCategory(MOVE_CRUNCH) == DAMAGE_CATEGORY_PHYSICAL); // Substitute doesn't fade otherwise PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_REGIROCK); } WHEN { diff --git a/test/battle/move_effect/raging_bull.c b/test/battle/move_effect/raging_bull.c index 7e72ca82738a..c75c97749515 100644 --- a/test/battle/move_effect/raging_bull.c +++ b/test/battle/move_effect/raging_bull.c @@ -3,11 +3,11 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_RAGING_BULL].effect == EFFECT_RAGING_BULL); - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); - ASSUME(gMovesInfo[MOVE_LIGHT_SCREEN].effect == EFFECT_LIGHT_SCREEN); - ASSUME(gMovesInfo[MOVE_REFLECT].effect == EFFECT_REFLECT); - ASSUME(gMovesInfo[MOVE_AURORA_VEIL].effect == EFFECT_AURORA_VEIL); + ASSUME(GetMoveEffect(MOVE_RAGING_BULL) == EFFECT_RAGING_BULL); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_LIGHT_SCREEN) == EFFECT_LIGHT_SCREEN); + ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT); + ASSUME(GetMoveEffect(MOVE_AURORA_VEIL) == EFFECT_AURORA_VEIL); } SINGLE_BATTLE_TEST("Raging Bull removes Light Screen, Reflect and Aurora Veil from the target's side of the field") diff --git a/test/battle/move_effect/recoil_if_miss.c b/test/battle/move_effect/recoil_if_miss.c index a5f011109548..8695156dd032 100644 --- a/test/battle/move_effect/recoil_if_miss.c +++ b/test/battle/move_effect/recoil_if_miss.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_JUMP_KICK].effect == EFFECT_RECOIL_IF_MISS); + ASSUME(GetMoveEffect(MOVE_JUMP_KICK) == EFFECT_RECOIL_IF_MISS); } SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss") @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss") SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on protect") { GIVEN { - ASSUME(!gMovesInfo[MOVE_JUMP_KICK].ignoresProtect); + ASSUME(!MoveIgnoresProtect(MOVE_JUMP_KICK)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Jump Kick's recoil happens after Spiky Shield damage and Pok PARAMETRIZE { hp = maxHp / 8; faintOnSpiky = TRUE; } // Faints after Spiky Shield's recoil GIVEN { - ASSUME(gMovesInfo[MOVE_SPIKY_SHIELD].effect == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_SPIKY_SHIELD) == EFFECT_PROTECT); PLAYER(SPECIES_WOBBUFFET) { HP(hp); MaxHP(maxHp); } PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/reflect.c b/test/battle/move_effect/reflect.c index 429dc6f6969e..83ac3b8503ef 100644 --- a/test/battle/move_effect/reflect.c +++ b/test/battle/move_effect/reflect.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_REFLECT].effect == EFFECT_REFLECT); + ASSUME(GetMoveEffect(MOVE_REFLECT) == EFFECT_REFLECT); } SINGLE_BATTLE_TEST("Reflect reduces physical damage", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Reflect reduces physical damage", s16 damage) PARAMETRIZE { move = MOVE_CELEBRATE; } PARAMETRIZE { move = MOVE_REFLECT; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -30,7 +30,7 @@ SINGLE_BATTLE_TEST("Reflect applies for 5 turns") { s16 damage[6]; GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/refresh.c b/test/battle/move_effect/refresh.c index 7cf319f3e6f8..7d0ba0273e52 100644 --- a/test/battle/move_effect/refresh.c +++ b/test/battle/move_effect/refresh.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_REFRESH].effect == EFFECT_REFRESH); + ASSUME(GetMoveEffect(MOVE_REFRESH) == EFFECT_REFRESH); } SINGLE_BATTLE_TEST("Refresh cures the user of burn, frostbite, poison, and paralysis") @@ -45,8 +45,8 @@ SINGLE_BATTLE_TEST("Refresh does not cure the user of Freeze") SINGLE_BATTLE_TEST("Refresh does not cure sleep when used by Sleep Talk") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SLEEP_TALK, MOVE_REFRESH); } } WHEN { diff --git a/test/battle/move_effect/relic_song.c b/test/battle/move_effect/relic_song.c index e7569c7e389e..f1e7fae92fdc 100644 --- a/test/battle/move_effect/relic_song.c +++ b/test/battle/move_effect/relic_song.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_RELIC_SONG].effect == EFFECT_RELIC_SONG); + ASSUME(GetMoveEffect(MOVE_RELIC_SONG) == EFFECT_RELIC_SONG); ASSUME(MoveHasAdditionalEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP) == TRUE); } diff --git a/test/battle/move_effect/retaliate.c b/test/battle/move_effect/retaliate.c index 581793e8547a..39c26d196c43 100644 --- a/test/battle/move_effect/retaliate.c +++ b/test/battle/move_effect/retaliate.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_RETALIATE].effect == EFFECT_RETALIATE); + ASSUME(GetMoveEffect(MOVE_RETALIATE) == EFFECT_RETALIATE); } SINGLE_BATTLE_TEST("Retaliate doubles in base power the turn after an ally faints") @@ -63,17 +63,17 @@ DOUBLE_BATTLE_TEST("Retaliate works with passive damage") PARAMETRIZE { move = MOVE_FLAME_BURST; moveTarget = playerRight; } PARAMETRIZE { move = MOVE_FIRE_PLEDGE; moveTarget = playerRight; move2 = MOVE_GRASS_PLEDGE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); - ASSUME(gMovesInfo[MOVE_POISON_POWDER].effect == EFFECT_POISON); - ASSUME(gMovesInfo[MOVE_WILL_O_WISP].effect == EFFECT_WILL_O_WISP); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_POISON_POWDER) == EFFECT_POISON); + ASSUME(GetMoveEffect(MOVE_WILL_O_WISP) == EFFECT_WILL_O_WISP); #if B_USE_FROSTBITE == TRUE - ASSUME(gMovesInfo[MOVE_ICE_BEAM].additionalEffects[0].moveEffect == MOVE_EFFECT_FREEZE_OR_FROSTBITE); + ASSUME(GetMoveAdditionalEffectById(MOVE_ICE_BEAM, 0)->moveEffect == MOVE_EFFECT_FREEZE_OR_FROSTBITE); #endif - ASSUME(gMovesInfo[MOVE_SANDSTORM].effect == EFFECT_SANDSTORM); - ASSUME(gMovesInfo[MOVE_HAIL].effect == EFFECT_HAIL); - ASSUME(gMovesInfo[MOVE_LEECH_SEED].effect == EFFECT_LEECH_SEED); - ASSUME(gMovesInfo[MOVE_MAGMA_STORM].additionalEffects[0].moveEffect == MOVE_EFFECT_WRAP); - ASSUME(gMovesInfo[MOVE_FLAME_BURST].additionalEffects[0].moveEffect == MOVE_EFFECT_FLAME_BURST); + ASSUME(GetMoveEffect(MOVE_SANDSTORM) == EFFECT_SANDSTORM); + ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL); + ASSUME(GetMoveEffect(MOVE_LEECH_SEED) == EFFECT_LEECH_SEED); + ASSUME(GetMoveAdditionalEffectById(MOVE_MAGMA_STORM, 0)->moveEffect == MOVE_EFFECT_WRAP); + ASSUME(GetMoveAdditionalEffectById(MOVE_FLAME_BURST, 0)->moveEffect == MOVE_EFFECT_FLAME_BURST); PLAYER(SPECIES_WYNAUT) { Ability(ABILITY_SHADOW_TAG); HP(18); } PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } PLAYER(SPECIES_WOBBUFFET); @@ -97,7 +97,7 @@ SINGLE_BATTLE_TEST("Retaliate works with Perish Song") { s16 damage[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_PERISH_SONG].effect == EFFECT_PERISH_SONG); + ASSUME(GetMoveEffect(MOVE_PERISH_SONG) == EFFECT_PERISH_SONG); PLAYER(SPECIES_WYNAUT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KOMMO_O) { Ability(ABILITY_SOUNDPROOF); } @@ -120,7 +120,7 @@ SINGLE_BATTLE_TEST("Retaliate works with self-inflicted fainting") { s16 damage[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_HEALING_WISH].effect == EFFECT_HEALING_WISH); + ASSUME(GetMoveEffect(MOVE_HEALING_WISH) == EFFECT_HEALING_WISH); PLAYER(SPECIES_WYNAUT); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/revelation_dance.c b/test/battle/move_effect/revelation_dance.c index 0549abb7b77b..3730ecc0b2a5 100644 --- a/test/battle/move_effect/revelation_dance.c +++ b/test/battle/move_effect/revelation_dance.c @@ -3,12 +3,12 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].effect == EFFECT_REVELATION_DANCE); - ASSUME(gMovesInfo[MOVE_REVELATION_DANCE].danceMove == TRUE); + ASSUME(GetMoveEffect(MOVE_REVELATION_DANCE) == EFFECT_REVELATION_DANCE); + ASSUME(IsDanceMove(MOVE_REVELATION_DANCE)); ASSUME(IsMoveEffectRemoveSpeciesType(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE)); - ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].effect == EFFECT_THIRD_TYPE); - ASSUME(gMovesInfo[MOVE_FORESTS_CURSE].argument.type == TYPE_GRASS); - ASSUME(gMovesInfo[MOVE_ROOST].effect == EFFECT_ROOST); + ASSUME(GetMoveEffect(MOVE_FORESTS_CURSE) == EFFECT_THIRD_TYPE); + ASSUME(GetMoveArgType(MOVE_FORESTS_CURSE) == TYPE_GRASS); + ASSUME(GetMoveEffect(MOVE_ROOST) == EFFECT_ROOST); } SINGLE_BATTLE_TEST("Revelation Dance changes its type depending on the user's 1st Type") diff --git a/test/battle/move_effect/revival_blessing.c b/test/battle/move_effect/revival_blessing.c index dbeda39f9153..10198ce3527a 100644 --- a/test/battle/move_effect/revival_blessing.c +++ b/test/battle/move_effect/revival_blessing.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING); + ASSUME(GetMoveEffect(MOVE_REVIVAL_BLESSING) == EFFECT_REVIVAL_BLESSING); } SINGLE_BATTLE_TEST("Revival Blessing revives a chosen fainted party member for the player") diff --git a/test/battle/move_effect/roar.c b/test/battle/move_effect/roar.c index f67a24bba102..ef6439088f5e 100644 --- a/test/battle/move_effect/roar.c +++ b/test/battle/move_effect/roar.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ROAR].effect == EFFECT_ROAR); + ASSUME(GetMoveEffect(MOVE_ROAR) == EFFECT_ROAR); } SINGLE_BATTLE_TEST("Roar switches the target with a random non-fainted replacement") diff --git a/test/battle/move_effect/role_play.c b/test/battle/move_effect/role_play.c index ab0d801ee9b9..d2d937f7d121 100644 --- a/test/battle/move_effect/role_play.c +++ b/test/battle/move_effect/role_play.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ROLE_PLAY].effect == EFFECT_ROLE_PLAY); + ASSUME(GetMoveEffect(MOVE_ROLE_PLAY) == EFFECT_ROLE_PLAY); } SINGLE_BATTLE_TEST("Role Play copies target's ability") diff --git a/test/battle/move_effect/roost.c b/test/battle/move_effect/roost.c index 449119a89abc..51d9499bd19c 100644 --- a/test/battle/move_effect/roost.c +++ b/test/battle/move_effect/roost.c @@ -3,28 +3,28 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ROOST].effect == EFFECT_ROOST); + ASSUME(GetMoveEffect(MOVE_ROOST) == EFFECT_ROOST); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FLYING); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FLYING); // One attack of each type to verify typelessness - ASSUME(gMovesInfo[MOVE_POUND].type == TYPE_NORMAL); - ASSUME(gMovesInfo[MOVE_KARATE_CHOP].type == TYPE_FIGHTING); - ASSUME(gMovesInfo[MOVE_GUST].type == TYPE_FLYING); - ASSUME(gMovesInfo[MOVE_POISON_STING].type == TYPE_POISON); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].type == TYPE_GROUND); - ASSUME(gMovesInfo[MOVE_ROCK_THROW].type == TYPE_ROCK); - ASSUME(gMovesInfo[MOVE_LEECH_LIFE].type == TYPE_BUG); - ASSUME(gMovesInfo[MOVE_LICK].type == TYPE_GHOST); - ASSUME(gMovesInfo[MOVE_STEEL_WING].type == TYPE_STEEL); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_VINE_WHIP].type == TYPE_GRASS); - ASSUME(gMovesInfo[MOVE_THUNDER_SHOCK].type == TYPE_ELECTRIC); - ASSUME(gMovesInfo[MOVE_CONFUSION].type == TYPE_PSYCHIC); - ASSUME(gMovesInfo[MOVE_ICE_BEAM].type == TYPE_ICE); - ASSUME(gMovesInfo[MOVE_DRAGON_BREATH].type == TYPE_DRAGON); - ASSUME(gMovesInfo[MOVE_BITE].type == TYPE_DARK); - ASSUME(gMovesInfo[MOVE_DISARMING_VOICE].type == TYPE_FAIRY); + ASSUME(GetMoveType(MOVE_POUND) == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_KARATE_CHOP) == TYPE_FIGHTING); + ASSUME(GetMoveType(MOVE_GUST) == TYPE_FLYING); + ASSUME(GetMoveType(MOVE_POISON_STING) == TYPE_POISON); + ASSUME(GetMoveType(MOVE_EARTHQUAKE) == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); + ASSUME(GetMoveType(MOVE_LEECH_LIFE) == TYPE_BUG); + ASSUME(GetMoveType(MOVE_LICK) == TYPE_GHOST); + ASSUME(GetMoveType(MOVE_STEEL_WING) == TYPE_STEEL); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_CONFUSION) == TYPE_PSYCHIC); + ASSUME(GetMoveType(MOVE_ICE_BEAM) == TYPE_ICE); + ASSUME(GetMoveType(MOVE_DRAGON_BREATH) == TYPE_DRAGON); + ASSUME(GetMoveType(MOVE_BITE) == TYPE_DARK); + ASSUME(GetMoveType(MOVE_DISARMING_VOICE) == TYPE_FAIRY); } SINGLE_BATTLE_TEST("Roost fails when user is at full HP") diff --git a/test/battle/move_effect/round.c b/test/battle/move_effect/round.c index 09209c79a2b6..0bac324b0fee 100644 --- a/test/battle/move_effect/round.c +++ b/test/battle/move_effect/round.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ROUND].effect == EFFECT_ROUND); + ASSUME(GetMoveEffect(MOVE_ROUND) == EFFECT_ROUND); } DOUBLE_BATTLE_TEST("Round allows other battlers which also selected the moves to immediately use the move, ignoring turn order") { GIVEN { ASSUME(gItemsInfo[ITEM_LAGGING_TAIL].holdEffect == HOLD_EFFECT_LAGGING_TAIL); - ASSUME(gMovesInfo[MOVE_IRON_HEAD].additionalEffects[0].moveEffect == MOVE_EFFECT_FLINCH); + ASSUME(GetMoveAdditionalEffectById(MOVE_IRON_HEAD, 0)->moveEffect == MOVE_EFFECT_FLINCH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/salt_cure.c b/test/battle/move_effect/salt_cure.c index afe811da502e..94e3ead5cc76 100644 --- a/test/battle/move_effect/salt_cure.c +++ b/test/battle/move_effect/salt_cure.c @@ -117,3 +117,18 @@ SINGLE_BATTLE_TEST("Salt Cure residual damage does not inflict any damage agains } } } + +SINGLE_BATTLE_TEST("If Salt Cure faints the target, messages will be applied in the correct order") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(25); } + } WHEN { + TURN { MOVE(player, MOVE_SALT_CURE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SALT_CURE, player); + MESSAGE("The opposing Wobbuffet is being salt cured!"); + MESSAGE("The opposing Wobbuffet is hurt by Salt Cure!"); + MESSAGE("The opposing Wobbuffet fainted!"); + } +} diff --git a/test/battle/move_effect/semi_invulnerable.c b/test/battle/move_effect/semi_invulnerable.c index d5bf90948884..331413121c14 100644 --- a/test/battle/move_effect/semi_invulnerable.c +++ b/test/battle/move_effect/semi_invulnerable.c @@ -3,18 +3,18 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_FLY].argument.twoTurnAttack.status) == STATUS3_ON_AIR); - ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_DIG].argument.twoTurnAttack.status) == STATUS3_UNDERGROUND); - ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_BOUNCE].argument.twoTurnAttack.status) == STATUS3_ON_AIR); - ASSUME(gMovesInfo[MOVE_DIVE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_DIVE].argument.twoTurnAttack.status) == STATUS3_UNDERWATER); - ASSUME(gMovesInfo[MOVE_PHANTOM_FORCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_PHANTOM_FORCE].argument.twoTurnAttack.status) == STATUS3_PHANTOM_FORCE); - ASSUME(gMovesInfo[MOVE_SHADOW_FORCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_SHADOW_FORCE].argument.twoTurnAttack.status) == STATUS3_PHANTOM_FORCE); + ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_FLY) == STATUS3_ON_AIR); + ASSUME(GetMoveEffect(MOVE_DIG) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_DIG) == STATUS3_UNDERGROUND); + ASSUME(GetMoveEffect(MOVE_BOUNCE) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_BOUNCE) == STATUS3_ON_AIR); + ASSUME(GetMoveEffect(MOVE_DIVE) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_DIVE) == STATUS3_UNDERWATER); + ASSUME(GetMoveEffect(MOVE_PHANTOM_FORCE) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_PHANTOM_FORCE) == STATUS3_PHANTOM_FORCE); + ASSUME(GetMoveEffect(MOVE_SHADOW_FORCE) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_SHADOW_FORCE) == STATUS3_PHANTOM_FORCE); } SINGLE_BATTLE_TEST("Semi-invulnerable moves make the user semi-invulnerable turn 1, then strike turn 2") diff --git a/test/battle/move_effect/shed_tail.c b/test/battle/move_effect/shed_tail.c index 1cdf74b0fd14..4667eab1ad20 100644 --- a/test/battle/move_effect/shed_tail.c +++ b/test/battle/move_effect/shed_tail.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SHED_TAIL].effect == EFFECT_SHED_TAIL); + ASSUME(GetMoveEffect(MOVE_SHED_TAIL) == EFFECT_SHED_TAIL); } SINGLE_BATTLE_TEST("Shed Tail creates a Substitute at the cost of 1/2 users maximum HP and switches the user out") @@ -110,8 +110,8 @@ SINGLE_BATTLE_TEST("Shed Tail creates a Substitute with 1/4 of user maximum heal PARAMETRIZE { hp = 164; } GIVEN { - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].argument.fixedDamage == 40); - ASSUME(gMovesInfo[MOVE_DRAGON_RAGE].effect == EFFECT_FIXED_DAMAGE_ARG); + ASSUME(GetMoveFixedDamage(MOVE_DRAGON_RAGE) == 40); + ASSUME(GetMoveEffect(MOVE_DRAGON_RAGE) == EFFECT_FIXED_DAMAGE_ARG); PLAYER(SPECIES_BULBASAUR) { MaxHP(hp); } PLAYER(SPECIES_BULBASAUR); OPPONENT(SPECIES_CHARMANDER); diff --git a/test/battle/move_effect/shell_trap.c b/test/battle/move_effect/shell_trap.c index d43893244a40..f121d1444d3d 100644 --- a/test/battle/move_effect/shell_trap.c +++ b/test/battle/move_effect/shell_trap.c @@ -3,10 +3,10 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].effect == EFFECT_SHELL_TRAP); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_WATER_GUN].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_LEER].category == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMoveEffect(MOVE_SHELL_TRAP) == EFFECT_SHELL_TRAP); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_WATER_GUN) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_LEER) == DAMAGE_CATEGORY_STATUS); } SINGLE_BATTLE_TEST("Shell Trap activates only if hit by a physical move") @@ -98,7 +98,7 @@ SINGLE_BATTLE_TEST("Shell Trap does not activate if battler faints before being DOUBLE_BATTLE_TEST("Shell Trap activates immediately after being hit on turn 1 and attacks both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_SHELL_TRAP) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } PLAYER(SPECIES_WOBBUFFET) { Speed(2); } OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } @@ -122,7 +122,7 @@ DOUBLE_BATTLE_TEST("Shell Trap activates immediately after being hit on turn 1 a DOUBLE_BATTLE_TEST("Shell Trap activates immediately after being hit on turn 2 and attacks both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_SHELL_TRAP) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } PLAYER(SPECIES_WOBBUFFET) { Speed(2); } OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } @@ -146,7 +146,7 @@ DOUBLE_BATTLE_TEST("Shell Trap activates immediately after being hit on turn 2 a DOUBLE_BATTLE_TEST("Shell Trap activates immediately after being hit on turn 3 and attacks both opponents") { GIVEN { - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_SHELL_TRAP) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } PLAYER(SPECIES_WOBBUFFET) { Speed(7); } OPPONENT(SPECIES_WOBBUFFET) { Speed(5); } @@ -170,7 +170,7 @@ DOUBLE_BATTLE_TEST("Shell Trap activates immediately after being hit on turn 3 a DOUBLE_BATTLE_TEST("Shell Trap targets correctly if one of the opponents has fainted") { GIVEN { - ASSUME(gMovesInfo[MOVE_SHELL_TRAP].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_SHELL_TRAP) == MOVE_TARGET_BOTH); PLAYER(SPECIES_GRENINJA) { Speed(60); } PLAYER(SPECIES_TURTONATOR) { Speed(10); } OPPONENT(SPECIES_BLASTOISE) { Speed(120); } diff --git a/test/battle/move_effect/simple_beam.c b/test/battle/move_effect/simple_beam.c index e91bf0b8ce0d..4250c8ce45d6 100644 --- a/test/battle/move_effect/simple_beam.c +++ b/test/battle/move_effect/simple_beam.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SIMPLE_BEAM].effect == EFFECT_SIMPLE_BEAM); + ASSUME(GetMoveEffect(MOVE_SIMPLE_BEAM) == EFFECT_SIMPLE_BEAM); } SINGLE_BATTLE_TEST("Simple Beam replaces target's ability with Simple") diff --git a/test/battle/move_effect/skill_swap.c b/test/battle/move_effect/skill_swap.c index 9c31ae59a7c9..c3c2ca91f4f0 100644 --- a/test/battle/move_effect/skill_swap.c +++ b/test/battle/move_effect/skill_swap.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SKILL_SWAP].effect == EFFECT_SKILL_SWAP); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); } SINGLE_BATTLE_TEST("Skill Swap swaps user and target's abilities") diff --git a/test/battle/move_effect/sleep.c b/test/battle/move_effect/sleep.c index 834f6066724b..702044d331d2 100644 --- a/test/battle/move_effect/sleep.c +++ b/test/battle/move_effect/sleep.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HYPNOSIS].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_HYPNOSIS) == EFFECT_SLEEP); } SINGLE_BATTLE_TEST("Hypnosis inflicts 1-3 turns of sleep") diff --git a/test/battle/move_effect/sleep_talk.c b/test/battle/move_effect/sleep_talk.c index 8ecd600f362d..4ac89e69d8ae 100644 --- a/test/battle/move_effect/sleep_talk.c +++ b/test/battle/move_effect/sleep_talk.c @@ -3,10 +3,10 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); - ASSUME(gMovesInfo[MOVE_RAZOR_WIND].sleepTalkBanned == TRUE); - ASSUME(gMovesInfo[MOVE_FLY].sleepTalkBanned == TRUE); - ASSUME(gMovesInfo[MOVE_DIG].sleepTalkBanned == TRUE); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); + ASSUME(IsMoveSleepTalkBanned(MOVE_RAZOR_WIND)); + ASSUME(IsMoveSleepTalkBanned(MOVE_FLY)); + ASSUME(IsMoveSleepTalkBanned(MOVE_DIG)); } SINGLE_BATTLE_TEST("Sleep Talk fails if not asleep") diff --git a/test/battle/move_effect/smelling_salts.c b/test/battle/move_effect/smelling_salts.c index 8d97ab8f0969..6b1d0b2d7ed6 100644 --- a/test/battle/move_effect/smelling_salts.c +++ b/test/battle/move_effect/smelling_salts.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_SMELLING_SALTS, MOVE_EFFECT_REMOVE_STATUS) == TRUE); - ASSUME(gMovesInfo[MOVE_SMELLING_SALTS].argument.status == STATUS1_PARALYSIS); + ASSUME(GetMoveEffectArg_Status(MOVE_SMELLING_SALTS) == STATUS1_PARALYSIS); } SINGLE_BATTLE_TEST("Smelling Salts does not cure paralyzed pokemons behind substitutes or get increased power") diff --git a/test/battle/move_effect/solar_beam.c b/test/battle/move_effect/solar_beam.c index 6fca334deedf..309d950c5096 100644 --- a/test/battle/move_effect/solar_beam.c +++ b/test/battle/move_effect/solar_beam.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); - ASSUME(gMovesInfo[MOVE_SOLAR_BLADE].argument.twoTurnAttack.status == B_WEATHER_SUN); + ASSUME(GetMoveEffect(MOVE_SOLAR_BEAM) == EFFECT_SOLAR_BEAM); + ASSUME(GetMoveTwoTurnAttackWeather(MOVE_SOLAR_BLADE) == B_WEATHER_SUN); } SINGLE_BATTLE_TEST("Solar Beam does not need a charging turn if Sun is up") diff --git a/test/battle/move_effect/sparkling_aria.c b/test/battle/move_effect/sparkling_aria.c index 24ac3c84bb0f..86b906228b72 100644 --- a/test/battle/move_effect/sparkling_aria.c +++ b/test/battle/move_effect/sparkling_aria.c @@ -4,8 +4,8 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_SPARKLING_ARIA, MOVE_EFFECT_REMOVE_STATUS) == TRUE); - ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].argument.status == STATUS1_BURN); - ASSUME(gMovesInfo[MOVE_SPARKLING_ARIA].soundMove == TRUE); + ASSUME(GetMoveEffectArg_Status(MOVE_SPARKLING_ARIA) == STATUS1_BURN); + ASSUME(IsSoundMove(MOVE_SPARKLING_ARIA)); } DOUBLE_BATTLE_TEST("Sparkling Aria cures burns from all Pokemon on the field and behind substitutes") diff --git a/test/battle/move_effect/special_attack_down.c b/test/battle/move_effect/special_attack_down.c index 60d015d1cddd..63ca071fc11e 100644 --- a/test/battle/move_effect/special_attack_down.c +++ b/test/battle/move_effect/special_attack_down.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_CONFIDE].effect == EFFECT_SPECIAL_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_CONFIDE) == EFFECT_SPECIAL_ATTACK_DOWN); } SINGLE_BATTLE_TEST("Confide lowers Special Attack", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Confide lowers Special Attack", s16 damage) PARAMETRIZE { lowerSpecialAttack = FALSE; } PARAMETRIZE { lowerSpecialAttack = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/special_attack_up_3.c b/test/battle/move_effect/special_attack_up_3.c index a701893f51f6..75f6c4b36dc6 100644 --- a/test/battle/move_effect/special_attack_up_3.c +++ b/test/battle/move_effect/special_attack_up_3.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TAIL_GLOW].effect == EFFECT_SPECIAL_ATTACK_UP_3); + ASSUME(GetMoveEffect(MOVE_TAIL_GLOW) == EFFECT_SPECIAL_ATTACK_UP_3); } SINGLE_BATTLE_TEST("Tail Glow drastically raises Special Attack", s16 damage) @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Tail Glow drastically raises Special Attack", s16 damage) PARAMETRIZE { raiseSpecialAttack = FALSE; } PARAMETRIZE { raiseSpecialAttack = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/speed_swap.c b/test/battle/move_effect/speed_swap.c new file mode 100644 index 000000000000..0a87b262365f --- /dev/null +++ b/test/battle/move_effect/speed_swap.c @@ -0,0 +1,58 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_SPEED_SWAP) == EFFECT_SPEED_SWAP); +} + +SINGLE_BATTLE_TEST("Speed Swap swaps user and target's speed stats") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Speed(6); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(10); } + }WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_SPEED_SWAP); } + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_TACKLE); } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPEED_SWAP, player); + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + } THEN { + EXPECT_EQ(player->speed, 10); + EXPECT_EQ(opponent->speed, 6); + } +} + +SINGLE_BATTLE_TEST("Speed Swap doesn't swap user and target's speed modifiers") +{ + u32 species, ability, move; + PARAMETRIZE { species = SPECIES_WOBBUFFET; ability = ABILITY_TELEPATHY; move = MOVE_ROCK_POLISH; } // x2.0 + PARAMETRIZE { species = SPECIES_PSYDUCK; ability = ABILITY_SWIFT_SWIM; move = MOVE_RAIN_DANCE; } // x2.0 + GIVEN { + ASSUME(GetMoveEffect(MOVE_ROCK_POLISH) == EFFECT_SPEED_UP_2); + ASSUME(GetMoveEffect(MOVE_RAIN_DANCE) == EFFECT_RAIN_DANCE); + PLAYER(SPECIES_WOBBUFFET) { Speed(8); } + OPPONENT(species) { Speed(10); Ability(ability); } + }WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SPEED_SWAP); } + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_TACKLE); } + } SCENE { + // Turn 1 + ANIMATION(ANIM_TYPE_MOVE, move, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPEED_SWAP, player); + // Turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); // Opponent is still first + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + } THEN { + EXPECT_EQ(player->speed, 10); + EXPECT_EQ(opponent->speed, 8); + if (move == MOVE_ROCK_POLISH) { + EXPECT_EQ(player->statStages[STAT_SPEED], DEFAULT_STAT_STAGE); + EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 2); + } + } +} diff --git a/test/battle/move_effect/spicy_extract.c b/test/battle/move_effect/spicy_extract.c index c9ddb3c30db0..b5fe1da0f10f 100644 --- a/test/battle/move_effect/spicy_extract.c +++ b/test/battle/move_effect/spicy_extract.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SPICY_EXTRACT].effect == EFFECT_SPICY_EXTRACT); + ASSUME(GetMoveEffect(MOVE_SPICY_EXTRACT) == EFFECT_SPICY_EXTRACT); } SINGLE_BATTLE_TEST("Spicy Extract raises target's Attack by 2 stages and lowers target's Defense by 2 stages") @@ -33,7 +33,7 @@ SINGLE_BATTLE_TEST("Spicy Extract is prevented by target's ability if it's Attac PARAMETRIZE { ability = ABILITY_LIGHT_METAL; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWORDS_DANCE].effect == EFFECT_ATTACK_UP_2); + ASSUME(GetMoveEffect(MOVE_SWORDS_DANCE) == EFFECT_ATTACK_UP_2); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BELDUM) { Ability(ability); } } WHEN { diff --git a/test/battle/move_effect/spikes.c b/test/battle/move_effect/spikes.c index 339a9f9a4bf1..187b9ce7acf3 100644 --- a/test/battle/move_effect/spikes.c +++ b/test/battle/move_effect/spikes.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SPIKES].effect == EFFECT_SPIKES); + ASSUME(GetMoveEffect(MOVE_SPIKES) == EFFECT_SPIKES); } SINGLE_BATTLE_TEST("Spikes damage on switch in") diff --git a/test/battle/move_effect/stealth_rock.c b/test/battle/move_effect/stealth_rock.c index 9a38f17a5ee5..d4399a2d0f0b 100644 --- a/test/battle/move_effect/stealth_rock.c +++ b/test/battle/move_effect/stealth_rock.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].effect == EFFECT_STEALTH_ROCK); + ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); } SINGLE_BATTLE_TEST("Stealth Rock damage on switch in based on typing") diff --git a/test/battle/move_effect/sticky_web.c b/test/battle/move_effect/sticky_web.c index e99368aa7d8d..ed0f6e5d93cc 100644 --- a/test/battle/move_effect/sticky_web.c +++ b/test/battle/move_effect/sticky_web.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB); + ASSUME(GetMoveEffect(MOVE_STICKY_WEB) == EFFECT_STICKY_WEB); } SINGLE_BATTLE_TEST("Sticky Web lowers Speed by 1 on switch-in") @@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Sticky Web can only be set up 1 time") DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explosion fainting both mons") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + ASSUME(GetMoveEffect(MOVE_EXPLOSION) == EFFECT_EXPLOSION); PLAYER(SPECIES_WOBBUFFET) {Speed(5);} PLAYER(SPECIES_WOBBUFFET) {HP(1500); Speed(10);} PLAYER(SPECIES_WOBBUFFET) {Speed(10);} @@ -197,7 +197,7 @@ DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no o PARAMETRIZE {hasReplacement = FALSE;} GIVEN { - ASSUME(gMovesInfo[MOVE_MEMENTO].effect == EFFECT_MEMENTO); + ASSUME(GetMoveEffect(MOVE_MEMENTO) == EFFECT_MEMENTO); PLAYER(SPECIES_SQUIRTLE) {Speed(5); } PLAYER(SPECIES_CHARMANDER) {Speed(5); } PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); Speed(5); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web. diff --git a/test/battle/move_effect/stockpile.c b/test/battle/move_effect/stockpile.c index f6c3f02a462d..f045fa68238c 100644 --- a/test/battle/move_effect/stockpile.c +++ b/test/battle/move_effect/stockpile.c @@ -4,9 +4,9 @@ // These tests cover all 3 effects: Stockpile, Spit up and Swallow. ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STOCKPILE].effect == EFFECT_STOCKPILE); - ASSUME(gMovesInfo[MOVE_SWALLOW].effect == EFFECT_SWALLOW); - ASSUME(gMovesInfo[MOVE_SPIT_UP].effect == EFFECT_SPIT_UP); + ASSUME(GetMoveEffect(MOVE_STOCKPILE) == EFFECT_STOCKPILE); + ASSUME(GetMoveEffect(MOVE_SWALLOW) == EFFECT_SWALLOW); + ASSUME(GetMoveEffect(MOVE_SPIT_UP) == EFFECT_SPIT_UP); } SINGLE_BATTLE_TEST("Stockpile's count can go up only to 3") @@ -148,8 +148,8 @@ SINGLE_BATTLE_TEST("Stockpile temporarily raises Def and Sp. Def", s16 dmgPyhsic PARAMETRIZE { move = MOVE_CELEBRATE; } GIVEN { ASSUME(B_STOCKPILE_RAISES_DEFS >= GEN_4); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET) { Speed(2); } OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } } WHEN { @@ -184,8 +184,8 @@ DOUBLE_BATTLE_TEST("Stockpile's Def and Sp. Def boost is lost after using Spit U PARAMETRIZE { count = 3; move = MOVE_SPIT_UP; } GIVEN { ASSUME(B_STOCKPILE_RAISES_DEFS >= GEN_4); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_GUST].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_GUST) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET) { Speed(4); HP(399); MaxHP(400); } PLAYER(SPECIES_WOBBUFFET) { Speed(3); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } diff --git a/test/battle/move_effect/stomping_tantrum.c b/test/battle/move_effect/stomping_tantrum.c index 32747282e420..c759de38b17d 100644 --- a/test/battle/move_effect/stomping_tantrum.c +++ b/test/battle/move_effect/stomping_tantrum.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STOMPING_TANTRUM].effect == EFFECT_STOMPING_TANTRUM); + ASSUME(GetMoveEffect(MOVE_STOMPING_TANTRUM) == EFFECT_STOMPING_TANTRUM); } SINGLE_BATTLE_TEST("Stomping Tatrum will deal double damage if user flinched on the previous turn") diff --git a/test/battle/move_effect/strength_sap.c b/test/battle/move_effect/strength_sap.c index 0246d0881f43..c38048ba8f2c 100644 --- a/test/battle/move_effect/strength_sap.c +++ b/test/battle/move_effect/strength_sap.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STRENGTH_SAP].effect == EFFECT_STRENGTH_SAP); + ASSUME(GetMoveEffect(MOVE_STRENGTH_SAP) == EFFECT_STRENGTH_SAP); } SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on target's Attack Stat", s16 hp) @@ -69,8 +69,8 @@ SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on tar } GIVEN { - ASSUME(gMovesInfo[MOVE_WORK_UP].effect == EFFECT_ATTACK_SPATK_UP); - ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN); + ASSUME(GetMoveEffect(MOVE_WORK_UP) == EFFECT_ATTACK_SPATK_UP); + ASSUME(GetMoveEffect(MOVE_GROWL) == EFFECT_ATTACK_DOWN); PLAYER(SPECIES_WOBBUFFET) { HP(50); } OPPONENT(SPECIES_WOBBUFFET) { Attack(60); } } WHEN { @@ -117,7 +117,7 @@ SINGLE_BATTLE_TEST("Strength Sap lowers Attack by 1 and restores HP based on tar SINGLE_BATTLE_TEST("Strength Sap fails if target is at -6 Atk") { GIVEN { - ASSUME(gMovesInfo[MOVE_CHARM].effect == EFFECT_ATTACK_DOWN_2); + ASSUME(GetMoveEffect(MOVE_CHARM) == EFFECT_ATTACK_DOWN_2); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -165,34 +165,3 @@ SINGLE_BATTLE_TEST("Strength Sap restores more HP if Big Root is held", s16 hp) EXPECT_GT(abs(results[1].hp), abs(results[0].hp)); } } - -SINGLE_BATTLE_TEST("Strength Sap makes attacker lose HP if target's ability is Liquid Ooze") -{ - s16 lostHp; - s32 atkStat; - - PARAMETRIZE { atkStat = 100; } - PARAMETRIZE { atkStat = 490; } // Checks that attacker can faint with no problems. - - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Attack(atkStat); Ability(ABILITY_LIQUID_OOZE); } - } WHEN { - TURN { MOVE(player, MOVE_STRENGTH_SAP); if (atkStat == 490) { SEND_OUT(player, 1); } } - } SCENE { - MESSAGE("Wobbuffet used Strength Sap!"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_STRENGTH_SAP, player); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("The opposing Wobbuffet's Attack fell!"); - ABILITY_POPUP(opponent, ABILITY_LIQUID_OOZE); - HP_BAR(player, captureDamage: &lostHp); - MESSAGE("Wobbuffet sucked up the liquid ooze!"); - if (atkStat >= 490) { - MESSAGE("Wobbuffet fainted!"); - SEND_IN_MESSAGE("Wobbuffet"); - } - } THEN { - EXPECT_EQ(lostHp, atkStat); - } -} diff --git a/test/battle/move_effect/stuff_cheeks.c b/test/battle/move_effect/stuff_cheeks.c index 3bb3f229254f..9e6a34c3068d 100644 --- a/test/battle/move_effect/stuff_cheeks.c +++ b/test/battle/move_effect/stuff_cheeks.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_STUFF_CHEEKS].effect == EFFECT_STUFF_CHEEKS); + ASSUME(GetMoveEffect(MOVE_STUFF_CHEEKS) == EFFECT_STUFF_CHEEKS); ASSUME(gItemsInfo[ITEM_LIECHI_BERRY].pocket == POCKET_BERRIES); ASSUME(gItemsInfo[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); } @@ -92,7 +92,7 @@ SINGLE_BATTLE_TEST("Stuff Cheeks can be used even if Magic Room is active") SINGLE_BATTLE_TEST("Stuff Cheeks fails if the user's berry is removed before they use the move") { GIVEN { - ASSUME(gMovesInfo[MOVE_KNOCK_OFF].effect == EFFECT_KNOCK_OFF); + ASSUME(GetMoveEffect(MOVE_KNOCK_OFF) == EFFECT_KNOCK_OFF); PLAYER(SPECIES_SKWOVET) { Item(ITEM_LIECHI_BERRY); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/substitute.c b/test/battle/move_effect/substitute.c index 92e894fa073f..e94767b6605f 100644 --- a/test/battle/move_effect/substitute.c +++ b/test/battle/move_effect/substitute.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SUBSTITUTE].effect == EFFECT_SUBSTITUTE); + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); } SINGLE_BATTLE_TEST("Substitute creates a Substitute at the cost of 1/4 users maximum HP") diff --git a/test/battle/move_effect/super_effective_on_arg.c b/test/battle/move_effect/super_effective_on_arg.c index d10b8a2231aa..2569ccb109ce 100644 --- a/test/battle/move_effect/super_effective_on_arg.c +++ b/test/battle/move_effect/super_effective_on_arg.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_FREEZE_DRY].effect == EFFECT_SUPER_EFFECTIVE_ON_ARG); + ASSUME(GetMoveEffect(MOVE_FREEZE_DRY) == EFFECT_SUPER_EFFECTIVE_ON_ARG); } SINGLE_BATTLE_TEST("Freeze Dry is super effective on water types") diff --git a/test/battle/move_effect/synthesis.c b/test/battle/move_effect/synthesis.c index e4a2b77869c6..6799bd28705a 100644 --- a/test/battle/move_effect/synthesis.c +++ b/test/battle/move_effect/synthesis.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SYNTHESIS].effect == EFFECT_SYNTHESIS); + ASSUME(GetMoveEffect(MOVE_SYNTHESIS) == EFFECT_SYNTHESIS); } SINGLE_BATTLE_TEST("Synthesis recovers 1/2 of the user's max HP") diff --git a/test/battle/move_effect/tailwind.c b/test/battle/move_effect/tailwind.c index 5fa53564512e..f105c9612ab6 100644 --- a/test/battle/move_effect/tailwind.c +++ b/test/battle/move_effect/tailwind.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND); + ASSUME(GetMoveEffect(MOVE_TAILWIND) == EFFECT_TAILWIND); } SINGLE_BATTLE_TEST("Tailwind applies for 4 turns") diff --git a/test/battle/move_effect/take_heart.c b/test/battle/move_effect/take_heart.c index 2961725b220b..e0294391034c 100644 --- a/test/battle/move_effect/take_heart.c +++ b/test/battle/move_effect/take_heart.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TAKE_HEART].effect == EFFECT_TAKE_HEART); + ASSUME(GetMoveEffect(MOVE_TAKE_HEART) == EFFECT_TAKE_HEART); } SINGLE_BATTLE_TEST("Take Heart increases Sp. Atk and Sp. Def by one stage") @@ -50,8 +50,8 @@ SINGLE_BATTLE_TEST("Take Heart cures the user of all status conditions") SINGLE_BATTLE_TEST("Take Heart cures sleep when used by Sleep Talk") { GIVEN { - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_SLEEP_TALK, MOVE_TAKE_HEART); } } WHEN { diff --git a/test/battle/move_effect/tar_shot.c b/test/battle/move_effect/tar_shot.c index 2b780577ecc0..f2aac4e55221 100644 --- a/test/battle/move_effect/tar_shot.c +++ b/test/battle/move_effect/tar_shot.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TAR_SHOT].effect == EFFECT_TAR_SHOT); + ASSUME(GetMoveEffect(MOVE_TAR_SHOT) == EFFECT_TAR_SHOT); } SINGLE_BATTLE_TEST("Tar Shot doubles the effectiveness of Fire-type moves used on the target") @@ -18,7 +18,7 @@ SINGLE_BATTLE_TEST("Tar Shot doubles the effectiveness of Fire-type moves used o ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC); ASSUME(gSpeciesInfo[SPECIES_OMASTAR].types[0] == TYPE_ROCK); ASSUME(gSpeciesInfo[SPECIES_OMASTAR].types[1] == TYPE_WATER); - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); GIVEN { PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/teatime.c b/test/battle/move_effect/teatime.c index dfdc70c80122..fc4ad2219872 100644 --- a/test/battle/move_effect/teatime.c +++ b/test/battle/move_effect/teatime.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TEATIME].effect == EFFECT_TEATIME); + ASSUME(GetMoveEffect(MOVE_TEATIME) == EFFECT_TEATIME); ASSUME(gItemsInfo[ITEM_LIECHI_BERRY].holdEffect == HOLD_EFFECT_ATTACK_UP); } diff --git a/test/battle/move_effect/telekinesis.c b/test/battle/move_effect/telekinesis.c index 746c42d053eb..31390d973359 100644 --- a/test/battle/move_effect/telekinesis.c +++ b/test/battle/move_effect/telekinesis.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TELEKINESIS].effect == EFFECT_TELEKINESIS); + ASSUME(GetMoveEffect(MOVE_TELEKINESIS) == EFFECT_TELEKINESIS); } SINGLE_BATTLE_TEST("Telekinesis makes the target unable to avoid any attacks made against it") { GIVEN { - ASSUME(gMovesInfo[MOVE_MINIMIZE].effect == EFFECT_MINIMIZE); // Raises evs by 2 - ASSUME(gMovesInfo[MOVE_SCREECH].accuracy < 100); + ASSUME(GetMoveEffect(MOVE_MINIMIZE) == EFFECT_MINIMIZE); // Raises evs by 2 + ASSUME(GetMoveAccuracy(MOVE_SCREECH) < 100); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); } WHEN { @@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Telekinesis ends after 3 turns") SINGLE_BATTLE_TEST("Telekinesis makes the target immune to Ground-type attacks") { GIVEN { - ASSUME(gMovesInfo[MOVE_BULLDOZE].type == TYPE_GROUND); + ASSUME(GetMoveType(MOVE_BULLDOZE) == TYPE_GROUND); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WYNAUT); } WHEN { diff --git a/test/battle/move_effect/teleport.c b/test/battle/move_effect/teleport.c index 3c79cb54ffb5..f77dffc658fe 100644 --- a/test/battle/move_effect/teleport.c +++ b/test/battle/move_effect/teleport.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TELEPORT].effect == EFFECT_TELEPORT); + ASSUME(GetMoveEffect(MOVE_TELEPORT) == EFFECT_TELEPORT); } SINGLE_BATTLE_TEST("Teleport fails when there is no pokemon to switch in") diff --git a/test/battle/move_effect/tera_blast.c b/test/battle/move_effect/tera_blast.c index 80e960a1affc..63e7a776b9a1 100644 --- a/test/battle/move_effect/tera_blast.c +++ b/test/battle/move_effect/tera_blast.c @@ -3,13 +3,13 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TERA_BLAST].effect == EFFECT_TERA_BLAST); + ASSUME(GetMoveEffect(MOVE_TERA_BLAST) == EFFECT_TERA_BLAST); } SINGLE_BATTLE_TEST("Tera Blast changes from Normal-type to the user's Tera Type") { GIVEN { - ASSUME(gMovesInfo[MOVE_TERA_BLAST].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TERA_BLAST) == TYPE_NORMAL); PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_DARK); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect/tera_starstorm.c b/test/battle/move_effect/tera_starstorm.c index b6b457164424..3077b38df913 100644 --- a/test/battle/move_effect/tera_starstorm.c +++ b/test/battle/move_effect/tera_starstorm.c @@ -3,13 +3,13 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TERA_STARSTORM].effect == EFFECT_TERA_STARSTORM); + ASSUME(GetMoveEffect(MOVE_TERA_STARSTORM) == EFFECT_TERA_STARSTORM); } SINGLE_BATTLE_TEST("Tera Starstorm changes from Normal-type to Stellar-type if used by Terapagos-Stellar") { GIVEN { - ASSUME(gMovesInfo[MOVE_TERA_STARSTORM].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TERA_STARSTORM) == TYPE_NORMAL); PLAYER(SPECIES_TERAPAGOS_STELLAR); OPPONENT(SPECIES_MISDREAVUS); } WHEN { @@ -25,7 +25,7 @@ SINGLE_BATTLE_TEST("Tera Starstorm changes from Normal-type to Stellar-type if u DOUBLE_BATTLE_TEST("Tera Starstorm targets both opponents in a double battle if used by Terapagos-Stellar") { GIVEN { - ASSUME(gMovesInfo[MOVE_TERA_STARSTORM].target == MOVE_TARGET_SELECTED); + ASSUME(GetMoveTarget(MOVE_TERA_STARSTORM) == MOVE_TARGET_SELECTED); PLAYER(SPECIES_TERAPAGOS_STELLAR); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -46,7 +46,7 @@ SINGLE_BATTLE_TEST("Tera Starstorm becomes a physical move if the user is Terapa PARAMETRIZE { tera = GIMMICK_NONE; } PARAMETRIZE { tera = GIMMICK_TERA; } GIVEN { - ASSUME(gMovesInfo[MOVE_TERA_STARSTORM].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_TERA_STARSTORM) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_TERAPAGOS_STELLAR) { Attack(100); SpAttack(50); } OPPONENT(SPECIES_WOBBUFFET) { Defense(200); SpDefense(200); } } WHEN { @@ -63,7 +63,7 @@ SINGLE_BATTLE_TEST("Tera Starstorm becomes a physical move if the user is Terapa SINGLE_BATTLE_TEST("Tera Starstorm remains Normal-type if used by Pokemon other than Terapagos") { GIVEN { - ASSUME(gMovesInfo[MOVE_TERA_STARSTORM].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_TERA_STARSTORM) == TYPE_NORMAL); ASSUME(gSpeciesInfo[SPECIES_MISDREAVUS].types[0] == TYPE_GHOST); PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } OPPONENT(SPECIES_MISDREAVUS); diff --git a/test/battle/move_effect/thousand_arrows.c b/test/battle/move_effect/thousand_arrows.c index 09e726fa2093..c62e71001d16 100644 --- a/test/battle/move_effect/thousand_arrows.c +++ b/test/battle/move_effect/thousand_arrows.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(MoveHasAdditionalEffect(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN) == TRUE); - ASSUME(gMovesInfo[MOVE_THOUSAND_ARROWS].ignoreTypeIfFlyingAndUngrounded == TRUE); + ASSUME(MoveHasAdditionalEffect(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN)); + ASSUME(MoveIgnoresTypeIfFlyingAndUngrounded(MOVE_THOUSAND_ARROWS) == TRUE); } SINGLE_BATTLE_TEST("Thousand Arrows does not ground mons behind substitutes") diff --git a/test/battle/move_effect/thunder.c b/test/battle/move_effect/thunder.c index 98a4979e7966..81ebd416ca7e 100644 --- a/test/battle/move_effect/thunder.c +++ b/test/battle/move_effect/thunder.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_THUNDER].effect == EFFECT_THUNDER); - ASSUME(gMovesInfo[MOVE_THUNDER].accuracy == 70); + ASSUME(GetMoveEffect(MOVE_THUNDER) == EFFECT_THUNDER); + ASSUME(GetMoveAccuracy(MOVE_THUNDER) == 70); } SINGLE_BATTLE_TEST("Thunder's accuracy is lowered to 50% in Sunlight") diff --git a/test/battle/move_effect/tidy_up.c b/test/battle/move_effect/tidy_up.c index fcb78ba962c3..9c934ab213fc 100644 --- a/test/battle/move_effect/tidy_up.c +++ b/test/battle/move_effect/tidy_up.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TIDY_UP].effect == EFFECT_TIDY_UP); + ASSUME(GetMoveEffect(MOVE_TIDY_UP) == EFFECT_TIDY_UP); } SINGLE_BATTLE_TEST("Tidy Up raises Attack and Speed by one") diff --git a/test/battle/move_effect/torment.c b/test/battle/move_effect/torment.c index dc911691b0f8..446d168de276 100644 --- a/test/battle/move_effect/torment.c +++ b/test/battle/move_effect/torment.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TORMENT].effect == EFFECT_TORMENT); + ASSUME(GetMoveEffect(MOVE_TORMENT) == EFFECT_TORMENT); } SINGLE_BATTLE_TEST("Torment prevents consecutive move uses") diff --git a/test/battle/move_effect/toxic.c b/test/battle/move_effect/toxic.c index 804ed56b8f75..7b8274a4417a 100644 --- a/test/battle/move_effect/toxic.c +++ b/test/battle/move_effect/toxic.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + ASSUME(GetMoveEffect(MOVE_TOXIC) == EFFECT_TOXIC); } SINGLE_BATTLE_TEST("Toxic inflicts bad poison") diff --git a/test/battle/move_effect/toxic_spikes.c b/test/battle/move_effect/toxic_spikes.c index fd18f57b97a4..70053b4a4449 100644 --- a/test/battle/move_effect/toxic_spikes.c +++ b/test/battle/move_effect/toxic_spikes.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + ASSUME(GetMoveEffect(MOVE_TOXIC_SPIKES) == EFFECT_TOXIC_SPIKES); } SINGLE_BATTLE_TEST("Toxic Spikes inflicts poison on switch in") @@ -212,7 +212,7 @@ SINGLE_BATTLE_TEST("Toxic Spikes are removed by Poison-type Pokémon affected by SINGLE_BATTLE_TEST("Toxic Spikes inflicts poison on switch in after Primal Reversed mon fainted") // Oddly specific, but encountered during testing { GIVEN { - ASSUME(gMovesInfo[MOVE_MEMENTO].effect == EFFECT_MEMENTO); // Faints the user. + ASSUME(GetMoveEffect(MOVE_MEMENTO) == EFFECT_MEMENTO); // Faints the user. PLAYER(SPECIES_WOBBUFFET) {Speed(5); } PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); Speed(1); } PLAYER(SPECIES_WYNAUT) {Speed(5); } diff --git a/test/battle/move_effect/triple_kick.c b/test/battle/move_effect/triple_kick.c index 9fe0ec60225e..5aeb1ea44249 100644 --- a/test/battle/move_effect/triple_kick.c +++ b/test/battle/move_effect/triple_kick.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_TRIPLE_KICK].effect == EFFECT_TRIPLE_KICK); + ASSUME(GetMoveEffect(MOVE_TRIPLE_KICK) == EFFECT_TRIPLE_KICK); } SINGLE_BATTLE_TEST("Triple Kick damage is increased by its base damage for each hit") diff --git a/test/battle/move_effect/two_turns_attack.c b/test/battle/move_effect/two_turns_attack.c index 8010d143569c..200fc72d1874 100644 --- a/test/battle/move_effect/two_turns_attack.c +++ b/test/battle/move_effect/two_turns_attack.c @@ -3,14 +3,14 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_RAZOR_WIND].effect == EFFECT_TWO_TURNS_ATTACK); - ASSUME(gMovesInfo[MOVE_SKULL_BASH].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(GetMoveEffect(MOVE_RAZOR_WIND) == EFFECT_TWO_TURNS_ATTACK); + ASSUME(GetMoveEffect(MOVE_SKULL_BASH) == EFFECT_TWO_TURNS_ATTACK); ASSUME(MoveHasAdditionalEffectSelf(MOVE_SKULL_BASH, MOVE_EFFECT_DEF_PLUS_1) == TRUE); - ASSUME(gMovesInfo[MOVE_SKY_ATTACK].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(GetMoveEffect(MOVE_SKY_ATTACK) == EFFECT_TWO_TURNS_ATTACK); // Electro shot - check for rain - ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].argument.twoTurnAttack.status == B_WEATHER_RAIN); - ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(GetMoveTwoTurnAttackWeather(MOVE_ELECTRO_SHOT) == B_WEATHER_RAIN); + ASSUME(GetMoveEffect(MOVE_ELECTRO_SHOT) == EFFECT_TWO_TURNS_ATTACK); ASSUME(MoveHasAdditionalEffectSelf(MOVE_ELECTRO_SHOT, MOVE_EFFECT_SP_ATK_PLUS_1) == TRUE); } diff --git a/test/battle/move_effect/upper_hand.c b/test/battle/move_effect/upper_hand.c index 69b2b75ef958..72a80a05426f 100644 --- a/test/battle/move_effect/upper_hand.c +++ b/test/battle/move_effect/upper_hand.c @@ -3,16 +3,16 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_UPPER_HAND].effect == EFFECT_UPPER_HAND); - ASSUME(gMovesInfo[MOVE_UPPER_HAND].priority == 3); + ASSUME(GetMoveEffect(MOVE_UPPER_HAND) == EFFECT_UPPER_HAND); + ASSUME(GetMovePriority(MOVE_UPPER_HAND) == 3); ASSUME(MoveHasAdditionalEffect(MOVE_UPPER_HAND, MOVE_EFFECT_FLINCH) == TRUE); } SINGLE_BATTLE_TEST("Upper Hand succeeds if the target is using a priority attacking move and causes it to flinch") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXTREME_SPEED].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_EXTREME_SPEED].priority == 2); + ASSUME(GetMoveCategory(MOVE_EXTREME_SPEED) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMovePriority(MOVE_EXTREME_SPEED) == 2); PLAYER(SPECIES_MIENSHAO); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -28,8 +28,8 @@ SINGLE_BATTLE_TEST("Upper Hand succeeds if the target is using a priority attack SINGLE_BATTLE_TEST("Upper Hand fails if the target is using a status move") { GIVEN { - ASSUME(gMovesInfo[MOVE_BABY_DOLL_EYES].category == DAMAGE_CATEGORY_STATUS); - ASSUME(gMovesInfo[MOVE_BABY_DOLL_EYES].priority == 1); + ASSUME(GetMoveCategory(MOVE_BABY_DOLL_EYES) == DAMAGE_CATEGORY_STATUS); + ASSUME(GetMovePriority(MOVE_BABY_DOLL_EYES) == 1); PLAYER(SPECIES_MIENSHAO); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -47,8 +47,8 @@ SINGLE_BATTLE_TEST("Upper Hand fails if the target is using a status move") SINGLE_BATTLE_TEST("Upper Hand fails if the target is not using a priority move") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAINING_KISS].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_DRAINING_KISS].priority == 0); + ASSUME(GetMoveCategory(MOVE_DRAINING_KISS) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMovePriority(MOVE_DRAINING_KISS) == 0); PLAYER(SPECIES_MIENSHAO); OPPONENT(SPECIES_COMFEY) { Ability(ABILITY_FLOWER_VEIL); } } WHEN { @@ -66,8 +66,8 @@ SINGLE_BATTLE_TEST("Upper Hand fails if the target is not using a priority move" SINGLE_BATTLE_TEST("Upper Hand succeeds if the target's move is boosted in priority by an Ability") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAINING_KISS].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_DRAINING_KISS].priority == 0); + ASSUME(GetMoveCategory(MOVE_DRAINING_KISS) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMovePriority(MOVE_DRAINING_KISS) == 0); PLAYER(SPECIES_MIENSHAO) { Speed(10); } OPPONENT(SPECIES_COMFEY) { Speed(5); Ability(ABILITY_TRIAGE); } } WHEN { @@ -83,8 +83,8 @@ SINGLE_BATTLE_TEST("Upper Hand succeeds if the target's move is boosted in prior SINGLE_BATTLE_TEST("Upper Hand fails if the target moves first") { GIVEN { - ASSUME(gMovesInfo[MOVE_DRAINING_KISS].category == DAMAGE_CATEGORY_SPECIAL); - ASSUME(gMovesInfo[MOVE_DRAINING_KISS].priority == 0); + ASSUME(GetMoveCategory(MOVE_DRAINING_KISS) == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMovePriority(MOVE_DRAINING_KISS) == 0); PLAYER(SPECIES_MIENSHAO) { Speed(5); } OPPONENT(SPECIES_COMFEY) { Speed(10); Ability(ABILITY_TRIAGE); } } WHEN { @@ -102,8 +102,8 @@ SINGLE_BATTLE_TEST("Upper Hand fails if the target moves first") SINGLE_BATTLE_TEST("Upper Hand is boosted by Sheer Force") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXTREME_SPEED].category == DAMAGE_CATEGORY_PHYSICAL); - ASSUME(gMovesInfo[MOVE_EXTREME_SPEED].priority == 2); + ASSUME(GetMoveCategory(MOVE_EXTREME_SPEED) == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMovePriority(MOVE_EXTREME_SPEED) == 2); ASSUME(MoveIsAffectedBySheerForce(MOVE_UPPER_HAND) == TRUE); PLAYER(SPECIES_HARIYAMA) { Ability(ABILITY_SHEER_FORCE); } OPPONENT(SPECIES_WOBBUFFET); @@ -124,7 +124,7 @@ AI_SINGLE_BATTLE_TEST("AI won't use Upper Hand unless it has seen a priority mov PARAMETRIZE { move = MOVE_QUICK_ATTACK; } GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); - ASSUME(gMovesInfo[MOVE_QUICK_ATTACK].priority == 1); + ASSUME(GetMovePriority(MOVE_QUICK_ATTACK) == 1); PLAYER(SPECIES_WOBBUFFET) {Moves(move); } OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_UPPER_HAND, MOVE_KARATE_CHOP); } } WHEN { diff --git a/test/battle/move_effect/uproar.c b/test/battle/move_effect/uproar.c index a97422390f65..cbe17ce066c3 100644 --- a/test/battle/move_effect/uproar.c +++ b/test/battle/move_effect/uproar.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_UPROAR].effect == EFFECT_UPROAR); + ASSUME(GetMoveEffect(MOVE_UPROAR) == EFFECT_UPROAR); } DOUBLE_BATTLE_TEST("Uproar status causes sleeping pokemon to wake up during an attack") diff --git a/test/battle/move_effect/wake_up_slap.c b/test/battle/move_effect/wake_up_slap.c index e4d7c2e6166c..0e172bf053d8 100644 --- a/test/battle/move_effect/wake_up_slap.c +++ b/test/battle/move_effect/wake_up_slap.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_WAKE_UP_SLAP, MOVE_EFFECT_REMOVE_STATUS) == TRUE); - ASSUME(gMovesInfo[MOVE_WAKE_UP_SLAP].argument.status == STATUS1_SLEEP); + ASSUME(GetMoveEffectArg_Status(MOVE_WAKE_UP_SLAP) == STATUS1_SLEEP); } SINGLE_BATTLE_TEST("Wake-Up Slap does not cure paralyzed pokemons behind substitutes or get increased power") diff --git a/test/battle/move_effect/weather_ball.c b/test/battle/move_effect/weather_ball.c index 432e5f79f737..047438348352 100644 --- a/test/battle/move_effect/weather_ball.c +++ b/test/battle/move_effect/weather_ball.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WEATHER_BALL].effect == EFFECT_WEATHER_BALL); + ASSUME(GetMoveEffect(MOVE_WEATHER_BALL) == EFFECT_WEATHER_BALL); } SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to a Fire-type move in Sunlight", s16 damage) diff --git a/test/battle/move_effect/worry_seed.c b/test/battle/move_effect/worry_seed.c index 3e74c883e738..c4b18b7cabd2 100644 --- a/test/battle/move_effect/worry_seed.c +++ b/test/battle/move_effect/worry_seed.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_WORRY_SEED].effect == EFFECT_WORRY_SEED); + ASSUME(GetMoveEffect(MOVE_WORRY_SEED) == EFFECT_WORRY_SEED); } SINGLE_BATTLE_TEST("Worry Seed replaces target's ability with Insomnia") diff --git a/test/battle/move_effect_secondary/bug_bite.c b/test/battle/move_effect_secondary/bug_bite.c index fdf9b05cf40a..e086941a5e30 100644 --- a/test/battle/move_effect_secondary/bug_bite.c +++ b/test/battle/move_effect_secondary/bug_bite.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_BUG_BITE, MOVE_EFFECT_BUG_BITE)); - ASSUME(gMovesInfo[MOVE_BUG_BITE].pp == 20); + ASSUME(GetMovePP(MOVE_BUG_BITE) == 20); } // Pretty much copy/paste of the Berry Fling Test. diff --git a/test/battle/move_effect_secondary/burn.c b/test/battle/move_effect_secondary/burn.c index 9801ad1f2571..0bc979f08ec7 100644 --- a/test/battle/move_effect_secondary/burn.c +++ b/test/battle/move_effect_secondary/burn.c @@ -43,7 +43,7 @@ DOUBLE_BATTLE_TEST("Lava Plume inflicts burn to all adjacent battlers") { GIVEN { ASSUME(MoveHasAdditionalEffect(MOVE_LAVA_PLUME, MOVE_EFFECT_BURN) == TRUE); - ASSUME(gMovesInfo[MOVE_LAVA_PLUME].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_LAVA_PLUME) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -111,7 +111,7 @@ SINGLE_BATTLE_TEST("Scald shouldn't burn a Water-type Pokémon") GIVEN { ASSUME(gSpeciesInfo[SPECIES_SQUIRTLE].types[0] == TYPE_WATER); ASSUME(MoveHasAdditionalEffect(MOVE_SCALD, MOVE_EFFECT_BURN) == TRUE); - ASSUME(gMovesInfo[MOVE_SCALD].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_SCALD) == TYPE_WATER); PLAYER(SPECIES_SQUIRTLE); OPPONENT(SPECIES_SQUIRTLE); } WHEN { diff --git a/test/battle/move_effect_secondary/freeze.c b/test/battle/move_effect_secondary/freeze.c index 45005cf5d7da..bfaadcebe1b0 100644 --- a/test/battle/move_effect_secondary/freeze.c +++ b/test/battle/move_effect_secondary/freeze.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_POWDER_SNOW, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE); - ASSUME(gMovesInfo[MOVE_BLIZZARD].accuracy == 70); + ASSUME(GetMoveAccuracy(MOVE_BLIZZARD) == 70); } #if B_USE_FROSTBITE == TRUE @@ -92,7 +92,7 @@ SINGLE_BATTLE_TEST("Freezing Glare shouldn't freeze Psychic-types") GIVEN { ASSUME(gSpeciesInfo[SPECIES_ARTICUNO_GALAR].types[0] == TYPE_PSYCHIC); ASSUME(MoveHasAdditionalEffect(MOVE_FREEZING_GLARE, MOVE_EFFECT_FREEZE_OR_FROSTBITE) == TRUE); - ASSUME(gMovesInfo[MOVE_FREEZING_GLARE].type == TYPE_PSYCHIC); + ASSUME(GetMoveType(MOVE_FREEZING_GLARE) == TYPE_PSYCHIC); PLAYER(SPECIES_ARTICUNO_GALAR); OPPONENT(SPECIES_ARTICUNO_GALAR); } WHEN { diff --git a/test/battle/move_effect_secondary/ion_deluge.c b/test/battle/move_effect_secondary/ion_deluge.c index efc66903bc5f..e5bf7c08101a 100644 --- a/test/battle/move_effect_secondary/ion_deluge.c +++ b/test/battle/move_effect_secondary/ion_deluge.c @@ -9,7 +9,7 @@ ASSUMPTIONS SINGLE_BATTLE_TEST("Ion Duldge turns normal moves into electric for the remainder of the current turn") { GIVEN { - ASSUME(gMovesInfo[MOVE_ION_DELUGE].effect == EFFECT_ION_DELUGE); + ASSUME(GetMoveEffect(MOVE_ION_DELUGE) == EFFECT_ION_DELUGE); PLAYER(SPECIES_KRABBY); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_effect_secondary/order_up.c b/test/battle/move_effect_secondary/order_up.c index 8d286850a28b..ec6f1c51b533 100644 --- a/test/battle/move_effect_secondary/order_up.c +++ b/test/battle/move_effect_secondary/order_up.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_ORDER_UP].additionalEffects[0].moveEffect == MOVE_EFFECT_ORDER_UP); + ASSUME(GetMoveAdditionalEffectById(MOVE_ORDER_UP, 0)->moveEffect == MOVE_EFFECT_ORDER_UP); } DOUBLE_BATTLE_TEST("Order Up increases a stat based on Tatsugiri's form") @@ -123,7 +123,7 @@ DOUBLE_BATTLE_TEST("Order up does not boosts any stats if Dondozo is not affecte DOUBLE_BATTLE_TEST("Order Up is boosted by Sheer Force without removing the stat boosting effect") { GIVEN { - ASSUME(gMovesInfo[MOVE_ENTRAINMENT].effect == EFFECT_ENTRAINMENT); + ASSUME(GetMoveEffect(MOVE_ENTRAINMENT) == EFFECT_ENTRAINMENT); PLAYER(SPECIES_DONDOZO) { Speed(10); } PLAYER(SPECIES_TATSUGIRI_CURLY) { Speed(9); } OPPONENT(SPECIES_WOBBUFFET) { Speed(8); } @@ -146,8 +146,8 @@ DOUBLE_BATTLE_TEST("Order Up is always boosted by Sheer Force", s16 damage) PARAMETRIZE(move = MOVE_ENTRAINMENT, ability = ABILITY_COMMANDER); GIVEN { - ASSUME(gMovesInfo[MOVE_HAZE].effect == EFFECT_HAZE); - ASSUME(gMovesInfo[MOVE_ENTRAINMENT].effect == EFFECT_ENTRAINMENT); + ASSUME(GetMoveEffect(MOVE_HAZE) == EFFECT_HAZE); + ASSUME(GetMoveEffect(MOVE_ENTRAINMENT) == EFFECT_ENTRAINMENT); PLAYER(SPECIES_DONDOZO) { Speed(10); } PLAYER(SPECIES_TATSUGIRI_CURLY) { Speed(9); Ability(ability); } OPPONENT(SPECIES_TAUROS) { Speed(21); Ability(ABILITY_SHEER_FORCE); } diff --git a/test/battle/move_effect_secondary/paralysis.c b/test/battle/move_effect_secondary/paralysis.c index 0e9d9589a862..711ca11ee8ac 100644 --- a/test/battle/move_effect_secondary/paralysis.c +++ b/test/battle/move_effect_secondary/paralysis.c @@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Body Slam shouldn't paralyze Normal-types") GIVEN { ASSUME(gSpeciesInfo[SPECIES_TAUROS].types[0] == TYPE_NORMAL); ASSUME(MoveHasAdditionalEffect(MOVE_BODY_SLAM, MOVE_EFFECT_PARALYSIS) == TRUE); - ASSUME(gMovesInfo[MOVE_BODY_SLAM].type == TYPE_NORMAL); + ASSUME(GetMoveType(MOVE_BODY_SLAM) == TYPE_NORMAL); PLAYER(SPECIES_TAUROS); OPPONENT(SPECIES_TAUROS); } WHEN { diff --git a/test/battle/move_effect_secondary/psychic_noise.c b/test/battle/move_effect_secondary/psychic_noise.c index e44ae75abe44..8e5eae4efb4a 100644 --- a/test/battle/move_effect_secondary/psychic_noise.c +++ b/test/battle/move_effect_secondary/psychic_noise.c @@ -4,7 +4,7 @@ ASSUMPTIONS { ASSUME(MoveHasAdditionalEffect(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE)); - ASSUME(gMovesInfo[MOVE_RECOVER].effect == EFFECT_RESTORE_HP); + ASSUME(GetMoveEffect(MOVE_RECOVER) == EFFECT_RESTORE_HP); } SINGLE_BATTLE_TEST("Psychic Noise blocks healing moves for 2 turns") diff --git a/test/battle/move_effects_combined/axe_kick.c b/test/battle/move_effects_combined/axe_kick.c index 94ab9377ad3d..5cc5b9b90c68 100644 --- a/test/battle/move_effects_combined/axe_kick.c +++ b/test/battle/move_effects_combined/axe_kick.c @@ -3,7 +3,7 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_AXE_KICK].effect == EFFECT_RECOIL_IF_MISS); + ASSUME(GetMoveEffect(MOVE_AXE_KICK) == EFFECT_RECOIL_IF_MISS); ASSUME(MoveHasAdditionalEffect(MOVE_AXE_KICK, MOVE_EFFECT_CONFUSION) == TRUE); } diff --git a/test/battle/move_effects_combined/barb_barrage.c b/test/battle/move_effects_combined/barb_barrage.c index cedb671b8604..62f78cd4cf8f 100644 --- a/test/battle/move_effects_combined/barb_barrage.c +++ b/test/battle/move_effects_combined/barb_barrage.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_BARB_BARRAGE].argument.status == STATUS1_PSN_ANY); + ASSUME(GetMoveEffect(MOVE_BARB_BARRAGE) == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(GetMoveEffectArg_Status(MOVE_BARB_BARRAGE) == STATUS1_PSN_ANY); ASSUME(MoveHasAdditionalEffect(MOVE_BARB_BARRAGE, MOVE_EFFECT_POISON) == TRUE); } diff --git a/test/battle/move_effects_combined/hurricane.c b/test/battle/move_effects_combined/hurricane.c index 6e9228ddaf64..02620f4d0596 100644 --- a/test/battle/move_effects_combined/hurricane.c +++ b/test/battle/move_effects_combined/hurricane.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_HURRICANE].effect == EFFECT_THUNDER); - ASSUME(gMovesInfo[MOVE_HURRICANE].accuracy == 70); + ASSUME(GetMoveEffect(MOVE_HURRICANE) == EFFECT_THUNDER); + ASSUME(GetMoveAccuracy(MOVE_HURRICANE) == 70); } SINGLE_BATTLE_TEST("Hurricane's accuracy is lowered to 50% in Sunlight") @@ -39,10 +39,10 @@ SINGLE_BATTLE_TEST("Hurricane can hit airborne targets (Fly, Bounce)") PARAMETRIZE { move = MOVE_FLY; } PARAMETRIZE { move = MOVE_BOUNCE; } GIVEN { - ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_FLY].argument.twoTurnAttack.status) == STATUS3_ON_AIR); - ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_BOUNCE].argument.twoTurnAttack.status) == STATUS3_ON_AIR); + ASSUME(GetMoveEffect(MOVE_FLY) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_FLY) == STATUS3_ON_AIR); + ASSUME(GetMoveEffect(MOVE_BOUNCE) == EFFECT_SEMI_INVULNERABLE); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_BOUNCE) == STATUS3_ON_AIR); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Moves(move); } } WHEN { @@ -57,8 +57,8 @@ SINGLE_BATTLE_TEST("Hurricane can hit airborne targets (Fly, Bounce)") DOUBLE_BATTLE_TEST("Hurricane can hit airborne targets (Sky Drop)") { GIVEN { - ASSUME(gMovesInfo[MOVE_SKY_DROP].effect == EFFECT_SKY_DROP); - ASSUME(UNCOMPRESS_BITS(gMovesInfo[MOVE_SKY_DROP].argument.twoTurnAttack.status) == STATUS3_ON_AIR); + ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP); + ASSUME(GetMoveTwoTurnAttackStatus(MOVE_SKY_DROP) == STATUS3_ON_AIR); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effects_combined/infernal_parade.c b/test/battle/move_effects_combined/infernal_parade.c index 890f8f9dc5e5..266718d2e986 100644 --- a/test/battle/move_effects_combined/infernal_parade.c +++ b/test/battle/move_effects_combined/infernal_parade.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].argument.status == STATUS1_ANY); + ASSUME(GetMoveEffect(MOVE_INFERNAL_PARADE) == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(GetMoveEffectArg_Status(MOVE_INFERNAL_PARADE) == STATUS1_ANY); ASSUME(MoveHasAdditionalEffect(MOVE_INFERNAL_PARADE, MOVE_EFFECT_BURN) == TRUE); } diff --git a/test/battle/move_effects_combined/make_it_rain.c b/test/battle/move_effects_combined/make_it_rain.c index 5469eac8a5d4..e0e00015a489 100644 --- a/test/battle/move_effects_combined/make_it_rain.c +++ b/test/battle/move_effects_combined/make_it_rain.c @@ -12,7 +12,7 @@ SINGLE_BATTLE_TEST("Make It Rain lowers special attack by one stage") s16 damage[2]; GIVEN { - ASSUME(gMovesInfo[MOVE_MAKE_IT_RAIN].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_MAKE_IT_RAIN) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -58,3 +58,46 @@ DOUBLE_BATTLE_TEST("Make It Rain lowers special attack by one stage if it hits b MESSAGE("Wobbuffet's Sp. Atk fell!"); } } + +DOUBLE_BATTLE_TEST("Make It Rain lowers special attack by one stage if it hits both targets") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_MAKE_IT_RAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAKE_IT_RAIN, playerLeft); + HP_BAR(opponentLeft); + NONE_OF { + MESSAGE("Coins were scattered everywhere!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Wobbuffet's Sp. Atk fell!"); + } + HP_BAR(opponentRight); + MESSAGE("Coins were scattered everywhere!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Wobbuffet's Sp. Atk fell!"); + } +} +DOUBLE_BATTLE_TEST("Make It Rain lowers special attack by one stage if second target Protects") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentRight, MOVE_PROTECT); MOVE(playerLeft, MOVE_MAKE_IT_RAIN); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PROTECT, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MAKE_IT_RAIN, playerLeft); + HP_BAR(opponentLeft); + NOT HP_BAR(opponentRight); + MESSAGE("Coins were scattered everywhere!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); + MESSAGE("Wobbuffet's Sp. Atk fell!"); + } +} diff --git a/test/battle/move_effects_combined/triple_arrows.c b/test/battle/move_effects_combined/triple_arrows.c index ad7878fdc93e..4fd040e32a17 100644 --- a/test/battle/move_effects_combined/triple_arrows.c +++ b/test/battle/move_effects_combined/triple_arrows.c @@ -49,7 +49,7 @@ SINGLE_BATTLE_TEST("Triple Arrows lands a critical hit") PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); GIVEN { ASSUME(B_CRIT_CHANCE >= GEN_7); - ASSUME(gMovesInfo[MOVE_TRIPLE_ARROWS].criticalHitStage == 1); + ASSUME(GetMoveCriticalHitStage(MOVE_TRIPLE_ARROWS) == 1); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_flags/cant_use_twice.c b/test/battle/move_flags/cant_use_twice.c index 99bd681acb2e..cba5596d267d 100644 --- a/test/battle/move_flags/cant_use_twice.c +++ b/test/battle/move_flags/cant_use_twice.c @@ -3,8 +3,8 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_GIGATON_HAMMER].cantUseTwice == TRUE); - ASSUME(gMovesInfo[MOVE_BLOOD_MOON].cantUseTwice == TRUE); + ASSUME(MoveCantBeUsedTwice(MOVE_GIGATON_HAMMER) == TRUE); + ASSUME(MoveCantBeUsedTwice(MOVE_BLOOD_MOON) == TRUE); } SINGLE_BATTLE_TEST("Struggle will be used if slow Encore is used on moves with the cantUseTwice flag") @@ -13,7 +13,7 @@ SINGLE_BATTLE_TEST("Struggle will be used if slow Encore is used on moves with t PARAMETRIZE { move = MOVE_GIGATON_HAMMER; } PARAMETRIZE { move = MOVE_BLOOD_MOON; } GIVEN { - ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Moves with the cantUseTwice flag strike again if fast encore PARAMETRIZE { move = MOVE_GIGATON_HAMMER; } PARAMETRIZE { move = MOVE_BLOOD_MOON; } GIVEN { - ASSUME(gMovesInfo[MOVE_ENCORE].effect == EFFECT_ENCORE); + ASSUME(GetMoveEffect(MOVE_ENCORE) == EFFECT_ENCORE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/move_flags/damages_airborne_double_damage.c b/test/battle/move_flags/damages_airborne_double_damage.c index dcdb801ff655..adeac7d3a218 100644 --- a/test/battle/move_flags/damages_airborne_double_damage.c +++ b/test/battle/move_flags/damages_airborne_double_damage.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Being airborne causes the target to take double damage from PARAMETRIZE { useDive = FALSE; } PARAMETRIZE { useDive = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TWISTER].damagesAirborneDoubleDamage); + ASSUME(MoveDamagesAirborneDoubleDamage(MOVE_TWISTER)); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } } WHEN { diff --git a/test/battle/move_flags/damages_underground.c b/test/battle/move_flags/damages_underground.c index 97b792b4dd1e..7d4b8cd9464b 100644 --- a/test/battle/move_flags/damages_underground.c +++ b/test/battle/move_flags/damages_underground.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Being underground causes the target to take double damage fr PARAMETRIZE { useDig = FALSE; } PARAMETRIZE { useDig = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].damagesUnderground); + ASSUME(MoveDamagesUnderground(MOVE_EARTHQUAKE)); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } } WHEN { diff --git a/test/battle/move_flags/damages_underwater.c b/test/battle/move_flags/damages_underwater.c index a7269a016263..b313d044c280 100644 --- a/test/battle/move_flags/damages_underwater.c +++ b/test/battle/move_flags/damages_underwater.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Being underwater causes the target to take double damage fro PARAMETRIZE { useDive = FALSE; } PARAMETRIZE { useDive = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SURF].damagesUnderwater); + ASSUME(MoveDamagesUnderWater(MOVE_SURF)); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } } WHEN { diff --git a/test/battle/move_flags/ignores_target_ability.c b/test/battle/move_flags/ignores_target_ability.c index 2836f4838ec0..f4f9ff30a724 100644 --- a/test/battle/move_flags/ignores_target_ability.c +++ b/test/battle/move_flags/ignores_target_ability.c @@ -3,9 +3,9 @@ ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SUNSTEEL_STRIKE].ignoresTargetAbility); - ASSUME(gMovesInfo[MOVE_MOONGEIST_BEAM].ignoresTargetAbility); - ASSUME(gMovesInfo[MOVE_PHOTON_GEYSER].ignoresTargetAbility); + ASSUME(MoveIgnoresTargetAbility(MOVE_SUNSTEEL_STRIKE)); + ASSUME(MoveIgnoresTargetAbility(MOVE_MOONGEIST_BEAM)); + ASSUME(MoveIgnoresTargetAbility(MOVE_PHOTON_GEYSER)); } SINGLE_BATTLE_TEST("ignoresTargetAbility moves do not ignore the attacker's own ability", s16 damage) @@ -20,19 +20,19 @@ SINGLE_BATTLE_TEST("ignoresTargetAbility moves do not ignore the attacker's own PARAMETRIZE { move = MOVE_PHOTON_GEYSER; ability = ABILITY_UNAWARE; } ASSUME(gAbilitiesInfo[ABILITY_UNAWARE].breakable); - ASSUME(gMovesInfo[MOVE_IRON_DEFENSE].effect == EFFECT_DEFENSE_UP_2); - ASSUME(gMovesInfo[MOVE_AMNESIA].effect == EFFECT_SPECIAL_DEFENSE_UP_2); + ASSUME(GetMoveEffect(MOVE_IRON_DEFENSE) == EFFECT_DEFENSE_UP_2); + ASSUME(GetMoveEffect(MOVE_AMNESIA) == EFFECT_SPECIAL_DEFENSE_UP_2); GIVEN { PLAYER(SPECIES_CLEFABLE) { Speed(1); Ability(ability); } OPPONENT(SPECIES_ARON) { Speed(2); } } WHEN { - if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL) + if (GetMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL) TURN { MOVE(opponent, MOVE_IRON_DEFENSE); MOVE(player, move); } else TURN { MOVE(opponent, MOVE_AMNESIA); MOVE(player, move); } } SCENE { - if (gMovesInfo[move].category == DAMAGE_CATEGORY_PHYSICAL) + if (GetMoveCategory(move) == DAMAGE_CATEGORY_PHYSICAL) ANIMATION(ANIM_TYPE_MOVE, MOVE_IRON_DEFENSE, opponent); else ANIMATION(ANIM_TYPE_MOVE, MOVE_AMNESIA, opponent); diff --git a/test/battle/move_flags/minimize_double_damage.c b/test/battle/move_flags/minimize_double_damage.c index f3cdd7657f06..fd44077c4fa0 100644 --- a/test/battle/move_flags/minimize_double_damage.c +++ b/test/battle/move_flags/minimize_double_damage.c @@ -7,8 +7,8 @@ SINGLE_BATTLE_TEST("MinimizeDoubleDamage flag makes moves cause double damage to PARAMETRIZE { useMinimize = FALSE; } PARAMETRIZE { useMinimize = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_MINIMIZE].effect == EFFECT_MINIMIZE); - ASSUME(gMovesInfo[MOVE_STEAMROLLER].minimizeDoubleDamage); + ASSUME(GetMoveEffect(MOVE_MINIMIZE) == EFFECT_MINIMIZE); + ASSUME(MoveIncreasesPowerToMinimizedTargets(MOVE_STEAMROLLER)); PLAYER(SPECIES_WOBBUFFET) { Speed(1); } OPPONENT(SPECIES_WOBBUFFET) { Speed(2); } } WHEN { diff --git a/test/battle/move_flags/powder.c b/test/battle/move_flags/powder.c index 35a6e1012b28..04920f79f303 100644 --- a/test/battle/move_flags/powder.c +++ b/test/battle/move_flags/powder.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon") { GIVEN { - ASSUME(gMovesInfo[MOVE_STUN_SPORE].powderMove); + ASSUME(IsPowderMove(MOVE_STUN_SPORE)); ASSUME(gSpeciesInfo[SPECIES_ODDISH].types[0] == TYPE_GRASS); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ODDISH); diff --git a/test/battle/move_flags/recoil.c b/test/battle/move_flags/recoil.c index bdada8a11479..dede6289da06 100644 --- a/test/battle/move_flags/recoil.c +++ b/test/battle/move_flags/recoil.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Take Down deals 25% of recoil damage to the user") s16 recoilDamage; GIVEN { - ASSUME(gMovesInfo[MOVE_TAKE_DOWN].recoil == 25); + ASSUME(GetMoveRecoil(MOVE_TAKE_DOWN) == 25); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -27,7 +27,7 @@ SINGLE_BATTLE_TEST("Double Edge deals 33% of recoil damage to the user") s16 recoilDamage; GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_EDGE].recoil == 33); + ASSUME(GetMoveRecoil(MOVE_DOUBLE_EDGE) == 33); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -47,7 +47,7 @@ SINGLE_BATTLE_TEST("Head Smash deals 50% of recoil damage to the user") s16 recoilDamage; GIVEN { - ASSUME(gMovesInfo[MOVE_HEAD_SMASH].recoil == 50); + ASSUME(GetMoveRecoil(MOVE_HEAD_SMASH) == 50); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -67,7 +67,7 @@ SINGLE_BATTLE_TEST("Flare Blitz deals 33% of recoil damage to the user and can b s16 recoilDamage; GIVEN { - ASSUME(gMovesInfo[MOVE_FLARE_BLITZ].recoil == 33); + ASSUME(GetMoveRecoil(MOVE_FLARE_BLITZ) == 33); ASSUME(MoveHasAdditionalEffect(MOVE_FLARE_BLITZ, MOVE_EFFECT_BURN)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); diff --git a/test/battle/move_flags/strike_count.c b/test/battle/move_flags/strike_count.c index ba71e35c263d..80a6f2435908 100644 --- a/test/battle/move_flags/strike_count.c +++ b/test/battle/move_flags/strike_count.c @@ -4,7 +4,7 @@ SINGLE_BATTLE_TEST("Two strike count turns a move into a 2-hit move") { GIVEN { - ASSUME(gMovesInfo[MOVE_DOUBLE_KICK].strikeCount == 2); + ASSUME(GetMoveStrikeCount(MOVE_DOUBLE_KICK) == 2); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Three strike count turns a move into a 3-hit move") s16 thirdHit; GIVEN { - ASSUME(gMovesInfo[MOVE_TRIPLE_DIVE].strikeCount == 3); + ASSUME(GetMoveStrikeCount(MOVE_TRIPLE_DIVE) == 3); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -49,8 +49,8 @@ SINGLE_BATTLE_TEST("Surging Strikes hits 3 times with each hit being a critical s16 thirdHit; GIVEN { - ASSUME(gMovesInfo[MOVE_SURGING_STRIKES].strikeCount == 3); - ASSUME(gMovesInfo[MOVE_SURGING_STRIKES].alwaysCriticalHit == TRUE); + ASSUME(GetMoveStrikeCount(MOVE_SURGING_STRIKES) == 3); + ASSUME(MoveAlwaysCrits(MOVE_SURGING_STRIKES)); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/sleep_clause.c b/test/battle/sleep_clause.c index f0f8f2906d37..a5f28f4f22f0 100644 --- a/test/battle/sleep_clause.c +++ b/test/battle/sleep_clause.c @@ -5,7 +5,7 @@ AI_SINGLE_BATTLE_TEST("Sleep Clause: AI will not use sleep moves while sleep cla { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -21,7 +21,7 @@ AI_DOUBLE_BATTLE_TEST("Sleep Clause: AI will not use sleep moves while sleep cla { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -39,7 +39,7 @@ AI_DOUBLE_BATTLE_TEST("Sleep Clause: AI will not use sleep move if partner is al { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -55,7 +55,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep moves fail when sleep clause is active") { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -82,7 +82,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep moves fail when sleep clause is active ( { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(100); } @@ -108,8 +108,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Rest does not activate sleep clause") { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -128,8 +128,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Rest does not activate sleep clause (Doubles)" { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(100); } @@ -150,8 +150,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Rest can still be used when sleep clause is ac { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -174,8 +174,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Rest can still be used when sleep clause is ac { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(100); } @@ -196,9 +196,9 @@ SINGLE_BATTLE_TEST("Sleep Clause: Psycho Shift'ing sleep will fail if sleep clau { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); - ASSUME(gMovesInfo[MOVE_PSYCHO_SHIFT].effect == EFFECT_PSYCHO_SHIFT); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_PSYCHO_SHIFT) == EFFECT_PSYCHO_SHIFT); PLAYER(SPECIES_WOBBUFFET) PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_SLEEP_TALK, MOVE_PSYCHO_SHIFT); } OPPONENT(SPECIES_WOBBUFFET); @@ -222,9 +222,9 @@ SINGLE_BATTLE_TEST("Sleep Clause: Psycho Shift'ing sleep will activate sleep cla { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); - ASSUME(gMovesInfo[MOVE_PSYCHO_SHIFT].effect == EFFECT_PSYCHO_SHIFT); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_PSYCHO_SHIFT) == EFFECT_PSYCHO_SHIFT); PLAYER(SPECIES_ZIGZAGOON) PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SLEEP_TALK, MOVE_PSYCHO_SHIFT); } @@ -252,7 +252,7 @@ AI_SINGLE_BATTLE_TEST("Sleep Clause: AI will not use Yawn while sleep clause is { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); @@ -269,7 +269,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Yawn will fail when sleep clause is active") { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -297,8 +297,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Effect Spore causes sleep 11% of the time with GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } @@ -321,8 +321,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Effect Spore causes sleep 11% of the time with GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } @@ -348,8 +348,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep from Effect Spore will not activate slee GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } @@ -375,8 +375,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep from Effect Spore will not activate slee GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(MoveMakesContact(MOVE_TACKLE)); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } @@ -401,7 +401,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Moves with sleep effect chance will activate s GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(MoveHasAdditionalEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP)); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -429,7 +429,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Moves with sleep effect chance will still do d GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(MoveHasAdditionalEffect(MOVE_RELIC_SONG, MOVE_EFFECT_SLEEP)); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -456,7 +456,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Dire Claw cannot sleep a mon when sleep clause GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(MoveHasAdditionalEffect(MOVE_DIRE_CLAW, MOVE_EFFECT_DIRE_CLAW)); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -482,7 +482,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Dark Void can only sleep one opposing mon if s // Source: https://bulbapedia.bulbagarden.net/wiki/Dark_Void_(move) GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_DARK_VOID].effect == EFFECT_DARK_VOID); + ASSUME(GetMoveEffect(MOVE_DARK_VOID) == EFFECT_DARK_VOID); PLAYER(SPECIES_DARKRAI); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -507,7 +507,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: G-Max Befuddle can only sleep one opposing mon { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_G_MAX_BEFUDDLE].argument.maxEffect == MAX_EFFECT_EFFECT_SPORE_FOES); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_BEFUDDLE) == MAX_EFFECT_EFFECT_SPORE_FOES); PLAYER(SPECIES_BUTTERFREE) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_CATERPIE); OPPONENT(SPECIES_WOBBUFFET); @@ -532,7 +532,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); ASSUME(B_SLEEP_TURNS >= GEN_5); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -564,10 +564,10 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PARAMETRIZE { move = MOVE_SPARKLY_SWIRL; healingSlot = opponentLeft; sporedSlot = opponentRight; switchIndex = 1; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); - ASSUME(gMovesInfo[MOVE_HEAL_BELL].effect == EFFECT_HEAL_BELL); - ASSUME(gMovesInfo[MOVE_SPARKLY_SWIRL].effect == EFFECT_SPARKLY_SWIRL); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_HEAL_BELL) == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_SPARKLY_SWIRL) == EFFECT_SPARKLY_SWIRL); ASSUME(B_SLEEP_TURNS >= GEN_5); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -622,7 +622,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); ASSUME(MoveHasAdditionalEffect(MOVE_WAKE_UP_SLAP, MOVE_EFFECT_REMOVE_STATUS)); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -664,8 +664,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_UPROAR].effect == EFFECT_UPROAR); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_UPROAR) == EFFECT_UPROAR); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -705,14 +705,14 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PARAMETRIZE { move = MOVE_AROMATHERAPY; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_SLEEP_TALK].effect == EFFECT_SLEEP_TALK); - ASSUME(gMovesInfo[MOVE_PSYCHO_SHIFT].effect == EFFECT_PSYCHO_SHIFT); - ASSUME(gMovesInfo[MOVE_JUNGLE_HEALING].effect == EFFECT_JUNGLE_HEALING); - ASSUME(gMovesInfo[MOVE_LUNAR_BLESSING].effect == EFFECT_JUNGLE_HEALING); - ASSUME(gMovesInfo[MOVE_PURIFY].effect == EFFECT_PURIFY); - ASSUME(gMovesInfo[MOVE_TAKE_HEART].effect == EFFECT_TAKE_HEART); - ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SLEEP_TALK) == EFFECT_SLEEP_TALK); + ASSUME(GetMoveEffect(MOVE_PSYCHO_SHIFT) == EFFECT_PSYCHO_SHIFT); + ASSUME(GetMoveEffect(MOVE_JUNGLE_HEALING) == EFFECT_JUNGLE_HEALING); + ASSUME(GetMoveEffect(MOVE_LUNAR_BLESSING) == EFFECT_JUNGLE_HEALING); + ASSUME(GetMoveEffect(MOVE_PURIFY) == EFFECT_PURIFY); + ASSUME(GetMoveEffect(MOVE_TAKE_HEART) == EFFECT_TAKE_HEART); + ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL); ASSUME(gItemsInfo[ITEM_CHESTO_BERRY].holdEffect == HOLD_EFFECT_CURE_SLP); PLAYER(SPECIES_ZIGZAGOON) { Item(ITEM_CHESTO_BERRY); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SLEEP_TALK, move); } @@ -761,7 +761,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_PELIPPER) { Ability(ABILITY_DRIZZLE); } OPPONENT(SPECIES_LUVDISC) { Ability(ABILITY_HYDRATION); } } WHEN { @@ -785,7 +785,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_SWABLU) { Ability(ABILITY_NATURAL_CURE); } OPPONENT(SPECIES_ZIGZAGOON); @@ -815,7 +815,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PASSES_RANDOMLY(33, 100, RNG_SHED_SKIN); GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_DRATINI) { Ability(ABILITY_SHED_SKIN); } } WHEN { @@ -839,7 +839,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PASSES_RANDOMLY(30, 100, RNG_HEALER); GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -867,7 +867,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PARAMETRIZE { heldItem = ITEM_LUM_BERRY; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); ASSUME(gItemsInfo[ITEM_CHESTO_BERRY].holdEffect == HOLD_EFFECT_CURE_SLP); ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); PLAYER(SPECIES_ZIGZAGOON); @@ -898,8 +898,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PARAMETRIZE { heldItem = ITEM_LUM_BERRY; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_FLING].effect == EFFECT_FLING); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_FLING) == EFFECT_FLING); ASSUME(gItemsInfo[ITEM_CHESTO_BERRY].holdEffect == HOLD_EFFECT_CURE_SLP); ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); PLAYER(SPECIES_ZIGZAGOON); @@ -931,7 +931,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); ASSUME(gItemsInfo[ITEM_AWAKENING].battleUsage == EFFECT_ITEM_CURE_STATUS); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -955,7 +955,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON) { Level(5); } OPPONENT(SPECIES_ZIGZAGOON); @@ -980,7 +980,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON) { Level(5); } @@ -1008,7 +1008,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_DELIBIRD) { Ability(ability); } OPPONENT(SPECIES_ZIGZAGOON) { Moves(MOVE_SLEEP_TALK, MOVE_SKILL_SWAP); } } WHEN { @@ -1044,7 +1044,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON) PLAYER(SPECIES_DELIBIRD) { Ability(ability); } OPPONENT(SPECIES_RALTS) { Ability(ABILITY_TRACE); } @@ -1081,7 +1081,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo KNOWN_FAILING; // Sleep Clause parts work, but Imposter seems broken with battle messages / targeting. Issue #5565 https://github.com/rh-hideout/pokeemerald-expansion/issues/5565 GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); ASSUME(gItemsInfo[ITEM_LAGGING_TAIL].holdEffect == HOLD_EFFECT_LAGGING_TAIL); PLAYER(SPECIES_ZIGZAGOON) PLAYER(SPECIES_DELIBIRD) { Ability(ability); } @@ -1116,7 +1116,7 @@ AI_SINGLE_BATTLE_TEST("Sleep Clause: AI will use sleep moves again when sleep cl { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); ASSUME(gItemsInfo[ITEM_CHESTO_BERRY].holdEffect == HOLD_EFFECT_CURE_SLP); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_CHESTO_BERRY); } @@ -1131,8 +1131,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_G_MAX_SWEETNESS].argument.maxEffect == MAX_EFFECT_AROMATHERAPY); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveMaxEffect(MOVE_G_MAX_SWEETNESS) == MAX_EFFECT_AROMATHERAPY); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_APPLETUN) { GigantamaxFactor(TRUE); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); @@ -1159,7 +1159,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Pre-existing sleep condition doesn't activate { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON) { Status1(STATUS1_SLEEP); } OPPONENT(SPECIES_ZIGZAGOON); @@ -1179,9 +1179,9 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep caused by Effect Spore does not prevent GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1215,8 +1215,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Waking up after Effect Spore doesn't deactivat GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } @@ -1252,9 +1252,9 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Waking up after Effect Spore doesn't deactivat GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); ASSUME(B_ABILITY_TRIGGER_CHANCE >= GEN_5); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_AROMATHERAPY].effect == EFFECT_HEAL_BELL); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_AROMATHERAPY) == EFFECT_HEAL_BELL); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1292,8 +1292,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Waking up after Rest doesn't deactivate sleep { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_ZIGZAGOON) { HP(1); MaxHP(100); } PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -1328,8 +1328,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Waking up after Rest doesn't deactivate sleep { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_REST].effect == EFFECT_REST); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_REST) == EFFECT_REST); PLAYER(SPECIES_ZIGZAGOON) { HP(1); MaxHP(100); } PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1366,7 +1366,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Suppressing and then sleeping Vital Spirit / I PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_DELIBIRD) { Ability(ability); } OPPONENT(SPECIES_ZIGZAGOON); @@ -1397,7 +1397,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Mold Breaker Pokémon sleeping Vital Spirit / PARAMETRIZE { ability = ABILITY_INSOMNIA; } GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_PANCHAM) { Ability(ABILITY_MOLD_BREAKER); } OPPONENT(SPECIES_DELIBIRD) { Ability(ability); } OPPONENT(SPECIES_ZIGZAGOON); @@ -1424,9 +1424,9 @@ SINGLE_BATTLE_TEST("Sleep Clause: Yawn'd Pokémon slept due to Effect Spore befo PASSES_RANDOMLY(11, 100, RNG_EFFECT_SPORE); GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); - ASSUME(gMovesInfo[MOVE_TACKLE].makesContact); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); + ASSUME(MoveMakesContact(MOVE_TACKLE)); PLAYER(SPECIES_BRELOOM) { Ability(ABILITY_EFFECT_SPORE); } OPPONENT(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -1451,8 +1451,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Yawn'd Pokémon who's partner is slept before { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -1478,8 +1478,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: If both Pokémon on one side are Yawn'd at the { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_ZIGZAGOON) { Speed(5); } PLAYER(SPECIES_ZIGZAGOON) { Speed(4); } OPPONENT(SPECIES_ZIGZAGOON) { Speed(3); } @@ -1503,8 +1503,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Reflection moves (ie. Magic Coat) fail if slee { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -1528,8 +1528,8 @@ SINGLE_BATTLE_TEST("Sleep Clause: Reflection moves (ie. Magic Coat) that reflect { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -1558,8 +1558,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Reflection moves (ie. Magic Coat) that reflect // Source: https://bulbapedia.bulbagarden.net/wiki/Dark_Void_(move) GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_MAGIC_COAT].effect == EFFECT_MAGIC_COAT); - ASSUME(gMovesInfo[MOVE_DARK_VOID].effect == EFFECT_DARK_VOID); + ASSUME(GetMoveEffect(MOVE_MAGIC_COAT) == EFFECT_MAGIC_COAT); + ASSUME(GetMoveEffect(MOVE_DARK_VOID) == EFFECT_DARK_VOID); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_DARKRAI); @@ -1583,7 +1583,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Magic Bounce'ing a sleep move activates sleep { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } PLAYER(SPECIES_ZIGZAGOON); OPPONENT(SPECIES_ZIGZAGOON); @@ -1612,7 +1612,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Magic Bounce reflecting Dark Void only sleeps // Source: https://bulbapedia.bulbagarden.net/wiki/Dark_Void_(move) GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_DARK_VOID].effect == EFFECT_DARK_VOID); + ASSUME(GetMoveEffect(MOVE_DARK_VOID) == EFFECT_DARK_VOID); PLAYER(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_DARKRAI); @@ -1636,7 +1636,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep Clause does not prevent sleeping your pa { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1679,7 +1679,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep Clause does not prevent sleeping your pa { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1722,7 +1722,7 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Sleep moves used after being Encore'd are prev { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1751,8 +1751,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Spore'ing opponent after Yawn'ing partner does { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); @@ -1788,8 +1788,8 @@ DOUBLE_BATTLE_TEST("Sleep Clause: Opponent Spore'ing player's partner after part { GIVEN { FLAG_SET(B_FLAG_SLEEP_CLAUSE); - ASSUME(gMovesInfo[MOVE_SPORE].effect == EFFECT_SLEEP); - ASSUME(gMovesInfo[MOVE_YAWN].effect == EFFECT_YAWN); + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_SLEEP); + ASSUME(GetMoveEffect(MOVE_YAWN) == EFFECT_YAWN); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); PLAYER(SPECIES_ZIGZAGOON); diff --git a/test/battle/spread_moves.c b/test/battle/spread_moves.c index 5228e3041f04..2791ca0ea5e9 100644 --- a/test/battle/spread_moves.c +++ b/test/battle/spread_moves.c @@ -36,8 +36,8 @@ DOUBLE_BATTLE_TEST("Spread Moves: No damage will be dealt to a mon in an invulne PARAMETRIZE { attackingMove = MOVE_HYPER_VOICE; invulMove = MOVE_DIVE; } PARAMETRIZE { attackingMove = MOVE_LAVA_PLUME; invulMove = MOVE_DIVE; } GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_LAVA_PLUME].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_LAVA_PLUME) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_ZAPDOS); @@ -172,8 +172,8 @@ DOUBLE_BATTLE_TEST("Spread Moves: A spread move attack will be weakened by stron DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (right) and Lightning Rod (left)") { GIVEN { - ASSUME(gMovesInfo[MOVE_DISCHARGE].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_DISCHARGE].type == TYPE_ELECTRIC); + ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_MIMIKYU); OPPONENT(SPECIES_RAICHU) { Ability(ABILITY_LIGHTNING_ROD); } @@ -191,8 +191,8 @@ DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (right) and DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (left) and Lightning Rod (reft)") { GIVEN { - ASSUME(gMovesInfo[MOVE_DISCHARGE].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_DISCHARGE].type == TYPE_ELECTRIC); + ASSUME(GetMoveTarget(MOVE_DISCHARGE) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveType(MOVE_DISCHARGE) == TYPE_ELECTRIC); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_MIMIKYU); OPPONENT(SPECIES_LANTURN) { Ability(ABILITY_VOLT_ABSORB); HP(1); } @@ -210,8 +210,8 @@ DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Disguise, Volt Absorb (left) and L DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Eiscue and Mimikyu (Based on vanilla games)") { GIVEN { - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].target == MOVE_TARGET_FOES_AND_ALLY); - ASSUME(gMovesInfo[MOVE_EARTHQUAKE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveTarget(MOVE_EARTHQUAKE) == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveCategory(MOVE_EARTHQUAKE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_EISCUE); OPPONENT(SPECIES_MIMIKYU); @@ -229,7 +229,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: AOE move vs Eiscue and Mimikyu (Based on vanil DOUBLE_BATTLE_TEST("Spread Moves: Spread move, Gem Boosted, vs Resist Berries") { GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET) { Speed(40); Item(ITEM_NORMAL_GEM); } PLAYER(SPECIES_WYNAUT) { Speed(30); } OPPONENT(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_CHILAN_BERRY); } @@ -249,7 +249,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Spread move, Gem Boosted, vs Resist Berries") DOUBLE_BATTLE_TEST("Spread Moves: Explosion, Gem Boosted, vs Resist Berries") { GIVEN { - ASSUME(gMovesInfo[MOVE_EXPLOSION].target == MOVE_TARGET_FOES_AND_ALLY); + ASSUME(GetMoveTarget(MOVE_EXPLOSION) == MOVE_TARGET_FOES_AND_ALLY); PLAYER(SPECIES_WOBBUFFET) { Speed(40); Item(ITEM_NORMAL_GEM); } PLAYER(SPECIES_MISDREAVUS) { Speed(30); } OPPONENT(SPECIES_WOBBUFFET) { Speed(20); Item(ITEM_CHILAN_BERRY); } @@ -270,8 +270,8 @@ DOUBLE_BATTLE_TEST("Spread Moves: Explosion, Gem Boosted, vs Resist Berries") DOUBLE_BATTLE_TEST("Spread Moves: Spread move vs Eiscue and Mimikyu with 1 Eject Button") { GIVEN { - ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].target == MOVE_TARGET_BOTH); - ASSUME(gMovesInfo[MOVE_RAZOR_LEAF].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveTarget(MOVE_RAZOR_LEAF) == MOVE_TARGET_BOTH); + ASSUME(GetMoveCategory(MOVE_RAZOR_LEAF) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { Speed(40); } PLAYER(SPECIES_WYNAUT) { Speed(30); } OPPONENT(SPECIES_MIMIKYU) { Speed(20); Item(ITEM_EJECT_BUTTON); } @@ -290,7 +290,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Spread move vs Eiscue and Mimikyu with 1 Eject DOUBLE_BATTLE_TEST("Spread Moves: Spread move vs Wide Guard") { GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET) { Speed(40); } PLAYER(SPECIES_WYNAUT) { Speed(20); } OPPONENT(SPECIES_WOBBUFFET) { Speed(30); } @@ -310,7 +310,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Spread move vs Wide Guard") DOUBLE_BATTLE_TEST("Spread Moves: Spread move vs one protecting mon") { GIVEN { - ASSUME(gMovesInfo[MOVE_HYPER_VOICE].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_HYPER_VOICE) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_WOBBUFFET); @@ -327,7 +327,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Spread move vs one protecting mon") DOUBLE_BATTLE_TEST("Spread Moves: Super Effective Message on both opposing mons") { GIVEN { - ASSUME(gMovesInfo[MOVE_PRECIPICE_BLADES].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_PRECIPICE_BLADES) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_GOLEM); @@ -345,7 +345,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Super Effective Message on both opposing mons" DOUBLE_BATTLE_TEST("Spread Moves: Super Effective Message on both player mons") { GIVEN { - ASSUME(gMovesInfo[MOVE_PRECIPICE_BLADES].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_PRECIPICE_BLADES) == MOVE_TARGET_BOTH); PLAYER(SPECIES_GOLEM); PLAYER(SPECIES_ONIX); OPPONENT(SPECIES_WOBBUFFET); @@ -363,7 +363,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Super Effective Message on both player mons") DOUBLE_BATTLE_TEST("Spread Moves: Not very effective Message on both opposing mons") { GIVEN { - ASSUME(gMovesInfo[MOVE_PRECIPICE_BLADES].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_PRECIPICE_BLADES) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_CHIKORITA); @@ -381,7 +381,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Not very effective Message on both opposing mo DOUBLE_BATTLE_TEST("Spread Moves: Not very effective message on both player mons") { GIVEN { - ASSUME(gMovesInfo[MOVE_PRECIPICE_BLADES].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_PRECIPICE_BLADES) == MOVE_TARGET_BOTH); PLAYER(SPECIES_CHIKORITA); PLAYER(SPECIES_TREECKO); OPPONENT(SPECIES_WOBBUFFET); @@ -399,7 +399,7 @@ DOUBLE_BATTLE_TEST("Spread Moves: Not very effective message on both player mons DOUBLE_BATTLE_TEST("Spread Moves: Doesn't affect message on both opposing mons") { GIVEN { - ASSUME(gMovesInfo[MOVE_PRECIPICE_BLADES].target == MOVE_TARGET_BOTH); + ASSUME(GetMoveTarget(MOVE_PRECIPICE_BLADES) == MOVE_TARGET_BOTH); PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WYNAUT); OPPONENT(SPECIES_PIDGEY); diff --git a/test/battle/terrain/starting_terrain.c b/test/battle/starting_status/terrain.c similarity index 100% rename from test/battle/terrain/starting_terrain.c rename to test/battle/starting_status/terrain.c diff --git a/test/battle/status1/burn.c b/test/battle/status1/burn.c index 63d6506fb626..c37768cedf09 100644 --- a/test/battle/status1/burn.c +++ b/test/battle/status1/burn.c @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Burn reduces Attack by 50%", s16 damage) PARAMETRIZE { burned = FALSE; } PARAMETRIZE { burned = TRUE; } GIVEN { - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); PLAYER(SPECIES_WOBBUFFET) { if (burned) Status1(STATUS1_BURN); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { diff --git a/test/battle/status1/freeze.c b/test/battle/status1/freeze.c index f218430909e1..f363ab9e359b 100644 --- a/test/battle/status1/freeze.c +++ b/test/battle/status1/freeze.c @@ -17,7 +17,7 @@ SINGLE_BATTLE_TEST("Freeze has a 20% chance of being thawed") SINGLE_BATTLE_TEST("Freeze is thawed by opponent's Fire-type attacks") { GIVEN { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Freeze is thawed by opponent's Fire-type attacks") SINGLE_BATTLE_TEST("Freeze is thawed by user's Flame Wheel") { GIVEN { - ASSUME(gMovesInfo[MOVE_FLAME_WHEEL].thawsUser); + ASSUME(MoveThawsUser(MOVE_FLAME_WHEEL)); PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -43,3 +43,21 @@ SINGLE_BATTLE_TEST("Freeze is thawed by user's Flame Wheel") MESSAGE("Wobbuffet used Flame Wheel!"); } } + +SINGLE_BATTLE_TEST("Freeze isn't thawed if opponent is asleep during thawing attack") +{ + PASSES_RANDOMLY(80, 100, RNG_FROZEN); + GIVEN { + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET) { Status1(STATUS1_FREEZE); } + OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_SLEEP); }; + } WHEN { + TURN { MOVE(opponent, MOVE_EMBER); MOVE(player, MOVE_CELEBRATE); } + } SCENE { + NONE_OF { + MESSAGE("The opposing Wobbuffet used Ember!"); + MESSAGE("Wobbuffet thawed out!"); + STATUS_ICON(player, none: TRUE); + } + } +} diff --git a/test/battle/status1/frostbite.c b/test/battle/status1/frostbite.c index a7776e5e2e1a..f45508f800b9 100644 --- a/test/battle/status1/frostbite.c +++ b/test/battle/status1/frostbite.c @@ -7,7 +7,7 @@ SINGLE_BATTLE_TEST("Frostbite reduces the special attack by 50 percent") s16 normaleDamage; GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET) { Status1(STATUS1_FROSTBITE); } } WHEN { diff --git a/test/battle/status2/confusion.c b/test/battle/status2/confusion.c index 4115123b3c11..c2ee92dd09cb 100644 --- a/test/battle/status2/confusion.c +++ b/test/battle/status2/confusion.c @@ -5,7 +5,7 @@ SINGLE_BATTLE_TEST("Confusion adds a 50/33% chance to hit self with 40 power") { s16 damage[2]; - ASSUME(gMovesInfo[MOVE_TACKLE].power == 40); + ASSUME(GetMovePower(MOVE_TACKLE) == 40); PASSES_RANDOMLY(B_CONFUSION_SELF_DMG_CHANCE >= GEN_7 ? 33 : 50, 100, RNG_CONFUSION); GIVEN { diff --git a/test/battle/trainer_control.c b/test/battle/trainer_control.c index 5344a2659637..bbc49c2ed519 100644 --- a/test/battle/trainer_control.c +++ b/test/battle/trainer_control.c @@ -11,16 +11,32 @@ #include "constants/trainers.h" #include "constants/battle.h" -static const struct Trainer sTestTrainers[] = +#define NUM_TEST_TRAINERS 3 + +static const struct Trainer sTestTrainers[DIFFICULTY_COUNT][NUM_TEST_TRAINERS] = { #include "trainer_control.h" }; +enum DifficultyLevel GetTrainerDifficultyLevelTest(u16 trainerId) +{ + enum DifficultyLevel difficulty = GetCurrentDifficultyLevel(); + + if (difficulty == DIFFICULTY_NORMAL) + return DIFFICULTY_NORMAL; + + if (sTestTrainers[difficulty][trainerId].party == NULL) + return DIFFICULTY_NORMAL; + + return difficulty; +} + TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon") { + u32 currTrainer = 0; struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); u8 nickBuffer[20]; - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[0], TRUE, BATTLE_TYPE_TRAINER); + CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); EXPECT(IsMonShiny(&testParty[0])); EXPECT(!IsMonShiny(&testParty[1])); @@ -94,8 +110,9 @@ TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon") TEST("CreateNPCTrainerPartyForTrainer generates different personalities for different mons") { + enum DifficultyLevel difficulty = GetTrainerDifficultyLevelTest(0); struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); - CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[0], TRUE, BATTLE_TYPE_TRAINER); + CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[difficulty][0], TRUE, BATTLE_TYPE_TRAINER); EXPECT(testParty[0].box.personality != testParty[1].box.personality); Free(testParty); } @@ -160,3 +177,46 @@ TEST("Trainer Class Balls apply to the entire party") } Free(testParty); } + +TEST("Difficulty default to Normal is the trainer doesn't have a member for the current diffuculty") +{ + SetCurrentDifficultyLevel(DIFFICULTY_EASY); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = 1; + CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_MEWTWO); + Free(testParty); +} + +TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (EASY)") +{ + SetCurrentDifficultyLevel(DIFFICULTY_EASY); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = 2; + CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_METAPOD); + EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 1); + Free(testParty); +} + +TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (HARD)") +{ + SetCurrentDifficultyLevel(DIFFICULTY_HARD); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = 2; + CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_ARCEUS); + EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 99); + Free(testParty); +} + +TEST("Difficulty changes which party if used for NPCs if defined for the difficulty (NORMAL)") +{ + SetCurrentDifficultyLevel(DIFFICULTY_NORMAL); + struct Pokemon *testParty = Alloc(6 * sizeof(struct Pokemon)); + u32 currTrainer = 2; + CreateNPCTrainerPartyFromTrainer(testParty, &sTestTrainers[GetTrainerDifficultyLevelTest(currTrainer)][currTrainer], TRUE, BATTLE_TYPE_TRAINER); + EXPECT(GetMonData(&testParty[0], MON_DATA_SPECIES) == SPECIES_MEWTWO); + EXPECT(GetMonData(&testParty[0], MON_DATA_LEVEL) == 50); + Free(testParty); +} diff --git a/test/battle/trainer_control.h b/test/battle/trainer_control.h index 72db458de77d..9bb878f76fdf 100644 --- a/test/battle/trainer_control.h +++ b/test/battle/trainer_control.h @@ -9,7 +9,7 @@ #line 1 "test/battle/trainer_control.party" #line 1 - [0] = + [DIFFICULTY_NORMAL][0] = { #line 2 .trainerName = _("Test1"), @@ -87,3 +87,158 @@ }, }, }, +#line 33 +#line 40 + [DIFFICULTY_NORMAL][1] = + { +#line 34 + .trainerName = _("Test2"), +#line 35 + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, +#line 36 + .trainerPic = TRAINER_PIC_RED, + .encounterMusic_gender = +#line 38 + TRAINER_ENCOUNTER_MUSIC_MALE, +#line 39 + .doubleBattle = FALSE, + .partySize = 1, + .party = (const struct TrainerMon[]) + { + { +#line 42 + .species = SPECIES_MEWTWO, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 44 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 43 + .lvl = 5, + .nature = NATURE_HARDY, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + }, + }, + }, +#line 45 +#line 52 + [DIFFICULTY_HARD][1] = + { +#line 46 + .trainerName = _("Test2"), +#line 47 + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, +#line 48 + .trainerPic = TRAINER_PIC_RED, + .encounterMusic_gender = +#line 50 + TRAINER_ENCOUNTER_MUSIC_MALE, +#line 51 + .doubleBattle = FALSE, + .partySize = 1, + .party = (const struct TrainerMon[]) + { + { +#line 54 + .species = SPECIES_YVELTAL, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 56 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 55 + .lvl = 99, + .nature = NATURE_HARDY, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + }, + }, + }, +#line 57 +#line 64 + [DIFFICULTY_NORMAL][2] = + { +#line 58 + .trainerName = _("Test2"), +#line 59 + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, +#line 60 + .trainerPic = TRAINER_PIC_RED, + .encounterMusic_gender = +#line 62 + TRAINER_ENCOUNTER_MUSIC_MALE, +#line 63 + .doubleBattle = FALSE, + .partySize = 1, + .party = (const struct TrainerMon[]) + { + { +#line 66 + .species = SPECIES_MEWTWO, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 68 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 67 + .lvl = 50, + .nature = NATURE_HARDY, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + }, + }, + }, +#line 69 +#line 76 + [DIFFICULTY_EASY][2] = + { +#line 70 + .trainerName = _("Test2"), +#line 71 + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, +#line 72 + .trainerPic = TRAINER_PIC_RED, + .encounterMusic_gender = +#line 74 + TRAINER_ENCOUNTER_MUSIC_MALE, +#line 75 + .doubleBattle = FALSE, + .partySize = 1, + .party = (const struct TrainerMon[]) + { + { +#line 78 + .species = SPECIES_METAPOD, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 80 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 79 + .lvl = 1, + .nature = NATURE_HARDY, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + }, + }, + }, +#line 81 +#line 88 + [DIFFICULTY_HARD][2] = + { +#line 82 + .trainerName = _("Test2"), +#line 83 + .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, +#line 84 + .trainerPic = TRAINER_PIC_RED, + .encounterMusic_gender = +#line 86 + TRAINER_ENCOUNTER_MUSIC_MALE, +#line 87 + .doubleBattle = FALSE, + .partySize = 1, + .party = (const struct TrainerMon[]) + { + { +#line 90 + .species = SPECIES_ARCEUS, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 92 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 91 + .lvl = 99, + .nature = NATURE_HARDY, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + }, + }, + }, diff --git a/test/battle/trainer_control.party b/test/battle/trainer_control.party index 8ebfc0e66481..3357bb70fe6d 100644 --- a/test/battle/trainer_control.party +++ b/test/battle/trainer_control.party @@ -29,3 +29,63 @@ IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe Wynaut Level: 5 IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe + +=== 1 === +Name: Test2 +Class: Pkmn Trainer 1 +Pic: Red +Gender: Male +Music: Male +Double Battle: No +Difficulty: Normal + +Mewtwo +Level: 5 + +=== 1 === +Name: Test2 +Class: Pkmn Trainer 1 +Pic: Red +Gender: Male +Music: Male +Double Battle: No +Difficulty: HARD + +Yveltal +Level: 99 + +=== 2 === +Name: Test2 +Class: Pkmn Trainer 1 +Pic: Red +Gender: Male +Music: Male +Double Battle: No +Difficulty: Normal + +Mewtwo +Level: 50 + +=== 2 === +Name: Test2 +Class: Pkmn Trainer 1 +Pic: Red +Gender: Male +Music: Male +Double Battle: No +Difficulty: Easy + +Metapod +Level: 1 + +=== 2 === +Name: Test2 +Class: Pkmn Trainer 1 +Pic: Red +Gender: Male +Music: Male +Double Battle: No +Difficulty: Hard + +Arceus +Level: 99 diff --git a/test/battle/weather/rain.c b/test/battle/weather/rain.c index 3359d25a818d..0620aae1009e 100644 --- a/test/battle/weather/rain.c +++ b/test/battle/weather/rain.c @@ -4,8 +4,8 @@ // Please add Rain interactions with move, item and ability effects on their respective files. ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); } SINGLE_BATTLE_TEST("Rain multiplies the power of Fire-type moves by 0.5x", s16 damage) diff --git a/test/battle/weather/sandstorm.c b/test/battle/weather/sandstorm.c index 38502cbbc79c..dcac3f71c33b 100644 --- a/test/battle/weather/sandstorm.c +++ b/test/battle/weather/sandstorm.c @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Sandstorm multiplies the special defense of Rock-types by 1. PARAMETRIZE { move = MOVE_SANDSTORM; } PARAMETRIZE { move = MOVE_CELEBRATE; } GIVEN { - ASSUME(gMovesInfo[MOVE_SWIFT].category == DAMAGE_CATEGORY_SPECIAL); + ASSUME(GetMoveCategory(MOVE_SWIFT) == DAMAGE_CATEGORY_SPECIAL); PLAYER(SPECIES_WOBBUFFET) ; OPPONENT(SPECIES_NOSEPASS); } WHEN { diff --git a/test/battle/weather/snow.c b/test/battle/weather/snow.c index 6c084f6b7a05..7b4e4cb2ffef 100644 --- a/test/battle/weather/snow.c +++ b/test/battle/weather/snow.c @@ -4,10 +4,10 @@ // Please add Snow interactions with move, item and ability effects on their respective files. ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_SNOWSCAPE].effect == EFFECT_SNOWSCAPE); + ASSUME(GetMoveEffect(MOVE_SNOWSCAPE) == EFFECT_SNOWSCAPE); ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ICE && gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ICE); ASSUME(gSpeciesInfo[SPECIES_GLALIE].types[0] == TYPE_ICE || gSpeciesInfo[SPECIES_GLALIE].types[1] == TYPE_ICE); - ASSUME(gMovesInfo[MOVE_TACKLE].category == DAMAGE_CATEGORY_PHYSICAL); + ASSUME(GetMoveCategory(MOVE_TACKLE) == DAMAGE_CATEGORY_PHYSICAL); } SINGLE_BATTLE_TEST("Snow multiplies the defense of Ice-types by 1.5x", s16 damage) diff --git a/test/battle/weather/sunlight.c b/test/battle/weather/sunlight.c index 6cf6348987b6..796ad3c3af24 100644 --- a/test/battle/weather/sunlight.c +++ b/test/battle/weather/sunlight.c @@ -4,8 +4,8 @@ // Please add Sunlight interactions with move, item and ability effects on their respective files. ASSUMPTIONS { - ASSUME(gMovesInfo[MOVE_EMBER].type == TYPE_FIRE); - ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER); + ASSUME(GetMoveType(MOVE_EMBER) == TYPE_FIRE); + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); } SINGLE_BATTLE_TEST("Sunlight multiplies the power of Fire-type moves by 1.5x", s16 damage) diff --git a/test/pokemon.c b/test/pokemon.c index 00b08ebb79c7..4469fe677d27 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -275,7 +275,7 @@ TEST("givemon [all]") ZeroPlayerPartyMons(); RUN_OVERWORLD_SCRIPT( - givemon SPECIES_WOBBUFFET, 100, item=ITEM_LEFTOVERS, ball=ITEM_MASTER_BALL, nature=NATURE_BOLD, abilityNum=2, gender=MON_MALE, hpEv=1, atkEv=2, defEv=3, speedEv=4, spAtkEv=5, spDefEv=6, hpIv=7, atkIv=8, defIv=9, speedIv=10, spAtkIv=11, spDefIv=12, move1=MOVE_TACKLE, move2=MOVE_SPLASH, move3=MOVE_CELEBRATE, move4=MOVE_EXPLOSION, isShiny=TRUE, ggMaxFactor=TRUE, teraType=TYPE_FIRE; + givemon SPECIES_WOBBUFFET, 100, item=ITEM_LEFTOVERS, ball=ITEM_MASTER_BALL, nature=NATURE_BOLD, abilityNum=2, gender=MON_MALE, hpEv=1, atkEv=2, defEv=3, speedEv=4, spAtkEv=5, spDefEv=6, hpIv=7, atkIv=8, defIv=9, speedIv=10, spAtkIv=11, spDefIv=12, move1=MOVE_TACKLE, move2=MOVE_SPLASH, move3=MOVE_CELEBRATE, move4=MOVE_EXPLOSION, isShiny=TRUE, gmaxFactor=TRUE, teraType=TYPE_FIRE, dmaxLevel=7; ); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); @@ -304,6 +304,7 @@ TEST("givemon [all]") EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_IS_SHINY), TRUE); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR), TRUE); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_TERA_TYPE), TYPE_FIRE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DYNAMAX_LEVEL), 7); } TEST("givemon [vars]") @@ -336,9 +337,10 @@ TEST("givemon [vars]") VarSet(VAR_TEMP_9, TRUE); VarSet(VAR_TEMP_A, TRUE); VarSet(VAR_TEMP_B, TYPE_FIRE); + VarSet(VAR_TEMP_E, 7); RUN_OVERWORLD_SCRIPT( - givemon VAR_TEMP_C, VAR_TEMP_D, item=VAR_0x8000, ball=VAR_0x8001, nature=VAR_0x8002, abilityNum=VAR_0x8003, gender=VAR_0x8004, hpEv=VAR_0x8005, atkEv=VAR_0x8006, defEv=VAR_0x8007, speedEv=VAR_0x8008, spAtkEv=VAR_0x8009, spDefEv=VAR_0x800A, hpIv=VAR_0x800B, atkIv=VAR_TEMP_0, defIv=VAR_TEMP_1, speedIv=VAR_TEMP_2, spAtkIv=VAR_TEMP_3, spDefIv=VAR_TEMP_4, move1=VAR_TEMP_5, move2=VAR_TEMP_6, move3=VAR_TEMP_7, move4=VAR_TEMP_8, isShiny=VAR_TEMP_9, ggMaxFactor=VAR_TEMP_A, teraType=VAR_TEMP_B; + givemon VAR_TEMP_C, VAR_TEMP_D, item=VAR_0x8000, ball=VAR_0x8001, nature=VAR_0x8002, abilityNum=VAR_0x8003, gender=VAR_0x8004, hpEv=VAR_0x8005, atkEv=VAR_0x8006, defEv=VAR_0x8007, speedEv=VAR_0x8008, spAtkEv=VAR_0x8009, spDefEv=VAR_0x800A, hpIv=VAR_0x800B, atkIv=VAR_TEMP_0, defIv=VAR_TEMP_1, speedIv=VAR_TEMP_2, spAtkIv=VAR_TEMP_3, spDefIv=VAR_TEMP_4, move1=VAR_TEMP_5, move2=VAR_TEMP_6, move3=VAR_TEMP_7, move4=VAR_TEMP_8, isShiny=VAR_TEMP_9, gmaxFactor=VAR_TEMP_A, teraType=VAR_TEMP_B, dmaxLevel=VAR_TEMP_E; ); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET); @@ -367,6 +369,7 @@ TEST("givemon [vars]") EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_IS_SHINY), TRUE); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR), TRUE); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_TERA_TYPE), TYPE_FIRE); + EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_DYNAMAX_LEVEL), 7); } TEST("checkteratype/setteratype work") diff --git a/test/script.c b/test/script.c new file mode 100644 index 000000000000..5f185d72cf7b --- /dev/null +++ b/test/script.c @@ -0,0 +1,116 @@ +#include "global.h" +#include "test/test.h" +#include "test/overworld_script.h" +#include "script.h" +#include "constants/decorations.h" +#include "constants/moves.h" + +TEST("Script_HasNoEffect control flow") +{ + const u8 *script = OVERWORLD_SCRIPT( + nop; + nop1; + checkflag FLAG_TEMP_1; + checktrainerflag 0; + compare VAR_TEMP_0, 0; + goto_if_eq GoneTo; + GoneTo: + call Sub; + call_if_eq Sub; + end; + + Sub: + goto SubRet; + SubRet: + return; + ); + EXPECT(Script_HasNoEffect(script)); +} + +TEST("Script_HasNoEffect variables") +{ + // Writes to special variables are not considered player-visible + // because their values are indeterminate if the player has control. + const u8 *writeSpecial = OVERWORLD_SCRIPT( + setvar VAR_0x8000, 1; + addvar VAR_0x8000, 1; + subvar VAR_0x8000, VAR_TEMP_0; + copyvar VAR_0x8000, VAR_TEMP_0; + setorcopyvar VAR_0x8000, VAR_TEMP_0; + specialvar VAR_RESULT, GetPlayerFacingDirection; + getplayerxy VAR_0x8000, VAR_0x8001; + getpartysize; + checkitemspace ITEM_POTION, 1; + checkitem ITEM_POTION, 1; + checkitemtype ITEM_POTION; + checkpcitem ITEM_POTION, 1; + checkdecorspace DECOR_SNORLAX_DOLL; + checkdecor DECOR_SNORLAX_DOLL; + checkpartymove MOVE_CELEBRATE; + random 2; + checkmoney 5000; + getpokenewsactive POKENEWS_LILYCOVE; + checkplayergender; + checkcoins VAR_RESULT; + checkmodernfatefulencounter 0; + end; + ); + + // Writes to other variables are considered player-visible because + // their values are preserved even while the player has control. + const u8 *setVariable = OVERWORLD_SCRIPT( + setvar VAR_TEMP_0, 1; + end; + ); + + const u8 *addVariable = OVERWORLD_SCRIPT( + addvar VAR_TEMP_0, 1; + end; + ); + + const u8 *subVariable = OVERWORLD_SCRIPT( + subvar VAR_TEMP_0, 1; + end; + ); + + const u8 *copyVariable = OVERWORLD_SCRIPT( + copyvar VAR_TEMP_0, VAR_RESULT; + end; + ); + + const u8 *setorcopyVariable = OVERWORLD_SCRIPT( + setorcopyvar VAR_TEMP_0, VAR_RESULT; + end; + ); + + const u8 *specialvarVariable = OVERWORLD_SCRIPT( + specialvar VAR_TEMP_0, GetPlayerFacingDirection; + end; + ); + + const u8 *getPlayerXYVariable1 = OVERWORLD_SCRIPT( + getplayerxy VAR_TEMP_0, VAR_RESULT; + end; + ); + + const u8 *getPlayerXYVariable2 = OVERWORLD_SCRIPT( + getplayerxy VAR_RESULT, VAR_TEMP_0; + end; + ); + + const u8 *checkCoinsVariable = OVERWORLD_SCRIPT( + checkcoins VAR_TEMP_0; + end; + ); + + EXPECT(Script_HasNoEffect(writeSpecial)); + EXPECT(!Script_HasNoEffect(setVariable)); + EXPECT(!Script_HasNoEffect(addVariable)); + EXPECT(!Script_HasNoEffect(subVariable)); + EXPECT(!Script_HasNoEffect(copyVariable)); + EXPECT(!Script_HasNoEffect(setorcopyVariable)); + EXPECT(!Script_HasNoEffect(specialvarVariable)); + EXPECT(!Script_HasNoEffect(getPlayerXYVariable1)); + EXPECT(!Script_HasNoEffect(getPlayerXYVariable2)); + EXPECT(!Script_HasNoEffect(checkCoinsVariable)); +} diff --git a/test/test_runner.c b/test/test_runner.c index d3196a20e183..7a81d1dc9f68 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -10,7 +10,7 @@ #include "test_runner.h" #include "test/test.h" -#define TIMEOUT_SECONDS 55 +#define TIMEOUT_SECONDS 60 void CB2_TestRunner(void); @@ -276,7 +276,7 @@ void CB2_TestRunner(void) { if (gTasks[i].isActive) { - Test_MgbaPrintf("%p: task not freed", gTasks[i].func); + Test_MgbaPrintf(":L%s:%d - %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); gTestRunnerState.result = TEST_RESULT_FAIL; } } diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 50d389c5452f..2b6f16246bf3 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -160,6 +160,7 @@ static void BattleTest_SetUp(void *data) { const struct BattleTest *test = data; memset(STATE, 0, sizeof(*STATE)); + TestInitConfigData(); InvokeTestFunction(test); STATE->parameters = STATE->parametersCount; if (STATE->parametersCount == 0 && test->resultsSize > 0) @@ -1416,6 +1417,7 @@ static void BattleTest_TearDown(void *data) // Free resources that aren't cleaned up when the battle was // aborted unexpectedly. ClearFlagAfterTest(); + TestFreeConfigData(); if (STATE->tearDownBattle) TearDownBattle(); } @@ -1512,6 +1514,12 @@ void SetFlagForTest(u32 sourceLine, u16 flagId) FlagSet(flagId); } +void TestSetConfig(u32 sourceLine, enum GenConfigTag configTag, u32 value) +{ + INVALID_IF(!STATE->runGiven, "WITH_CONFIG outside of GIVEN"); + SetGenConfig(configTag, value); +} + void ClearFlagAfterTest(void) { if (DATA.flagId != 0) @@ -1766,7 +1774,8 @@ void Moves_(u32 sourceLine, u16 moves[MAX_MON_MOVES]) break; INVALID_IF(moves[i] >= MOVES_COUNT, "Illegal move: %d", moves[i]); SetMonData(DATA.currentMon, MON_DATA_MOVE1 + i, &moves[i]); - SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &gMovesInfo[moves[i]].pp); + u32 pp = GetMovePP(moves[i]); + SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &pp); } DATA.explicitMoves[DATA.currentSide] |= 1 << DATA.currentPartyIndex; } @@ -2084,7 +2093,8 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 * { INVALID_IF(DATA.explicitMoves[battlerId & BIT_SIDE] & (1 << DATA.currentMonIndexes[battlerId]), "Missing explicit %S", GetMoveName(ctx->move)); SetMonData(mon, MON_DATA_MOVE1 + i, &ctx->move); - SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &gMovesInfo[ctx->move].pp); + u32 pp = GetMovePP(ctx->move); + SetMonData(DATA.currentMon, MON_DATA_PP1 + i, &pp); *moveSlot = i; *moveId = ctx->move; break; @@ -2108,12 +2118,12 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 * u32 item = GetMonData(mon, MON_DATA_HELD_ITEM); u32 holdEffect = ItemId_GetHoldEffect(item); u32 species = GetMonData(mon, MON_DATA_SPECIES); - u32 side = GetBattlerSide(battlerId); + u32 side = battlerId & BIT_SIDE; // Check invalid item usage. INVALID_IF(ctx->gimmick == GIMMICK_MEGA && holdEffect != HOLD_EFFECT_MEGA_STONE && species != SPECIES_RAYQUAZA, "Cannot Mega Evolve without a Mega Stone"); INVALID_IF(ctx->gimmick == GIMMICK_Z_MOVE && holdEffect != HOLD_EFFECT_Z_CRYSTAL, "Cannot use a Z-Move without a Z-Crystal"); - INVALID_IF(ctx->gimmick == GIMMICK_Z_MOVE && ItemId_GetSecondaryId(item) != gMovesInfo[*moveId].type + INVALID_IF(ctx->gimmick == GIMMICK_Z_MOVE && ItemId_GetSecondaryId(item) != GetMoveType(*moveId) && GetSignatureZMove(*moveId, species, item) == MOVE_NONE && *moveId != MOVE_PHOTON_GEYSER, // exception because test won't recognize Ultra Necrozma pre-Burst "Cannot turn %S into a Z-Move with %S", GetMoveName(ctx->move), ItemId_GetName(item)); @@ -2175,7 +2185,7 @@ void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx) MoveGetIdAndSlot(battlerId, &ctx, &moveId, &moveSlot, sourceLine); target = MoveGetTarget(battlerId, moveId, &ctx, sourceLine); - if (gMovesInfo[moveId].effect == EFFECT_REVIVAL_BLESSING) + if (GetMoveEffect(moveId) == EFFECT_REVIVAL_BLESSING) requirePartyIndex = MoveGetFirstFainted(battlerId) != PARTY_SIZE; // Check party menu moves. diff --git a/test/text.c b/test/text.c index ed343d103981..781aaaed3ec6 100644 --- a/test/text.c +++ b/test/text.c @@ -23,10 +23,10 @@ TEST("Move names fit on Pokemon Summary Screen") u32 move = MOVE_NONE; for (i = 1; i < MOVES_COUNT; i++) { - PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + PARAMETRIZE_LABEL("%S", GetMoveName(i)) { move = i; } } - //DebugPrintf("Move %d: %S", GetStringWidth(fontId, gMovesInfo[move].name, 0), gMovesInfo[move].name); - EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + //DebugPrintf("Move %d: %S", GetStringWidth(fontId, GetMoveName(move), 0), GetMoveName(move)); + EXPECT_LE(GetStringWidth(fontId, GetMoveName(move), 0), widthPx); } TEST("Move names fit on Battle Screen") @@ -36,9 +36,9 @@ TEST("Move names fit on Battle Screen") u32 move = MOVE_NONE; for (i = 1; i < MOVES_COUNT; i++) { - PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + PARAMETRIZE_LABEL("%S", GetMoveName(i)) { move = i; } } - EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + EXPECT_LE(GetStringWidth(fontId, GetMoveName(move), 0), widthPx); } TEST("Move names fit on Contest Screen") @@ -48,7 +48,7 @@ TEST("Move names fit on Contest Screen") u32 move = MOVE_NONE; for (i = 1; i < MOVES_COUNT; i++) { - PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + PARAMETRIZE_LABEL("%S", GetMoveName(i)) { move = i; } } // All moves explicitly listed here are too big to fit. switch (move) @@ -56,10 +56,10 @@ TEST("Move names fit on Contest Screen") case MOVE_STOMPING_TANTRUM: case MOVE_NATURES_MADNESS: case MOVE_DOUBLE_IRON_BASH: - EXPECT_GT(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + EXPECT_GT(GetStringWidth(fontId, GetMoveName(move), 0), widthPx); break; default: - EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + EXPECT_LE(GetStringWidth(fontId, GetMoveName(move), 0), widthPx); break; } } @@ -71,9 +71,9 @@ TEST("Move names fit on TMs & HMs Bag Screen") u32 move = MOVE_NONE; for (i = 1; i < MOVES_COUNT; i++) { - PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + PARAMETRIZE_LABEL("%S", GetMoveName(i)) { move = i; } } - EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + EXPECT_LE(GetStringWidth(fontId, GetMoveName(move), 0), widthPx); } TEST("Move names fit on Move Relearner Screen") @@ -83,9 +83,9 @@ TEST("Move names fit on Move Relearner Screen") u32 move = MOVE_NONE; for (i = 1; i < MOVES_COUNT; i++) { - PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + PARAMETRIZE_LABEL("%S", GetMoveName(i)) { move = i; } } - EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + EXPECT_LE(GetStringWidth(fontId, GetMoveName(move), 0), widthPx); } TEST("Move descriptions fit on Pokemon Summary Screen") @@ -95,9 +95,9 @@ TEST("Move descriptions fit on Pokemon Summary Screen") u32 move = MOVE_NONE; for (i = 1; i < MOVES_COUNT; i++) { - PARAMETRIZE_LABEL("%S", gMovesInfo[i].description) { move = i; } + PARAMETRIZE_LABEL("%S", GetMoveDescription(i)) { move = i; } } - EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].description, 0), widthPx); + EXPECT_LE(GetStringWidth(fontId, GetMoveDescription(move), 0), widthPx); } TEST("Item names fit on Bag Screen (list)") diff --git a/tools/trainerproc/main.c b/tools/trainerproc/main.c index f1bcf1bfa4ae..fda4ac7c3f9e 100644 --- a/tools/trainerproc/main.c +++ b/tools/trainerproc/main.c @@ -123,6 +123,9 @@ struct Trainer struct String starting_status; int starting_status_line; + + struct String difficulty; + int difficulty_line; }; static bool is_empty_string(struct String s) @@ -1195,9 +1198,16 @@ static bool parse_trainer(struct Parser *p, const struct Parsed *parsed, struct trainer->starting_status_line = value.location.line; trainer->starting_status = token_string(&value); } + else if (is_literal_token(&key, "Difficulty")) + { + if (trainer->difficulty_line) + any_error = !set_show_parse_error(p, key.location, "duplicate 'Difficulty'"); + trainer->difficulty_line = value.location.line; + trainer->difficulty = token_string(&value); + } else { - any_error = !set_show_parse_error(p, key.location, "expected one of 'Name', 'Class', 'Pic', 'Gender', 'Music', 'Items', 'Double Battle', or 'AI'"); + any_error = !set_show_parse_error(p, key.location, "expected one of 'Name', 'Class', 'Pic', 'Gender', 'Music', 'Items', 'Double Battle', 'Difficulty', or 'AI'"); } } if (!trainer->pic_line) @@ -1618,7 +1628,14 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par { struct Trainer *trainer = &parsed->trainers[i]; fprintf(f, "#line %d\n", trainer->id_line); - fprintf(f, " ["); + if (is_empty_string(trainer->difficulty)) + trainer->difficulty = literal_string("Normal"); + else + fprintf(f, "#line %d\n", trainer->difficulty_line); + fprint_constant(f, " [DIFFICULTY",trainer->difficulty); + fprintf(f, "]"); + + fprintf(f, "["); fprint_string(f, trainer->id); fprintf(f, "] =\n"); fprintf(f, " {\n"); @@ -1705,7 +1722,6 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par if (!is_empty_string(trainer->mugshot)) { fprintf(f, "#line %d\n", trainer->mugshot_line); - fprintf(f, " .mugshotEnabled = TRUE,\n"); fprintf(f, " .mugshotColor = "); fprint_constant(f, "MUGSHOT_COLOR", trainer->mugshot); fprintf(f, ",\n"); @@ -1742,17 +1758,17 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par switch (pokemon->gender) { - case GENDER_ANY: - fprintf(f, " .gender = TRAINER_MON_RANDOM_GENDER,\n"); - break; - case GENDER_MALE: - fprintf(f, "#line %d\n", pokemon->header_line); - fprintf(f, " .gender = TRAINER_MON_MALE,\n"); - break; - case GENDER_FEMALE: - fprintf(f, "#line %d\n", pokemon->header_line); - fprintf(f, " .gender = TRAINER_MON_FEMALE,\n"); - break; + case GENDER_ANY: + fprintf(f, " .gender = TRAINER_MON_RANDOM_GENDER,\n"); + break; + case GENDER_MALE: + fprintf(f, "#line %d\n", pokemon->header_line); + fprintf(f, " .gender = TRAINER_MON_MALE,\n"); + break; + case GENDER_FEMALE: + fprintf(f, "#line %d\n", pokemon->header_line); + fprintf(f, " .gender = TRAINER_MON_FEMALE,\n"); + break; } if (!is_empty_string(pokemon->item))