From 2988883a12d6016ff43203b7a8426355cb4fc6fa Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Mon, 29 Jan 2024 12:52:03 -0300 Subject: [PATCH 01/25] Unused warnings are not treated as errrors by default --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index d899015225..df402f96ad 100644 --- a/Makefile +++ b/Makefile @@ -43,6 +43,7 @@ REVISION := 0 MODERN ?= 1 TEST ?= 0 ANALYZE ?= 0 +UNUSED_ERROR?= 0 ifeq (agbcc,$(MAKECMDGOALS)) MODERN := 0 @@ -127,6 +128,9 @@ override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi ifeq ($(ANALYZE),1) override CFLAGS += -fanalyzer endif +ifeq ($(UNUSED_ERROR),0) +override CFLAGS += -Wno-error=unused-variable -Wno-error=unused-variable -Wno-error=unused-const-variable -Wno-error=unused-parameter -Wno-error=unused-function -Wno-error=unused-but-set-parameter -Wno-error=unused-but-set-variable -Wno-error=unused-value -Wno-error=unused-local-typedefs +endif ROM := $(MODERN_ROM_NAME) OBJ_DIR := $(MODERN_OBJ_DIR_NAME) LIBPATH := -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libgcc.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libnosys.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libc.a))" From e8a6c463915fcb4186c8ff2da4faaca61534eaf6 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Mon, 29 Jan 2024 13:19:01 -0300 Subject: [PATCH 02/25] Only do unused error under RHH's repo + workflow test --- .github/workflows/build.yml | 1 + Makefile | 3 +++ src/battle_interface.c | 9 +++++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8c5bcb7ed8..0322cbe11f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,7 @@ jobs: GAME_LANGUAGE: ENGLISH MODERN: 0 COMPARE: 0 + UNUSED_ERROR: 1 steps: - name: Checkout uses: actions/checkout@v2 diff --git a/Makefile b/Makefile index df402f96ad..88376cddef 100644 --- a/Makefile +++ b/Makefile @@ -128,9 +128,12 @@ override CFLAGS += -mthumb -mthumb-interwork -O2 -mabi=apcs-gnu -mtune=arm7tdmi ifeq ($(ANALYZE),1) override CFLAGS += -fanalyzer endif +# Only throw an error for unused elements if its RH-Hideout's repo ifeq ($(UNUSED_ERROR),0) +ifneq ($(GITHUB_REPOSITORY_OWNER),rh-hideout) override CFLAGS += -Wno-error=unused-variable -Wno-error=unused-variable -Wno-error=unused-const-variable -Wno-error=unused-parameter -Wno-error=unused-function -Wno-error=unused-but-set-parameter -Wno-error=unused-but-set-variable -Wno-error=unused-value -Wno-error=unused-local-typedefs endif +endif ROM := $(MODERN_ROM_NAME) OBJ_DIR := $(MODERN_OBJ_DIR_NAME) LIBPATH := -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libgcc.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libnosys.a))" -L "$(dir $(shell $(PATH_MODERNCC) -mthumb -print-file-name=libc.a))" diff --git a/src/battle_interface.c b/src/battle_interface.c index d3751f702f..b8bde1b25d 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -3070,14 +3070,19 @@ static void ClearAbilityName(u8 spriteId1, u8 spriteId2) 7, 9, 1); } -static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2) +static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2, u8 prueba4) { + u8 prueba1; + u8 prueba2 = 2; + const u8 prueba3 = 3; + u8 prueba5; int i; u8 lastChar; u8* textPtr; u8 monName[POKEMON_NAME_LENGTH + 3] = {0}; u8* nick = gBattleMons[battlerId].nickname; // This needs to be updated for Illusion support + prueba5 = 5; for (i = 0; i < POKEMON_NAME_LENGTH; ++i) { monName[i] = nick[i]; @@ -3309,7 +3314,7 @@ void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) StartSpriteAnim(&gSprites[spriteId1], 0); StartSpriteAnim(&gSprites[spriteId2], 0); - PrintBattlerOnAbilityPopUp(battlerId, spriteId1, spriteId2); + PrintBattlerOnAbilityPopUp(battlerId, spriteId1, spriteId2, 0); PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2); RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32)); } From a0bcdbff42c3597ae3b9901852015195bc6d1a50 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Mon, 29 Jan 2024 13:31:42 -0300 Subject: [PATCH 03/25] Workflow test worked, undoing changes --- src/battle_interface.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/battle_interface.c b/src/battle_interface.c index b8bde1b25d..d3751f702f 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -3070,19 +3070,14 @@ static void ClearAbilityName(u8 spriteId1, u8 spriteId2) 7, 9, 1); } -static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2, u8 prueba4) +static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2) { - u8 prueba1; - u8 prueba2 = 2; - const u8 prueba3 = 3; - u8 prueba5; int i; u8 lastChar; u8* textPtr; u8 monName[POKEMON_NAME_LENGTH + 3] = {0}; u8* nick = gBattleMons[battlerId].nickname; // This needs to be updated for Illusion support - prueba5 = 5; for (i = 0; i < POKEMON_NAME_LENGTH; ++i) { monName[i] = nick[i]; @@ -3314,7 +3309,7 @@ void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) StartSpriteAnim(&gSprites[spriteId1], 0); StartSpriteAnim(&gSprites[spriteId2], 0); - PrintBattlerOnAbilityPopUp(battlerId, spriteId1, spriteId2, 0); + PrintBattlerOnAbilityPopUp(battlerId, spriteId1, spriteId2); PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2); RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32)); } From f7e5709745d6dc313b131330d1131eef7169e3f9 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada Date: Wed, 31 Jan 2024 08:18:43 -0300 Subject: [PATCH 04/25] Review changes --- Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 88376cddef..5632b3570e 100644 --- a/Makefile +++ b/Makefile @@ -36,14 +36,14 @@ else EXE := endif -TITLE := POKEMON EMER -GAME_CODE := BPEE -MAKER_CODE := 01 -REVISION := 0 -MODERN ?= 1 -TEST ?= 0 -ANALYZE ?= 0 -UNUSED_ERROR?= 0 +TITLE := POKEMON EMER +GAME_CODE := BPEE +MAKER_CODE := 01 +REVISION := 0 +MODERN ?= 1 +TEST ?= 0 +ANALYZE ?= 0 +UNUSED_ERROR ?= 0 ifeq (agbcc,$(MAKECMDGOALS)) MODERN := 0 @@ -130,8 +130,8 @@ override CFLAGS += -fanalyzer endif # Only throw an error for unused elements if its RH-Hideout's repo ifeq ($(UNUSED_ERROR),0) -ifneq ($(GITHUB_REPOSITORY_OWNER),rh-hideout) -override CFLAGS += -Wno-error=unused-variable -Wno-error=unused-variable -Wno-error=unused-const-variable -Wno-error=unused-parameter -Wno-error=unused-function -Wno-error=unused-but-set-parameter -Wno-error=unused-but-set-variable -Wno-error=unused-value -Wno-error=unused-local-typedefs +ifneq ($(GITHUB_REPOSITORY_OWNER),rh-hideout) +override CFLAGS += -Wno-error=unused-variable -Wno-error=unused-const-variable -Wno-error=unused-parameter -Wno-error=unused-function -Wno-error=unused-but-set-parameter -Wno-error=unused-but-set-variable -Wno-error=unused-value -Wno-error=unused-local-typedefs endif endif ROM := $(MODERN_ROM_NAME) From 2d24f964206cd9670d8d0e4fa22c03126ad3541c Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Thu, 1 Feb 2024 20:55:53 -0300 Subject: [PATCH 05/25] Version 1.7.3 (#4106) * Version 1.7.3 * Latest changelog --- .../ISSUE_TEMPLATE/01_battle_engine_bugs.yaml | 3 +- .github/ISSUE_TEMPLATE/04_other_errors.yaml | 3 +- CHANGELOG.md | 13 ++-- README.md | 4 +- docs/changelogs/1.7.2.md | 2 +- docs/changelogs/1.7.3.md | 77 +++++++++++++++++++ docs/changelogs/template.md | 6 +- include/constants/expansion.h | 4 +- 8 files changed, 96 insertions(+), 16 deletions(-) create mode 100644 docs/changelogs/1.7.3.md diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 44cc8c2891..6493f4c11b 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.7.2 (Latest release) + - 1.7.3 (Latest release) - master (default when pulling, unreleased bugfixes) - upcoming (Edge) + - 1.7.2 - 1.7.1 - 1.7.0 - 1.6.2 diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index 41d5c30eff..e39eac4f56 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.7.2 (Latest release) + - 1.7.3 (Latest release) - master (default when pulling, unreleased bugfixes) - upcoming (Edge) + - 1.7.2 - 1.7.1 - 1.7.0 - 1.6.2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fba967c8a..d4805a5d40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Pokeemerald-Expansion Changelogs -## [Version 1.7.2](docs/changelogs/1.7.2.md) - Bugfix Release +## Version 1.7.x +### [Version 1.7.3](docs/changelogs/1.7.3.md) - Bugfix Release +### [Version 1.7.2](docs/changelogs/1.7.2.md) - Bugfix Release +### [Version 1.7.1](docs/changelogs/1.7.1.md) - Bugfix Release +### [Version 1.7.0](docs/changelogs/1.7.0.md) - Feature Release -## [Version 1.7.1](docs/changelogs/1.7.1.md) - Bugfix Release - -## [Version 1.7.0](docs/changelogs/1.7.0.md) - Feature Release - -## [Version 1.6.2](docs/changelogs/1.6.2.md) - Bugfix Release +## Version 1.6.x +### [Version 1.6.2](docs/changelogs/1.6.2.md) - Bugfix Release diff --git a/README.md b/README.md index 53dc2ab6ed..9f2e022dd6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ pokeemerald-expansion is a decomp hack base project based off pret's [pokeemeral 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 v1.7.2 https://github.com/rh-hideout/pokeemerald-expansion/ +Based off RHH's pokeemerald-expansion v1.7.3 https://github.com/rh-hideout/pokeemerald-expansion/ ``` ## What features are included? @@ -166,7 +166,7 @@ With this, you'll get the latest version of pokeemerald-expansion, plus a couple ## **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`. -- Once you have your remote set up, run the command `git pull RHH expansion/1.7.2`. +- Once you have your remote set up, run the command `git pull RHH expansion/1.7.3`. ### 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 :) diff --git a/docs/changelogs/1.7.2.md b/docs/changelogs/1.7.2.md index 8fc0d60565..1c94bbda3d 100644 --- a/docs/changelogs/1.7.2.md +++ b/docs/changelogs/1.7.2.md @@ -1,4 +1,4 @@ -# Template +# Version 1.7.2 ```md ## How to update diff --git a/docs/changelogs/1.7.3.md b/docs/changelogs/1.7.3.md new file mode 100644 index 0000000000..4727e195bc --- /dev/null +++ b/docs/changelogs/1.7.3.md @@ -0,0 +1,77 @@ +# Version 1.7.3 + +```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.7.3`. +``` + +## 🌋 *IMPORTANT CHANGES* 🌋 +* Unused warnings are no longer treated as errrors by default by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4092 +* [Critical fix] Backported gHeap alignment fix from upstream pret by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4089 + * Fixes issue that causes graphics to bug when leaving Littleroot for Birch's cutscene. + +## 🧬 General 🧬 +* Fixed HGSS Dex's dark mode search palette by @ravepossum in https://github.com/rh-hideout/pokeemerald-expansion/pull/4095 + +## 🐉 Pokémon 🐉 +### Changed +* Condensed Oinkologne teachable learnsets (they previously had different tables despite having the same learnsets) by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4026 +* Removed illegal teachable learnset moves that didn't match Gen 7 or 9 by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4039 and https://github.com/rh-hideout/pokeemerald-expansion/pull/4042 +### Fixed +* Fixed incorrect family toggle preproc blocks by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4024 + * Cosplay and Cap Pikachu animations were still being included even if disabled. + * Fixed compile errors when: + * Feebas' family was disabled but not Castform. + * Chatot was disabled but not Spiritomb. + * Virizion was disabled but not Tornadus or Thundurus. + * Zekrom was disabled but not Landorus. + * Kyurem was disabled but not Keldeo or Meloetta. + * Wishiwashi was disabled but not Rockruff. +* Fixed compile error when disabling Gen 4 cross-evolutions while having Kingdra enabled by @Skyeward and @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4044 and https://github.com/rh-hideout/pokeemerald-expansion/pull/4046 + +## ⚔️ Battle General ⚔️ ## +### Fixed +* Fixed Steven double battle palette error by @johannakullmann in https://github.com/rh-hideout/pokeemerald-expansion/pull/4078 + +## 🤹 Moves 🤹 +### Changed +* Renamed `EFFECT_STEEL_BEAM` to `EFFECT_MAX_HP_50_RECOIL` by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4043 +### Fixed +* Fixed Pursuit's effect not working by @ZnogyroP @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4086 + +## 🎭 Abilities 🎭 +### Fixed +* Fixed Emergency Exit issues: + * Fixed rounding error that caused it to not switch out when odd-numbered HP was off by 1 by @SBird1337 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4040 + * Eg: going from 101 Max HP to 50 HP would've *not* cause it to switch out. + * Fixes Emergency Exit switching out even if the Pokémon was healed above the threshold before it would've triggered by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4041 + * Eg: going from 100 Max HP to 45 HP and eating a Sitrus Berry back to 55 HP would've cause it to switch out. + * Cleanup by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4100 +* Fixed Corrosion only working for status moves by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4037 +* Fixed Magic Guard not preventing Mind Blown recoil damage by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4043 + +## 🧶 Items 🧶 +### Fixed +* Fixed oversight causing chosen fossil to be lost if bag is full by @fakuzatsu in https://github.com/rh-hideout/pokeemerald-expansion/pull/3978 + * Fixed other Key Item script oversights by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4066 +* Fixed Life Orb causing damage on switch-in from Eject Pack and Red Card by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4038 +* Fixed Glimmering Charm sprite by @SonikkuA-DatH and @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4047 + +## 🤖 Battle AI 🤖 +### Fixed +* Fixed AI trying to switch into the same mon twice in the same turn by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/4098 + +## 🧪 Test Runner 🧪 +### Added +* Corrosion tests by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4037 +* Pursuit/Tangling Hair interaction by @ZnogyroP @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4086 +### Changed +* Passing `KNOWN_FAILING` tests are now listed separately from `PASSED` tests by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4063 + +## New Contributors +* @Skyeward made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4044 + +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.2...expansion/1.7.3 + + diff --git a/docs/changelogs/template.md b/docs/changelogs/template.md index 607d69592a..f67520c388 100644 --- a/docs/changelogs/template.md +++ b/docs/changelogs/template.md @@ -3,7 +3,7 @@ ```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.7.2`. +- Once you have your remote set up, run the command `git pull RHH expansion/1.Y.Z`. ``` ## 🌋 *IMPORTANT CHANGES* 🌋 @@ -88,6 +88,6 @@ ## New Contributors * Tony -**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.7.1...expansion/1.7.2 +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.Y.Z...expansion/1.Y.Z - + diff --git a/include/constants/expansion.h b/include/constants/expansion.h index 84a14db36b..42af988a19 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -3,10 +3,10 @@ #define EXPANSION_VERSION_MAJOR 1 #define EXPANSION_VERSION_MINOR 7 -#define EXPANSION_VERSION_PATCH 2 +#define EXPANSION_VERSION_PATCH 3 // FALSE if this this version of Expansion is not a tagged commit, i.e. // it contains unreleased changes. -#define EXPANSION_TAGGED_RELEASE FALSE +#define EXPANSION_TAGGED_RELEASE TRUE #endif From e828ae58a1f6790f275adec73a3b3ff6f688fc2f Mon Sep 17 00:00:00 2001 From: kaicardenas2 <150625530+kaicardenas2@users.noreply.github.com> Date: Thu, 1 Feb 2024 19:20:10 -0500 Subject: [PATCH 06/25] Non-Tagged Release (#4109) --- include/constants/expansion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/constants/expansion.h b/include/constants/expansion.h index 42af988a19..7e6cf52b26 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -7,6 +7,6 @@ // FALSE if this this version of Expansion is not a tagged commit, i.e. // it contains unreleased changes. -#define EXPANSION_TAGGED_RELEASE TRUE +#define EXPANSION_TAGGED_RELEASE FALSE #endif From f1b6fbb80011b983d086b36fa88378be7f5b0377 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 2 Feb 2024 18:09:04 +0100 Subject: [PATCH 07/25] Indigo Disk sprites --- graphics/pokemon/gouging_fire/back.png | Bin 0 -> 804 bytes graphics/pokemon/gouging_fire/front.png | Bin 0 -> 1159 bytes graphics/pokemon/gouging_fire/normal.pal | 19 ++++++++ graphics/pokemon/gouging_fire/shiny.pal | 19 ++++++++ graphics/pokemon/hydrapple/back.png | Bin 0 -> 829 bytes graphics/pokemon/hydrapple/front.png | Bin 0 -> 1159 bytes graphics/pokemon/hydrapple/icon.png | Bin 0 -> 550 bytes graphics/pokemon/hydrapple/normal.pal | 19 ++++++++ graphics/pokemon/hydrapple/shiny.pal | 19 ++++++++ graphics/pokemon/iron_boulder/back.png | Bin 0 -> 674 bytes graphics/pokemon/iron_boulder/front.png | Bin 0 -> 1041 bytes graphics/pokemon/iron_boulder/normal.pal | 19 ++++++++ graphics/pokemon/iron_boulder/shiny.pal | 19 ++++++++ graphics/pokemon/iron_crown/back.png | Bin 0 -> 765 bytes graphics/pokemon/iron_crown/front.png | Bin 0 -> 930 bytes graphics/pokemon/iron_crown/normal.pal | 19 ++++++++ graphics/pokemon/iron_crown/shiny.pal | 19 ++++++++ graphics/pokemon/raging_bolt/back.png | Bin 0 -> 840 bytes graphics/pokemon/raging_bolt/front.png | Bin 0 -> 1232 bytes graphics/pokemon/raging_bolt/normal.pal | 19 ++++++++ graphics/pokemon/raging_bolt/shiny.pal | 19 ++++++++ src/data/graphics/pokemon.h | 42 ++++++++-------- src/data/pokemon/species_info/gen_8.h | 14 +++--- src/data/pokemon/species_info/gen_9.h | 58 +++++++++++------------ 24 files changed, 247 insertions(+), 57 deletions(-) create mode 100644 graphics/pokemon/gouging_fire/back.png create mode 100644 graphics/pokemon/gouging_fire/front.png create mode 100644 graphics/pokemon/gouging_fire/normal.pal create mode 100644 graphics/pokemon/gouging_fire/shiny.pal create mode 100644 graphics/pokemon/hydrapple/back.png create mode 100644 graphics/pokemon/hydrapple/front.png create mode 100644 graphics/pokemon/hydrapple/icon.png create mode 100644 graphics/pokemon/hydrapple/normal.pal create mode 100644 graphics/pokemon/hydrapple/shiny.pal create mode 100644 graphics/pokemon/iron_boulder/back.png create mode 100644 graphics/pokemon/iron_boulder/front.png create mode 100644 graphics/pokemon/iron_boulder/normal.pal create mode 100644 graphics/pokemon/iron_boulder/shiny.pal create mode 100644 graphics/pokemon/iron_crown/back.png create mode 100644 graphics/pokemon/iron_crown/front.png create mode 100644 graphics/pokemon/iron_crown/normal.pal create mode 100644 graphics/pokemon/iron_crown/shiny.pal create mode 100644 graphics/pokemon/raging_bolt/back.png create mode 100644 graphics/pokemon/raging_bolt/front.png create mode 100644 graphics/pokemon/raging_bolt/normal.pal create mode 100644 graphics/pokemon/raging_bolt/shiny.pal diff --git a/graphics/pokemon/gouging_fire/back.png b/graphics/pokemon/gouging_fire/back.png new file mode 100644 index 0000000000000000000000000000000000000000..8a0f79ef5cff3509e824be4147fc7a276be16676 GIT binary patch literal 804 zcmV+<1Ka$GP)mte%x8lCVbH(latLU0hsrJv2QL8JJ)>XE3yq0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs0007$Nkl9lYH44k)=xjsJV9eyPt%ik1WUKV#d z0OcnK1kfk|>g--`H4`lL`fmXj2N-~P29{-M6;}s1s5=K<06YSFcq9w}Bt^_sVrR*S zk%H=)0{Jo5(_wrdrF%VDsZ_$+6P_F>rn7TA?WS(yz6Dr5`=g}YJ-2|-mJmU6SUyaD zIZ_^64u)Yt|Eqo(mCY0|s^`~$iT)eFWIw%4!W7WEFayqabf=gDLIpH;Yv;lokW-bf zb-Vy?(+Hncwp6AHNXP3el1!^RGU%7I8v*BgGXP}M+Gzj;fD*8~@Wvy(`m9X}3j!#i zIC2gKX2)9Y+8cI(HSP%6(=-o$hlLD40Xsw|!c+!#76RaiB?kF3VcMSwwH#~>_>9?i z)rrst`wgM$;Te$GQ*ojtT<__iUmXC;0SBW}1Bf#iu4yP|)I~7iVNR4E^hR!1BoX9> za|bd?8SK6e$FcXOSdr?-XF~>Qvo0N(hj5$(nAu|;9Ue>CKHI@9ls3OokJ^y(v~^xs zsbp2ATt?!AEcdo4fq(P18(Ify#bI&;zoid0l5{Y|0F<%9E+T12QCjav(2DhQLPzG` zrUcGHUg3JnKtl*UE`W-FW`zMvkOg%8QmV!?X*s-!xRfLL$0%b~W75>mte%xMj5I7!$Dh|G(Yt zmSIBzbA8yVb%m*9;y#vI66ALKkC)kR0r%e!i~#@5>5eOXn_yes0NDK}fcp>#oKC=Z z2*yQ1A|Z9amu)m`$1+PIki&Oh4#Dr+f^_%^z#W^@otgmzSP&n+VFDOZ+YX@K1lXO( zAM=P97y%570N{x~byOZd3#b!td=Fp%0fxBF&SUvBBM<#>XAP4@G(&Qp{T2Pq+?c}< z2~6~Z?>rYU$~C~Ejc$g$B18a>DfG$5Lj5H`ZGd3mS(+vW9{R^4^vO%fU4LE(cEO$b z+BAvqqUY%XnTwQyLC>2A~D`wUN(@ ziGwwyzxuz;KxxjqC#Lod0N&dofLU*(uH_j>LRuE(*;Dio7$(3F0IH)8szHkvTe~$B zBj0i)^lTxw4x5JnXq2S46HV3U!)Vd5gb42W4WnAc}}XogEqK7?xW7lwdo67N`qo0vy;*X8@2R zhZ6uFC0v?COIsJof}N0P0djCn*3m*fS#$(%3MpU~CA8-lltViiD#o_h3YC&eeGz3xS%1<2uSru|uKoNTQb-BD`~ zU~N@70Pse@6wc`X2*JzvU^n*V-2+=|YYln;>MOyubut}~yVpaXNnO0gU5-0m0_ZXAT6n;QsCE4X z09N`2n4P~gXj>T-07CFvtE}W%4mpG1xE*;1c;c_k@EtjTpdLmmG*Mncz!m^XL)bYy z@Rs=VrpZIq&SM|O5qA2^@!A7GONlH3iYMw}BVOJVK-NQ!cjb0G9ydyC@xtt2m{Xs1 z{;H+Q9RP<%RPkuA9dLscoR~(f0PEgIs_D}>AsueR7tAu+m2DL}B7+r!h*$i}{Wy$` z8@Q);Sa-)aYb(-S8?W~vmV5ZBGShm}AX!}nYw_poKBOHZ4kbTqI)*nd0K|3i>jpb! z4i6b8-8nBXd?}9W5&(q4WDA@Cc%O)xoazHm2suB(pRUuz1B$MzBR*X{!XK&?LtOu8 Z{Q(-XH!`1q*1Z4#002ovPDHLkV1j}g4+H=J literal 0 HcmV?d00001 diff --git a/graphics/pokemon/gouging_fire/normal.pal b/graphics/pokemon/gouging_fire/normal.pal new file mode 100644 index 0000000000..26c06154b0 --- /dev/null +++ b/graphics/pokemon/gouging_fire/normal.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +154 212 167 +76 44 11 +255 222 123 +8 8 8 +184 148 35 +249 199 40 +99 86 99 +210 212 207 +172 158 149 +53 140 58 +78 198 90 +136 17 14 +192 25 22 +151 77 32 +81 36 0 +207 114 56 diff --git a/graphics/pokemon/gouging_fire/shiny.pal b/graphics/pokemon/gouging_fire/shiny.pal new file mode 100644 index 0000000000..115a249070 --- /dev/null +++ b/graphics/pokemon/gouging_fire/shiny.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +154 212 167 +61 17 25 +249 189 116 +8 8 8 +199 100 36 +235 148 37 +99 86 99 +210 212 207 +172 158 149 +39 146 176 +70 220 210 +51 50 50 +93 92 92 +116 61 52 +61 17 25 +152 96 57 diff --git a/graphics/pokemon/hydrapple/back.png b/graphics/pokemon/hydrapple/back.png new file mode 100644 index 0000000000000000000000000000000000000000..f84712a508af9a67d89eb9b93c815e52122fc87f GIT binary patch literal 829 zcmV-D1H$}?P)vJNbiCd{XkjI>Y_+-qYzMA@q#EdpYwd z(I%9piw^P9MCR1$ko`mbBq1hpt03C>g!ER9*i}!8gjO*zUU{B(YINE}FJ6*kTJ;QK zbUJJCGX|`GluBV4yDO2Mx6~5vY$}D3+lcIZp(gkn0m`q4Wpus}-}i4~fS4GjKX86! zfOsv45WnZ4S_7ecBrF3&AV6pV=fuj1NiY_o1mIhIDL`<7umh(<3LysJ?&HNGvV8!; zffV9RxImh~^6W_o4%6^a6Kf#Pma*04GMpe-0jTj=527N(ffS`{Jpgg{=V~n8j;ERy zmT?#UD2drv_$Yg=1H({)AzZRQm?nUQBTTs_LJLL!@C4zpn2t>y_{GBzwx?W_TMZxw zob&MG@|uR4s~EyO?=KEBN7xBW4H&^~=l$@LTY)>MU5DZWYC{T2j}lh${R09KwiCf! z3;q@Ri+m*w;Qj(9fMH*P7rce+ZGfY7lmP9aBv9OJC373d8Uy`yeJ+3+gPC@_t|EII zjKqBkh-%E9s4+?fQHsUn1@2r7)Znz!zbc?@q$ughFHoW;b> z2^^ZX*R6V+xQu}d`1SU?@@=_}^CK1XP5{;AyD*xR^87LezM|$5$Q<2h{H~`nBd~R_{{(S01jnXNoGw=04e|g00;m8000000Mb*F00000NkvXX Hu0mjfP4H}V literal 0 HcmV?d00001 diff --git a/graphics/pokemon/hydrapple/front.png b/graphics/pokemon/hydrapple/front.png new file mode 100644 index 0000000000000000000000000000000000000000..eecdea6d782df1824dd4c7112ecc90d50d6a6517 GIT binary patch literal 1159 zcmV;21bF+2P)ML^aHVUn<{EEjIF*rUdQkgPRVs5)dapCNC?a`x_!cM41R{pP(l|Nk3=&~6>z zPh9*hMtj#0KJmXkdjR;nb9(8H_Qwxiwtjizn&|_87QP9ld9n}CULsT{ft$h!`W>5pSu74CzG{f;CCXQ`%=$ryC|@@MIyXgk^^*`)RM*hc z4}e3y6y141AO+t7vyFa#AU!zbH%8aM$P`sA#Y|i;?^Db&KDp=;`Bvrfpn3wp`3Jy_ zVc~lqTie0-$6bvyF{XT0G6~oU&{@8IV%7j;+vpnrl!i5sW~*TQI7uZkJr^5ooX;!? zXhH&d##nA|Ruc|@etTn-h-9-=HK%~AV2fzJDJ;I0z~mxJ53?nj)WAqDSQuB#CQx+(5W~zl40AzREV<{QukWq{$)>*20EJhiN-vMBh1J^^y0$?tPs2Dp- z0FXT{#7IffChcRS%?Yt9Ohm|Tlm9CyATF^6P2ho3!Gnm1oo|6V@lG{NV)bY_n8^M} z1%MrK35>QgL$<#d&L%yvqqB*Kijf{~6QpD}PHCWW+0pGt0@Juue~V2GOwXT~@;+%5 z8&&x&t^utwl-YW6Z3aQHOg{qjY;vK7QeREhqPvJ#0yXAa01E2U+%P8RFxXjPtxM3l zSV} zo2Aqyi?L>3Z2^93#T%X7!4{?lM#IQiK-+p%BrWe7=+dHJLIMnjnh%wT{$bzrASc^Q6|98qso;HW00z z+V2jGFiIB5%pb8Gu_(qu4EJ z_jVi_%>w_u-YLwbL-v>@5oprc8&$*uyPMa4*@aJVgZWma0000EWmrjOO-%qQ00008 Z000000002eQ0@?kEP) zb924Dz5oCJdz?y~%}SK^O73%<_LTO$q+0goDfafP)zxa|N-1JuT0ucUX*qpc0004( zNkl*#;94lrm?Bp$=v$q`_d%e523%;w(*U(Na#UJw6tIs-_@H0O4m2Zu?O4O zxZ>@Bs!46!d5Q?RRe_bxresJ|Notw1>2Mgls36LN;NTiE5c!rHPhj_2{$r35bK|4^ z*p>kyq%(cRPSsHahR64YRR!&K5b!s5yk5!V!xo&rI~KsBx_VXypbnq)9^5W472pdB zjDl13Al$zPaH#_;`EHm3g+;eNN^nvJ9AX$by->&i9e5bSg7NeamHTER7V$J{Q}g z5A?lU3WRkZNbGeV_#7WHP(CU!|N9V0!-o|$eV7d&V_*KJ@=?wEOdmg$_F$1yqx0_o o000hUSV?A0O#mtY000O800000007cclK=n!07*qoM6N<$f?{L!l>h($ literal 0 HcmV?d00001 diff --git a/graphics/pokemon/hydrapple/normal.pal b/graphics/pokemon/hydrapple/normal.pal new file mode 100644 index 0000000000..6fec9a7957 --- /dev/null +++ b/graphics/pokemon/hydrapple/normal.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +152 208 160 +88 56 32 +16 16 16 +152 24 16 +96 16 8 +32 72 24 +136 88 56 +216 80 64 +72 128 56 +248 160 160 +192 168 80 +40 96 8 +88 168 24 +160 216 72 +240 200 80 +32 88 8 diff --git a/graphics/pokemon/hydrapple/shiny.pal b/graphics/pokemon/hydrapple/shiny.pal new file mode 100644 index 0000000000..d3d0f68f92 --- /dev/null +++ b/graphics/pokemon/hydrapple/shiny.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +152 208 160 +88 56 32 +16 16 16 +216 136 0 +192 80 0 +32 72 24 +136 88 56 +248 208 16 +72 128 56 +248 232 144 +192 168 80 +40 96 8 +88 168 24 +160 216 72 +240 200 80 +32 88 8 diff --git a/graphics/pokemon/iron_boulder/back.png b/graphics/pokemon/iron_boulder/back.png new file mode 100644 index 0000000000000000000000000000000000000000..3c7cf2bf330872d1dd6d3e76f734888947117b97 GIT binary patch literal 674 zcmV;T0$u%yP)pwZ0PTbIfZ0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs0006JNkltoUt;ELjz zDo-J7BZB!Swo3RGlaJ07K#maBwI|>v*8uGOQsray8-T-rfLkYkzbvGy2w~l>grIvck<@b(T>$XgTxA=C(De{D4WRWdW>tXr z4dA3$2=_+;34|RZ~{|yiYK)D$O#Fz=60I2Ce)cBhw1^^If5Fn<; zZ-_F5`Xr@f0P}O_kJrZvhf@Ke1fb(k0>y#Ue*#jH-z$LjLkZG8-67du2nm(D0VXOV zpkxGcByS(0W`s#Ed?6s~aqKBaD5sH<5O%Cy-e851N+53^TMCOQpuW`rNINX>Yqc>h zJDCZ#ln_#KuFg;h>Te7kLi~ti1pKDO1Cjj%zw5T3OCehf0%ib6l2?^$0t~kh!=Nig z+traJ-w+)2i#0*$ zB}0G&XVOk*dQo3=lGOXL`m;H=+yC`fm&l*VH6?9`?ZX#Khr~sp^7FTLbPNCpI*$J3 zD?;cqm+QX=3`tYI-|s~!e}>ap2HCnr2h~xaDF8q&A|C-J)U`dT2>^IcIv7e&N(G_| zu!(?Cn*m720fa%#v=*+~t%Ef{(xzwV0hmNfVK!dcfOW_(5Op#K^GNr*~bS+JRaL4?}{2nOJKPeH`c zR({tFo&xWF>>q>%07$7Bmif4N%mj?jnDBQt~f)v9q0I0eF^RvVO-b?{FHADbNaQ%b`066GZ!14pYQqN6o zlLP$uvzSNg07;vH2tghXc#v0sTM%Xs29SVK6*Vz?0v$miHT>0(UATIX*-{}tk zm~i>UXiIMRWKTW&IM-CIJU!w@au0wlJRFXCHbSK^a@4;jQFU1ns;hIagBOWa?gJPvXHqvg9`AL? zCDQqU;0Y72NR#uI?D_z7lejvF&#{awo=Ht_)-MAOzx@uuWrg;jflQoVHy=CGs9831kd40y+$9OSzG3av+UsW-d(UOyt9&yU-g1(`k+(r}P5QG1i^ zIEnNld_;L^A;)!ih!QFEw+3Pnz%(1{a6!nGhdDRz3|PDN$rhEU!vz3)XFIgw=dU}(a^%J}&EijtZ$Z5!~qrTRx_cMDQ^R!?}-@fZ>(mOoZO+ppz^U|y-P@9695!lC?W3Qn_w2Mj~2WqIRHeK+)lYp%p z9w+i{X(Z>?5Syjcj5@6~YL?EbElR`oaX2KNoF!>mw z2yv(YgF2vLni9f$O<#a;1faDKL>nSCp#&+!wi~p*ZXqmakf8|1(|N5fI#!7-ElLPh ziy@>^QVxn)(>!1Oun-DBR@PPkfG=DqrsE}ml-9M#7XUt(9XVo~U5fTCOXlnWpYWFG)VK)9aCK|slF0Ix9s?NxvR zwow4T0|q7B0oajoK#kL4#{gA;093-zKD+@owjmXLR!gsQ$a+0s61J|LQjBte!p^1b1+W)@n{|}L(tZZufgH~J3>0Vz@_PY6 z038YX=8cyZ2?LrU5SRo2I$h9*MPp_g>8rh{QfuzEk)8m3t7sdk2Ow1J8#k03ItbDc z06G$ZxVSAW0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs0009KNkl}Un+3T4Sk-?oi3A`A$W2d#Y#Hb+!T=F-HzEhLMq~g7$r5-p1-6+C zP%gZO0w)m*oUfadoh2v%>MeNym_C+4 zt<&8DN|d^lKoTX;0E}M&{t7_7E(G?o$mOukg#1<5^DpN>P<;ki+Sv*~c-{-T{j~vG zZ1P)BlT2 zrtBiA{=Ne~1K3Uy&f`u<7e{XTW6>6|J7|Qs1`GAUQ6rbr@W(<0ls15q^S|q6d<1Yd z-tUAJaQN)H1>hy?6W|h_xkHSvUvbVCzNc-i&(+~R@y&00#CO4OpMi|z_TKG!8tQ#I zJYo#@wY#c!^ZYRyOxYhPV|+gy@Cq=Ku#N8F2nX^RFgF0`$N;NCPXqn|D0{~~I@aO) z{!woAivy0$>(A)paACu_IHBb9on^RlIFXhwF?lrn7qiSQT=SOt_y7O^07*qoM6N<$ Eg1mUSY5)KL literal 0 HcmV?d00001 diff --git a/graphics/pokemon/iron_crown/normal.pal b/graphics/pokemon/iron_crown/normal.pal new file mode 100644 index 0000000000..2df8f4b6a9 --- /dev/null +++ b/graphics/pokemon/iron_crown/normal.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +154 212 167 +0 163 172 +96 240 240 +210 248 248 +8 8 8 +179 146 50 +122 86 30 +130 138 163 +240 194 19 +1 68 78 +19 163 180 +59 202 202 +19 114 130 +60 68 78 +202 202 218 +162 202 218 diff --git a/graphics/pokemon/iron_crown/shiny.pal b/graphics/pokemon/iron_crown/shiny.pal new file mode 100644 index 0000000000..aaf724e6b4 --- /dev/null +++ b/graphics/pokemon/iron_crown/shiny.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +154 212 167 +0 163 172 +96 240 240 +210 248 248 +8 8 8 +171 172 186 +50 60 68 +130 138 163 +234 234 240 +96 96 104 +194 194 202 +248 248 251 +138 146 154 +60 68 78 +202 202 218 +162 202 218 diff --git a/graphics/pokemon/raging_bolt/back.png b/graphics/pokemon/raging_bolt/back.png new file mode 100644 index 0000000000000000000000000000000000000000..ae03ffab6b5eee25ffbd0c67b493753a0fd95cd6 GIT binary patch literal 840 zcmV-O1GoH%P)|F)Ge=gwNmb_VyKHLswV#>dACedx~4)^=!UA;#lz0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs0008FNkl?8 z7+-R1)0sM*W}jCpfs?;KdpURUhAVw2uLv%LlHmmaLI`gF4jqK@0s!SLAiOC78%O{Q z5pE$oF4p6%od9k%!pC`@2?1DqE~t06V(_ypPxc|_k~7uuBY@nq10o0@XKv*$0Mv@I zArt_=b+X@?7rurLD8EdzkE0$55Kt&3a1MVLt%RH|0&D-#emfM%X!%-4W*h!Ownat0Iz7&&$etdGDJ3NGyf z0&r8E$4CG|MEYrfB1>F2A#@WvkPw<4EASm4CJGfn9C`aeH57v`qICkz5dtVfm*E_M z<&Ao}&>V@LhY<^KZKmDv?gDnPfbbD^`+E74g1Q)(1-2lIqOBTF} zgDMm4P7P?1G>;_pf)fJ9iS{BAzV3TwfVZ`dly4*12;31zlkoi-08j_B??XKj$cClw z6RFz@IUGdJok4_)O)(OZQcih zX3Yc)o5I851__=ARi9iof;O}tcE!*azVevah|R885p>iH1RN38&mJb(`k{mvcWN^U zI3(;D@r(e6gaa4XfK?9LNANXZS`+*(&2zxS`m{Eo=hZBEL@R?dDWDFF#Z7wz84gIB z1kh^oI|A;N^9)ctEr1@(`p~uJ0M!%KF;&?7X8;&S+e8Ecq`Lixwz#lPwgghagn;c= zmR5-Qv8#1~qNsKM7~wb!ITILxmsG=(Z%rTxV2)(r0ik7xF{G!2B#UDx4+v~Q03VFu z2|)nViBEk(Xrn;CKOZdO8KG?|B!v3}Jq{>Fws8Afv1TXuEP)dCSKt7Mv=5}ak9(R4J0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs000C(NklS~dkSC05AL*@+- zO`?#eC24@#2N78$enY5i^StfmVi6J+#KGxJZ&vW{3jlHi!3P+!1lj;XF>#C*1Wc@7 zJSgYqgAApfkd(CeASH`@A_UQW$JC4if0~j-K^ypj0}L}UCWJ*c-SM0WfN=uM1yiwi z#K$xcupy7|F^iH_3F&RY5aTphYF`U=mfp%(;~t;A_mhJb$u^oqNG`nDOFXT%W8B02^WAmfEEmpmKkd3b?L+Pldc5JSAfl9Pd%&-IF%unE=P}5{S+G@ z-vG5xhY&F9S#EXc05QOP1EdPT%xq>oxwk&x$uxZiOxE+2fHLZP`qVCt-GGOH7%pYh z-~>DEcplfeLuf~P3OeB0h}r?Bd^@_7;0(B*3r+~jaHO7rwWi<+m^_Gdo!0|-FDOy+ zM}Q|XoaHvq(fzm3uO9)H$Xc_m=LP+kj&5M>DHs5N;AOOCGnsW91OS9+qw7ZoS|A}c z?;>{OnCg;ZufGA{!UjEHa(|~)c^rLo+~2^v@);)HhDJtkSesoZN-}1!gHG> zo-@Y4?Tyz?#Pe5_Vm=7ix!XDeM5=)X*pa5(HbW>JRv4#2pQA5pX8^8$(7&b*fXC>C zk0zh_+3L79{dHBd{Ao|bJUalLpDDMliI&7Q>(hWujHzEQzT*piQh&cjZyExGeKa&s z2`ve5Av-TT*#Ncbs0sU!TexyJ;63WcaQ0nqxtyz@%=KLNamwi+=8-t+tg!0V9%ifsGV z_cnh8c-uv8i@D$4dlfPXf2ac@DE>=dB^v-oxeNc3e#6YSZCqhK#;f8TfQevy+x2mj uw}Ycq=}tH~KOe=3X?K&q2k{H|O#T4{bV5MREx82%0000 Date: Fri, 2 Feb 2024 19:06:28 +0100 Subject: [PATCH 08/25] Archaludon --- graphics/pokemon/archaludon/back.png | Bin 0 -> 609 bytes graphics/pokemon/archaludon/front.png | Bin 0 -> 1210 bytes graphics/pokemon/archaludon/normal.pal | 19 +++++++++++++++++++ graphics/pokemon/archaludon/shiny.pal | 19 +++++++++++++++++++ src/data/graphics/pokemon.h | 8 ++++---- src/data/pokemon/species_info/gen_8.h | 16 ++++++++-------- 6 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 graphics/pokemon/archaludon/back.png create mode 100644 graphics/pokemon/archaludon/front.png create mode 100644 graphics/pokemon/archaludon/normal.pal create mode 100644 graphics/pokemon/archaludon/shiny.pal diff --git a/graphics/pokemon/archaludon/back.png b/graphics/pokemon/archaludon/back.png new file mode 100644 index 0000000000000000000000000000000000000000..4b2d3971efb04d27643c20b1855affe8780d66c8 GIT binary patch literal 609 zcmV-n0-pVeP)He>9rOQ(9veVvTmb*75NBaD@@b0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs0005dNkl}c_Md|QgI*ROu{AGJK>;h_MQ^_ig&OeTV*5zHlG!8i7;$1K_|kTVedp3G>9N=yK4>Of|OEEFl-?HQG_J5x#r(>br(#}uyqXk zjG!0c+}AfnaL$=wLV$>oN(J<4mm|0V2|bG;qL1E_gG|)^zF7nq=tBe;eGI{Sk1>!Y zC5r$flK>V3;;A$VMNtE_GB63?4opyzM2nEpz!bOxcgGUhg856G!9`Ld~PB)yD|T=f~Lr z`3Q{X1^*O5c)I%lM~>tDywhk`s&5dUAB^QDh@;#Io#bT%v%H6;9H)C@y@FOI}zx!X*^^e555xUB%25w vKJqYI-X?j9(Byotb}bkW>|a#0000G zbW%=J|NsC0|NsC0|NsC0|NsC0%^|Xs000CjNklwS?IdtabWu>3?nGruAmB?lZt}?6M7n^=7i}`%Jwz5KNcBX;A3C^0%$(KKE}a-4~Y{%7y-#~nU5om0G8tp92Si+NTuLE&c~4- z0`SEohE$#a>=xKFj{^P!0C&~?A>i)-LinEc@^t9|;0(EpPY1vn`k7a(DnPyhShD1g zeF6X;Sg3*>E4TpBpyYRZ1>^$~Bx6_7Ai!GJdX?UH4?d(h_LZYW5mMBP*lN1}X#2N#Rb>%4_D1eyb)&VVzD!|HcE`TMN3vt<&kjf*CT7|H0Wl_7UTXRGXl@Qp^ zZ!s_nvsVGvFt|;6R&$Ix(litfur~nZ)(JXD4jDp#2J6;GO8OKXgk|O_k@d3`5{PDh zj9KN~320uJCqF9Ec_v%20%A7RZr?kL72qw7O zmk>IjL~Vy8F@Sa0LmzvEAEf^a7ln~ zsDjhRV(f+BX{Oo+01N`Egy2hyD4P!{^-5}Am;h2Is=X;8??S2-7(58kHCQpz5aJjd z5ZRr`xlrxn;C>k3=0mtA$&%pq8U<>AwuexbQELH-EbhZlCdFdOtqO>` zfSO8o#zT;z#j*HMr~r*p&|9LFz$jo?XosU#f*xO6Dztp+Ng4e#v1f*aGi?dCylr_B z%*kvEu_b!37r~R1HYX?|T!dz<*OsXOeft0bW0);i7s2w@-Ypt|*8uqYmqIbqkwC#3 zQ@+2R*zY&WzY%Id=wxb$F928Qw*E=ARkF0f_72E$y}>og0|Ch+3q%L-i+#PM8K7K& zSSmsXRxSWkANWOrU();zVQ;t|h((iVfLNpO7Db)j{y5utx%ZKcUjyLkD3c)A>!S(K zCc2*zGH#ISgUAHXUw|_}sDSs|W^MqkF}o8+fV`wZ=XV|dwQ}YFoj1P${r%xXmNL&= zz{L9PLvTQiPn$5~ju6E1C^qtb1tA2xr|>VsVN0}9v7z}^%x}j&cj#qo3i#6+YwPp* Y2aSAH#dxm>@c;k-07*qoM6N<$f^r-viU0rr literal 0 HcmV?d00001 diff --git a/graphics/pokemon/archaludon/normal.pal b/graphics/pokemon/archaludon/normal.pal new file mode 100644 index 0000000000..cda3805601 --- /dev/null +++ b/graphics/pokemon/archaludon/normal.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +154 212 167 +136 73 83 +8 8 8 +189 126 61 +224 90 94 +240 225 123 +3 33 81 +105 99 119 +223 226 244 +252 253 253 +184 181 206 +49 93 142 +141 132 166 +18 56 103 +98 133 172 +132 109 58 diff --git a/graphics/pokemon/archaludon/shiny.pal b/graphics/pokemon/archaludon/shiny.pal new file mode 100644 index 0000000000..79e6173d9a --- /dev/null +++ b/graphics/pokemon/archaludon/shiny.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +154 212 167 +134 152 175 +8 8 8 +174 103 68 +217 226 242 +227 155 106 +17 62 103 +61 65 71 +131 147 160 +172 186 203 +107 116 127 +52 154 201 +83 90 99 +23 98 141 +118 190 214 +241 240 251 diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 2dd93eb118..efb16af883 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -11574,10 +11574,10 @@ const u8 gMonFootprint_QuestionMark[] = INCBIN_U8("graphics/pokemon/question_mar #endif //P_GIGANTAMAX_FORMS #if P_GEN_9_CROSS_EVOS - // const u32 gMonFrontPic_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/front.4bpp.lz"); - // const u32 gMonPalette_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/normal.gbapal.lz"); - // const u32 gMonBackPic_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/back.4bpp.lz"); - // const u32 gMonShinyPalette_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/shiny.gbapal.lz"); + const u32 gMonFrontPic_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/front.4bpp.lz"); + const u32 gMonPalette_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/normal.gbapal.lz"); + const u32 gMonBackPic_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/back.4bpp.lz"); + const u32 gMonShinyPalette_Archaludon[] = INCBIN_U32("graphics/pokemon/archaludon/shiny.gbapal.lz"); // const u8 gMonIcon_Archaludon[] = INCBIN_U8("graphics/pokemon/archaludon/icon.4bpp"); #if P_FOOTPRINTS // const u8 gMonFootprint_Archaludon[] = INCBIN_U8("graphics/pokemon/archaludon/footprint.1bpp"); diff --git a/src/data/pokemon/species_info/gen_8.h b/src/data/pokemon/species_info/gen_8.h index bae9dadea8..1bdf34835c 100644 --- a/src/data/pokemon/species_info/gen_8.h +++ b/src/data/pokemon/species_info/gen_8.h @@ -1985,7 +1985,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .backPicYOffset = 0, .backAnimId = BACK_ANIM_NONE, PALETTES(Hydrapple), - ICON(Hydrapple, 0), + ICON(Hydrapple, 1), //FOOTPRINT(Hydrapple) LEARNSETS(Hydrapple), }, @@ -4333,15 +4333,15 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .pokemonOffset = 2, .trainerScale = 286, .trainerOffset = 1, - //FRONT_PIC(Archaludon, 64, 64), + FRONT_PIC(Archaludon, 64, 64), .frontPicYOffset = 0, .frontAnimFrames = sAnims_Archaludon, - //.frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, - //BACK_PIC(Archaludon, 64, 64), - .backPicYOffset = 0, - //.backAnimId = BACK_ANIM_NONE, - //PALETTES(Archaludon), - //ICON(Archaludon, 0), + .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + BACK_PIC(Archaludon, 64, 64), + .backPicYOffset = 7, + .backAnimId = BACK_ANIM_NONE, + PALETTES(Archaludon), + // ICON(Archaludon, 0), //FOOTPRINT(Archaludon) LEARNSETS(Archaludon), }, From 3a45f0de0aa07811d4cc3f5bcae0aabd57de6131 Mon Sep 17 00:00:00 2001 From: Eduardo Quezada D'Ottone Date: Fri, 2 Feb 2024 16:12:39 -0300 Subject: [PATCH 09/25] Apply suggestions from code review --- src/data/pokemon/species_info/gen_8.h | 2 +- src/data/pokemon/species_info/gen_9.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data/pokemon/species_info/gen_8.h b/src/data/pokemon/species_info/gen_8.h index 1bdf34835c..3e956b371a 100644 --- a/src/data/pokemon/species_info/gen_8.h +++ b/src/data/pokemon/species_info/gen_8.h @@ -4341,7 +4341,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .backPicYOffset = 7, .backAnimId = BACK_ANIM_NONE, PALETTES(Archaludon), - // ICON(Archaludon, 0), + //ICON(Archaludon, 0), //FOOTPRINT(Archaludon) LEARNSETS(Archaludon), }, diff --git a/src/data/pokemon/species_info/gen_9.h b/src/data/pokemon/species_info/gen_9.h index c9f1eb4950..c0feb0b3e9 100644 --- a/src/data/pokemon/species_info/gen_9.h +++ b/src/data/pokemon/species_info/gen_9.h @@ -5476,7 +5476,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .backPicYOffset = 6, .backAnimId = BACK_ANIM_NONE, PALETTES(GougingFire), - // ICON(GougingFire, 0), + //ICON(GougingFire, 0), //FOOTPRINT(GougingFire) LEARNSETS(GougingFire), }, @@ -5526,7 +5526,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .backPicYOffset = 0, .backAnimId = BACK_ANIM_NONE, PALETTES(RagingBolt), - // ICON(RagingBolt, 0), + //ICON(RagingBolt, 0), //FOOTPRINT(RagingBolt) LEARNSETS(RagingBolt), }, @@ -5575,7 +5575,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .backPicYOffset = 12, .backAnimId = BACK_ANIM_NONE, PALETTES(IronBoulder), - // ICON(IronBoulder, 0), + //ICON(IronBoulder, 0), //FOOTPRINT(IronBoulder) LEARNSETS(IronBoulder), }, @@ -5625,7 +5625,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .backPicYOffset = 2, .backAnimId = BACK_ANIM_NONE, PALETTES(IronCrown), - // ICON(IronCrown, 0), + //ICON(IronCrown, 0), //FOOTPRINT(IronCrown) LEARNSETS(IronCrown), }, From ab2774f8c7976bdc915319508e65e392fdcbc447 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sat, 3 Feb 2024 16:00:41 +0100 Subject: [PATCH 10/25] Adds Dragon Cheer (#4122) * Adds Dragon Cheer * fix assumptions --------- Co-authored-by: ghoulslash <41651341+ghoulslash@users.noreply.github.com> --- data/battle_anim_scripts.s | 2 +- data/battle_scripts_1.s | 4 +- data/battle_scripts_2.s | 2 +- include/constants/battle.h | 9 +-- include/constants/battle_move_effects.h | 1 + src/battle_ai_main.c | 10 ++- src/battle_ai_switch_items.c | 2 +- src/battle_main.c | 2 +- src/battle_message.c | 2 +- src/battle_script_commands.c | 19 ++++-- src/battle_util.c | 6 +- src/battle_z_move.c | 2 +- src/data/battle_move_effects.h | 7 ++ src/data/moves_info.h | 3 +- src/item_use.c | 2 +- test/battle/crit_chance.c | 91 ++++++++++++++++++++++++- 16 files changed, 138 insertions(+), 26 deletions(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 6a9fce1b89..0f79ab4e1a 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -17159,7 +17159,7 @@ Move_RAGING_BULL:: restorebg waitbgfadein end - + @ Credits to Z-nogyroP. Simple anim that combines Force Palm + Fake Out Move_UPPER_HAND:: loadspritegfx ANIM_TAG_SHADOW_BALL diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 685378df8f..c814b85510 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -3579,7 +3579,7 @@ BattleScript_EffectFocusEnergy:: attackcanceler attackstring ppreduce - jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY, BattleScript_ButItFailed + jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY_ANY, BattleScript_ButItFailed setfocusenergy attackanimation waitanimation @@ -9941,10 +9941,8 @@ BattleScript_RaiseCritAlliesLoop: setstatchanger STAT_ATK, 0, FALSE @ for animation setgraphicalstatchangevalues playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 - swapattackerwithtarget printstring STRINGID_PKMNGETTINGPUMPED waitmessage B_WAIT_TIME_LONG - swapattackerwithtarget BattleScript_RaiseCritAlliesIncrement: setbyte sSTAT_ANIM_PLAYED, FALSE jumpifbytenotequal gBattlerTarget, gBattlerAttacker, BattleScript_RaiseCritAlliesEnd diff --git a/data/battle_scripts_2.s b/data/battle_scripts_2.s index 78e077fbd5..d760e00acd 100644 --- a/data/battle_scripts_2.s +++ b/data/battle_scripts_2.s @@ -114,7 +114,7 @@ BattleScript_ItemSetMist:: BattleScript_ItemSetFocusEnergy:: call BattleScript_UseItemMessage - jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY, BattleScript_ButItFailed + jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY_ANY, BattleScript_ButItFailed setfocusenergy playmoveanimation BS_ATTACKER, MOVE_FOCUS_ENERGY waitanimation diff --git a/include/constants/battle.h b/include/constants/battle.h index ddaa79cbc9..a353fbb357 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -129,7 +129,7 @@ #define STATUS2_FLINCHED (1 << 3) #define STATUS2_UPROAR (1 << 4 | 1 << 5 | 1 << 6) #define STATUS2_UPROAR_TURN(num) ((num) << 4) -#define STATUS2_UNUSED (1 << 7) +#define STATUS2_TORMENT (1 << 7) #define STATUS2_BIDE (1 << 8 | 1 << 9) #define STATUS2_BIDE_TURN(num) (((num) << 8) & STATUS2_BIDE) #define STATUS2_LOCK_CONFUSE (1 << 10 | 1 << 11) // e.g. Thrash @@ -139,7 +139,7 @@ #define STATUS2_POWDER (1 << 14) #define STATUS2_INFATUATION (1 << 16 | 1 << 17 | 1 << 18 | 1 << 19) // 4 bits, one for every battler #define STATUS2_INFATUATED_WITH(battler) (gBitTable[battler] << 16) -#define STATUS2_FOCUS_ENERGY (1 << 20) +#define STATUS2_DEFENSE_CURL (1 << 20) #define STATUS2_TRANSFORMED (1 << 21) #define STATUS2_RECHARGE (1 << 22) #define STATUS2_RAGE (1 << 23) @@ -149,8 +149,9 @@ #define STATUS2_NIGHTMARE (1 << 27) #define STATUS2_CURSED (1 << 28) #define STATUS2_FORESIGHT (1 << 29) -#define STATUS2_DEFENSE_CURL (1 << 30) -#define STATUS2_TORMENT (1 << 31) +#define STATUS2_DRAGON_CHEER (1 << 30) +#define STATUS2_FOCUS_ENERGY (1 << 31) +#define STATUS2_FOCUS_ENERGY_ANY (STATUS2_DRAGON_CHEER | STATUS2_FOCUS_ENERGY) #define STATUS3_LEECHSEED_BATTLER (1 << 0 | 1 << 1) // The battler to receive HP from Leech Seed #define STATUS3_LEECHSEED (1 << 2) diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 4b03a2eef1..004d675701 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -352,6 +352,7 @@ enum { EFFECT_RAIN_ALWAYS_HIT, // Unlike EFFECT_THUNDER, it doesn't get its accuracy reduced under sun. EFFECT_SHED_TAIL, EFFECT_UPPER_HAND, + EFFECT_DRAGON_CHEER, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index a6d320b129..4945a7d873 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -1477,7 +1477,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) ADJUST_SCORE(-10); break; case EFFECT_FOCUS_ENERGY: - if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) + if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY_ANY) ADJUST_SCORE(-10); break; case EFFECT_CONFUSE: @@ -1762,6 +1762,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_FOLLOW_ME: case EFFECT_HELPING_HAND: + case EFFECT_DRAGON_CHEER: if (!isDoubleBattle || !IsBattlerAlive(BATTLE_PARTNER(battlerAtk)) || PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove) @@ -2781,6 +2782,13 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) RETURN_SCORE_PLUS(DECENT_EFFECT); // partner has earthquake or magnitude -> good idea to use magnet rise } break; + case EFFECT_DRAGON_CHEER: + if (gBattleMons[battlerAtkPartner].status2 & STATUS2_FOCUS_ENERGY_ANY || !HasDamagingMove(battlerAtkPartner)) + ADJUST_SCORE(-5); + else if (atkPartnerHoldEffect == HOLD_EFFECT_SCOPE_LENS + || IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_DRAGON) + || gMovesInfo[aiData->partnerMove].criticalHitStage > 0) + ADJUST_SCORE(GOOD_EFFECT); } // our effect relative to partner // consider global move effects diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 657ebb9c73..231ab442a5 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -2088,7 +2088,7 @@ static bool32 ShouldUseItem(u32 battler) break; case EFFECT_ITEM_SET_FOCUS_ENERGY: if (!gDisableStructs[battler].isFirstTurn - || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY + || gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY || AI_OpponentCanFaintAiWithMod(battler, 0)) break; shouldUse = TRUE; diff --git a/src/battle_main.c b/src/battle_main.c index bb10546d9c..e4c5c7a784 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3106,7 +3106,7 @@ void SwitchInClearSetData(u32 battler) } if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS) { - gBattleMons[battler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED); + 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 | STATUS3_GASTRO_ACID | STATUS3_EMBARGO | STATUS3_TELEKINESIS | STATUS3_MAGNET_RISE | STATUS3_HEAL_BLOCK | STATUS3_AQUA_RING | STATUS3_POWER_TRICK); diff --git a/src/battle_message.c b/src/battle_message.c index 28318b3850..258b103af7 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -166,7 +166,7 @@ static const u8 sText_PkmnFreedFrom[] = _("{B_ATK_NAME_WITH_PREFIX} was freed\nf static const u8 sText_PkmnCrashed[] = _("{B_ATK_NAME_WITH_PREFIX} kept going\nand crashed!"); const u8 gText_PkmnShroudedInMist[] = _("{B_ATK_PREFIX2} became\nshrouded in MIST!"); static const u8 sText_PkmnProtectedByMist[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is protected\nby MIST!"); -const u8 gText_PkmnGettingPumped[] = _("{B_ATK_NAME_WITH_PREFIX} is getting\npumped!"); +const u8 gText_PkmnGettingPumped[] = _("{B_DEF_NAME_WITH_PREFIX} is getting\npumped!"); static const u8 sText_PkmnHitWithRecoil[] = _("{B_ATK_NAME_WITH_PREFIX} is hit\nwith recoil!"); static const u8 sText_PkmnProtectedItself2[] = _("{B_ATK_NAME_WITH_PREFIX} protected\nitself!"); static const u8 sText_PkmnBuffetedBySandstorm[] = _("{B_ATK_NAME_WITH_PREFIX} is buffeted\nby the sandstorm!"); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index ec9afc056c..5ea9d6563a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1906,6 +1906,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec else { critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0) + + 1 * ((gBattleMons[battlerAtk].status2 & STATUS2_DRAGON_CHEER) != 0) + gMovesInfo[gCurrentMove].criticalHitStage + (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS) + 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[battlerAtk].species == SPECIES_CHANSEY) @@ -12331,14 +12332,20 @@ static void Cmd_setfocusenergy(void) { CMD_ARGS(); - if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY) + if ((gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || (gAbsentBattlerFlags & gBitTable[gBattlerTarget]))) + || gBattleMons[gBattlerTarget].status2 & STATUS2_FOCUS_ENERGY_ANY) { gMoveResultFlags |= MOVE_RESULT_FAILED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FOCUS_ENERGY_FAILED; } + else if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && !IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_DRAGON)) + { + gBattleMons[gBattlerTarget].status2 |= STATUS2_DRAGON_CHEER; + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED; + } else { - gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY; + gBattleMons[gBattlerTarget].status2 |= STATUS2_FOCUS_ENERGY; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED; } gBattlescriptCurrInstr = cmd->nextInstr; @@ -16539,10 +16546,10 @@ void BS_TryUpperHand(void) { NATIVE_ARGS(const u8 *failInstr); - if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget) - || gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE - || IS_MOVE_STATUS(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 + if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget) + || gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE + || IS_MOVE_STATUS(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 gBattlescriptCurrInstr = cmd->nextInstr; diff --git a/src/battle_util.c b/src/battle_util.c index 4385dc3ecb..d2d5c50925 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6859,7 +6859,7 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect) break; case HOLD_EFFECT_CRITICAL_UP: // lansat berry if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY) + && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) { gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; @@ -6984,7 +6984,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn) break; case HOLD_EFFECT_CRITICAL_UP: if (B_BERRIES_INSTANT >= GEN_4 - && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY) + && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) { gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; @@ -7295,7 +7295,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn) effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, TRUE); break; case HOLD_EFFECT_CRITICAL_UP: - if (!moveTurn && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY) + if (!moveTurn && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY) && HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem)) { gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY; diff --git a/src/battle_z_move.c b/src/battle_z_move.c index 8cb379d892..b2377bffd4 100644 --- a/src/battle_z_move.c +++ b/src/battle_z_move.c @@ -606,7 +606,7 @@ void SetZEffect(void) } break; case Z_EFFECT_BOOST_CRITS: - if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY)) + if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY_ANY)) { gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_BOOST_CRITS; diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 97d91b2630..09234f6fdf 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2229,4 +2229,11 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleScript = BattleScript_EffectUpperHand, .battleTvScore = 0, // TODO: Assign points }, + + [EFFECT_DRAGON_CHEER] = + { + .battleScript = BattleScript_EffectFocusEnergy, + .battleTvScore = 1, + .encourageEncore = TRUE, + }, }; diff --git a/src/data/moves_info.h b/src/data/moves_info.h index e46482e304..b68aecb319 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -2884,6 +2884,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_STATUS, .zMove = { .effect = Z_EFFECT_ACC_UP_1 }, + .argument = STATUS2_FOCUS_ENERGY, .ignoresProtect = TRUE, .mirrorMoveBanned = TRUE, .snatchAffected = TRUE, @@ -19859,7 +19860,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Increases allies' critical hit\n" "ratio, especially if Dragons."), - .effect = EFFECT_PLACEHOLDER, //EFFECT_DRAGON_CHEER + .effect = EFFECT_DRAGON_CHEER, .power = 0, .type = TYPE_DRAGON, .accuracy = 0, diff --git a/src/item_use.c b/src/item_use.c index f9badda639..e711f8cd22 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -1192,7 +1192,7 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon) cannotUse = TRUE; break; case EFFECT_ITEM_SET_FOCUS_ENERGY: - if (gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY) + if (gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY_ANY) cannotUse = TRUE; break; case EFFECT_ITEM_SET_MIST: diff --git a/test/battle/crit_chance.c b/test/battle/crit_chance.c index 66ba62495f..4964767e8e 100644 --- a/test/battle/crit_chance.c +++ b/test/battle/crit_chance.c @@ -212,7 +212,6 @@ SINGLE_BATTLE_TEST("Signature items Leek and Lucky Punch increase the critical h u32 species; u32 item; - ASSUME(B_CRIT_CHANCE >= GEN_7); PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); PARAMETRIZE { species = SPECIES_FARFETCHD; item = ITEM_LEEK; } @@ -250,3 +249,93 @@ SINGLE_BATTLE_TEST("Dire Hit increases a battler's critical hit chance by 2 stag MESSAGE("A critical hit!"); } } + +SINGLE_BATTLE_TEST("Focus Energy increases critical hit ratio by two") +{ + PASSES_RANDOMLY(8, 8, RNG_CRITICAL_HIT); + GIVEN { + ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1); + ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FOCUS_ENERGY); } + TURN { MOVE(player, MOVE_SLASH); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player); + MESSAGE("Wobbuffet is getting pumped!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SLASH, player); + MESSAGE("A critical hit!"); + } +} + +SINGLE_BATTLE_TEST("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("Dragon Cheer increases critical hit ratio by one on non Dragon types") +{ + PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT); + GIVEN { + 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("Dragon Cheer increases critical hit ratio by two on Dragon types") +{ + PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT); + GIVEN { + 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("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!"); + } +} From 85eea4869debe7dcd7e707a89ed6251a3d412651 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sat, 3 Feb 2024 16:56:50 +0100 Subject: [PATCH 11/25] Fix move animation crashing on some emulators because of division by zero (#4121) * fix flip turn div by zero * fix incinerate move anim div by zero --- include/global.h | 2 +- src/battle_anim_ghost.c | 4 ++-- src/battle_anim_mons.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/global.h b/include/global.h index 60abf094af..5cd5c68995 100644 --- a/include/global.h +++ b/include/global.h @@ -61,7 +61,7 @@ // Used in cases where division by 0 can occur in the retail version. // Avoids invalid opcodes on some emulators, and the otherwise UB. #ifdef UBFIX -#define SAFE_DIV(a, b) ((b) ? (a) / (b) : 0) +#define SAFE_DIV(a, b) (((b) != 0) ? (a) / (b) : 0) #else #define SAFE_DIV(a, b) ((a) / (b)) #endif diff --git a/src/battle_anim_ghost.c b/src/battle_anim_ghost.c index 7bd6a0268e..6a12481531 100644 --- a/src/battle_anim_ghost.c +++ b/src/battle_anim_ghost.c @@ -474,8 +474,8 @@ void AnimShadowBall(struct Sprite *sprite) sprite->data[3] = gBattleAnimArgs[2]; sprite->data[4] = sprite->x << 4; sprite->data[5] = sprite->y << 4; - sprite->data[6] = ((oldPosX - sprite->x) << 4) / (gBattleAnimArgs[0] << 1); - sprite->data[7] = ((oldPosY - sprite->y) << 4) / (gBattleAnimArgs[0] << 1); + sprite->data[6] = SAFE_DIV(((oldPosX - sprite->x) << 4), (gBattleAnimArgs[0] << 1)); + sprite->data[7] = SAFE_DIV(((oldPosY - sprite->y) << 4), (gBattleAnimArgs[0] << 1)); sprite->callback = AnimShadowBall_Step; } diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 78e1a0a445..83d91c1ca4 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -1025,8 +1025,8 @@ void InitSpriteDataForLinearTranslation(struct Sprite *sprite) { s16 x = (sprite->data[2] - sprite->data[1]) << 8; s16 y = (sprite->data[4] - sprite->data[3]) << 8; - sprite->data[1] = x / sprite->data[0]; - sprite->data[2] = y / sprite->data[0]; + sprite->data[1] = SAFE_DIV(x, sprite->data[0]); + sprite->data[2] = SAFE_DIV(y, sprite->data[0]); sprite->data[4] = 0; sprite->data[3] = 0; } From 46d9adb32698dbd66d113b04905095dabc2101ad Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sat, 3 Feb 2024 19:34:52 +0100 Subject: [PATCH 12/25] Fixes Eerie Spell double pp and message drop (#4127) Co-authored-by: Bassoonian --- data/battle_scripts_1.s | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 9a26c78dc2..c817ffc4bb 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -4755,26 +4755,7 @@ BattleScript_EffectDestinyBond:: goto BattleScript_MoveEnd BattleScript_EffectEerieSpell:: - attackcanceler - attackstring - ppreduce - accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE - attackstring - ppreduce - critcalc - damagecalc - adjustdamage - attackanimation - waitanimation - effectivenesssound - hitanimation BS_TARGET - waitstate - healthbarupdate BS_TARGET - datahpupdate BS_TARGET - critmessage - waitmessage B_WAIT_TIME_LONG - resultmessage - waitmessage B_WAIT_TIME_LONG + call BattleScript_EffectHit_Ret tryfaintmon BS_TARGET eeriespellppreduce BattleScript_MoveEnd printstring STRINGID_PKMNREDUCEDPP From e75169fb8761c24ca890509428563bb6769b5b07 Mon Sep 17 00:00:00 2001 From: ravepossum <145081120+ravepossum@users.noreply.github.com> Date: Sat, 3 Feb 2024 14:07:47 -0500 Subject: [PATCH 13/25] Fix HGSS Dex List Decapped Tileset (#4126) * fix decap HGSS dex tileset scroll bar * more tileset fixes --------- Co-authored-by: ravepossum Co-authored-by: Bassoonian --- .../pokedex/hgss/tileset_menu_list_DECA.png | Bin 1542 -> 1552 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/graphics/pokedex/hgss/tileset_menu_list_DECA.png b/graphics/pokedex/hgss/tileset_menu_list_DECA.png index dc84b9ea38c68347040e85a4002a4856cf0cbcf8..f7f28de03979cc0cef50747d376373e9dd06be61 100644 GIT binary patch delta 1441 zcmV;S1z!4w43G?vZ~=>vaTR~t2!fy(O*ZM7&Xlt!8!v%R6m;WU5w9hBTbAqNilooS zy#+97$MQb_u%}zHKLxNKJ?=I0HmjSk@bH9VBc*3xr!_o z3$!xFZvl)JnQs>3lK{8mD}dldo^kEK2eJ0#6y#?)(+Yt4t&AB}0^l@P?<0Uv0UH1# z{ywVE0OVZ#Yv6>#;(i8z>_Y(UftG*(a;6dh$NCZ(2Mtj=0-A)HFpVJ4YzoSKLvR6r z(_vBo?2*YL)DtlU2zP%0uF4P~oB)L90MdR7AXotRPCVf`fS_d$wsiIWM?Jt<<^g~l zp!<$dNddb@>UboOMgg|Z5)h@_Jz@FCy`BD&h^C}HK*m2$!6AD>>ha#x5B=@|M0ol{ zRsi-dJP`dkfp7Gf0O>azN^b*LQg^wDo&w#KOaKOBV;T4w`jqX}{t3qRcM0G-fPSz2t$x~O>T#c%P)?^xc%T&r zhaUCc0YE+A;*IE&==8)6YbL3b5x@e?9#AeZJm5d-Bl|FbUjeYf_Avl|22k=tiukVp zieB{Y06 z_;|toIscAbPM=kP1S6$uGuvP=xA<6WNBGztn8ke$0J>oCJicbRl@8>m81pG5PeE#4 zD~>YXIRF~XuY^Vbr9*K8v_ozCc1$Vm%Crt38Mvj!4pty0g8r;0QqHHjPQnD-m683^?1QvP>haW+@GBD;rD^x8==Ngz468n zM5juJo|^s8fJ4wj0J_!{pHFwx*F1m=V)#RYHDp-H#f%p=@XbKt+sJZEuz*rHV>CA)hU^u1+#2Af5_&$K}fMGwk{y2awGl1Nt zALe3`ZE`cZ?*VzvCxD};Cg4(T;E_Et1u4}Sr~tyG22i&P9lcs8ln(+l+Dl-$zGJg)WB^>XO|e^_ zt|fo`^9Dc@#oqwPC)WX*C@$S8*xmy$qu5iNr@9LmTm1llQ%F@8L^{y`b`(>Ka=+f{ z>&RLWDWs~a>BNJzX)0D`>ir79lDI{8h8{qKHO(K@T%d8GJvq&VR!a@*ddG`v8Q_}j z1v(K;uw0VZs2HC%)@}HX=rI6X{UV4GFKU07x>o?uI-edwYV!)`f^BnjY#h#-TvTbJ zx}eHJO4xHg2`U*dK*40b?@Akcw9rhz&Ie3UqDHUNOSGk|KbHE01` z6xZ(8>M8&*^foZcUFg2le+fX#rCtRtAS4m0b+10lg2D!|1=p%X!H zp7!U_(H|-L(@@#Z?<5M(IzxCM6@Ql~E&z;n`|lFPIzX2oG{D_N;lfHHcu`!MC4#pB vXe%5hg0}(uED^j8FiQmQ1N^M~2ly2OOhml(hOb2d00000NkvXXu0mjfPkoxi delta 1431 zcmV;I1!($^42BGlZ~=jlaTR}C1yR6jvPsW$rkp)Vyexd8pc`YdSSjB2WxL+*Nceor zTL6o8EdK)lXSgNjQvhe|aYtH$n*dks$FF392LV{6DB<&`+?aU+=uY5y2jD~ZPJvey z&fvhl=?D^3fQ11oYRWx0w-x9<8B!df1E9UiXj zw*W?q%&NusB)~2C3cy*GXN(^BAl9Cog7n>zX&FGh3uB!s1~ARl=Lo=6Kn2i=zmF&= zfRw9$4V(}ypECet9|A}ZXaWLAnTi3#_0<@nbOba3HDMaThSe10XGL%UproN70LU|| zMJOj?3E=JmT$Le!n*e{f=K#Wa3&8aN?wxqta{x}t>H5;t+aL8n$ubWBqyRn75|vo? z)bTvE0&HI;poEe7p8?A;_cr=-B3hER011Ddf}=*MhmDulL%(|f9=<)19f0!-4|qE# zuu4xCApC|y>1}|X)Lm|&Cj;330PjRW51?+#65xI!a->KdIJAG%6Hr=oHh=Ih0?dPH zAq-$F3xL7ciVS=Wee(9&{|Q#?pB%t80PSA;Tl}<5)Z;!ip-iWWc|ePSLy!1x0H7Xl z@qzUTbb2ZdQet!Q;OG$a>Mc0{}h+ zLx8MsP)2~@Lj!-%TXc3Z;_mA{P&|DhIBd8K&>La2AOGS2@sh5}*&Yfoe7s=)lz+!A zr_U}xfRWNw%{CZJE!Jn-9zJ~!tm3`}09`QnGCsB3atHF0_vw_9rXZ--ilfXo2SB6g zmCy(vcgSvlcBs{F$Ascm<^cN2t*1(w`vQ=rKwHRP(*S>g-l>cMl8e2s&vFq4j27$# z-+-b9$QmvJq?d8t!y9`3EEXZw;{|&`(VOz(esa!--v{w`uM}z=)py<)g2+^9&{L}) z8gK}D2td}F?DOT0`kDuDK@5Lrl+EQY0CWimU}9)guT}M@mjm>K)qgkFJ07?Ra22fa zfPV>KGzEXk17dEvQ`T2h&UD>_@L)Jy53n)r5I+vE9O};l^koH*+N6e347`nRM)y6y z&-nxpdrE>(6^5$)ktqnF#y|yNCMAG)-0(m@p5=(^q$>b)He4AJ+_32x53oh2)&NXI z$X8olF}pHHqazvf7W4yss1X!aSC)a*(K$ZQg=~KSr2jGoORk#%L;_y(3;@5D!;KcEbF8^kjkLD_ zeAFAR+m)4eIR)s$Hj91_(9w=X(=Hy7DIWw-+H+u;wxe1%JOHlRrr53Dt|k1l9RL-@ z-vEE`Z|(!AD9+s}*xm!^MzN(h4{USTU8FUIRCSJ}6A93dVrmiYms@=unHH8ps=As^ zELdBnVqvB}?*MFx*>tCC0a#em{87yX8q=Jd)D5QVa+Vd`E1K7I0dcPJ|27sY= zfYH*0o^$<|0JL1{l>y}HXz)1bIX>m*^l;n+a3!0ST@TL$D)ni(nsAslo(O_*Dl&f^ zoma@v^8mt}VFAl_@2Yzgqu&5jy%E3#7OHix7UyZ#IgC_*i-|%e0%t7k&!eM1QnaU` zyr17m6t?Je?txVNU81-EFxu_EOBDM6O@fdBcN2wiJBi>$F=3Sm-UgtpaF__*2C%C{ l@H)UM5xfuZv+^I{5A?RX#aAHMga8Ww002ovPDHLkV1i{yoqYfR From 691b1879f89de6561dd486b29b5b55cae0933eef Mon Sep 17 00:00:00 2001 From: LOuroboros Date: Sun, 4 Feb 2024 09:04:55 -0300 Subject: [PATCH 14/25] Renamed VAR_TERRAIN to B_VAR_TERRAIN and added a var-based field terrain timer (#4132) * Renamed VAR_TERRAIN and introduced a var-based field terrains timer * Fixed sky battle configs alignment and syntax * Added B_VAR_TERRAIN_TIMER handling to Overworld_ResetBattleFlagsAndVars * Removed pointless edits to EndTurnTerrain * Updated B_VAR_TERRAIN_TIMER's comment * Updated the syntax of ABILITYEFFECT_SWITCH_IN_TERRAIN to comply with Agbcc * Nuked pointless VarGet calls in the case ABILITYEFFECT_SWITCH_IN_TERRAIN of AbilityBattleEffects * Reverted changes made to BS_SetRemoveTerrain I shouldn't have touched it at all since it's not involved with B_VAR_TERRAIN functionality. * Removed trailing spaces in the case ABILITYEFFECT_SWITCH_IN_TERRAIN of AbilityBattleEffects --- include/config/battle.h | 12 ++--- src/battle_util.c | 111 +++++++++++++++++++++++++--------------- src/overworld.c | 10 ++-- 3 files changed, 83 insertions(+), 50 deletions(-) diff --git a/include/config/battle.h b/include/config/battle.h index 49b0c5a073..163e4c0f08 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -179,15 +179,15 @@ // Var Settings // To use the following features in scripting, replace the 0s with the var ID you're assigning it to. -// Eg: Replace with VAR_UNUSED_0x40F7 so you can use VAR_TERRAIN for that feature. -#define VAR_TERRAIN 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 +// Eg: Replace with VAR_UNUSED_0x40F7 so you can use B_VAR_TERRAIN for that feature. +#define B_VAR_TERRAIN 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_TERRAIN_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) // 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. -#define B_VAR_SKY_BATTLE 0 // If this var has a value, the game will remember the positions of Pokémon used in Sky Battles. - -#define B_SKY_BATTLE_STRICT_ELIGIBILITY FALSE //If TRUE, Sky Battles will use the eligibility from Pokémon XY. If FALSE, all Flying-types or Pokémon with Levitate are allowed. +#define B_FLAG_SKY_BATTLE 0 // If this flag has a value, the player will be able to engage in scripted Sky Battles. +#define B_VAR_SKY_BATTLE 0 // If this var has a value, the game will remember the positions of Pokémon used in Sky Battles. +#define B_SKY_BATTLE_STRICT_ELIGIBILITY FALSE // If TRUE, Sky Battles will use the eligibility from Pokémon XY. If FALSE, all Flying-types or Pokémon with Levitate are allowed. // Flag and Var settings #define B_RESET_FLAGS_VARS_AFTER_WHITEOUT TRUE // If TRUE, Overworld_ResetBattleFlagsAndVars will reset battle-related Flags and Vars when the player whites out. diff --git a/src/battle_util.c b/src/battle_util.c index d2d5c50925..735b286e24 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4016,50 +4016,79 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 switch (caseID) { case ABILITYEFFECT_SWITCH_IN_TERRAIN: - gBattleScripting.battler = battler; - if (VarGet(VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY) { - u16 terrainFlags = VarGet(VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY; // only works for status flag (1 << 15) - gFieldStatuses = terrainFlags | STATUS_FIELD_TERRAIN_PERMANENT; // terrain is permanent - switch (VarGet(VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY) - { - case STATUS_FIELD_ELECTRIC_TERRAIN: - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; - break; - case STATUS_FIELD_MISTY_TERRAIN: - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; - break; - case STATUS_FIELD_GRASSY_TERRAIN: - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_GRASSY; - break; - case STATUS_FIELD_PSYCHIC_TERRAIN: - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; - break; - } + u8 varTerrainTimer = VarGet(B_VAR_TERRAIN_TIMER); - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; + gBattleScripting.battler = battler; + if (VarGet(B_VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY) + { + u16 terrainFlags = VarGet(B_VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY; // only works for status flag (1 << 15) + + if (varTerrainTimer == 0) + { + gFieldStatuses = terrainFlags | STATUS_FIELD_TERRAIN_PERMANENT; // terrain is permanent + } + else + { + gFieldStatuses |= terrainFlags; + gFieldTimers.terrainTimer = varTerrainTimer; + } + + switch (VarGet(B_VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY) + { + case STATUS_FIELD_ELECTRIC_TERRAIN: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; + break; + case STATUS_FIELD_MISTY_TERRAIN: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; + break; + case STATUS_FIELD_GRASSY_TERRAIN: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_GRASSY; + break; + case STATUS_FIELD_PSYCHIC_TERRAIN: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_PSYCHIC; + break; + } + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect++; + } + else if (B_THUNDERSTORM_TERRAIN == TRUE + && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM + && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)) + { + // overworld weather started rain, so just do electric terrain anim + if (varTerrainTimer == 0) + { + gFieldStatuses = (STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); + } + else + { + gFieldStatuses |= STATUS_FIELD_ELECTRIC_TERRAIN; + gFieldTimers.terrainTimer = varTerrainTimer; + } + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect++; + } + else if (B_FOG_TERRAIN == TRUE + && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) + && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) + { + if (varTerrainTimer == 0) + { + gFieldStatuses = (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); + } + else + { + gFieldStatuses |= STATUS_FIELD_ELECTRIC_TERRAIN; + gFieldTimers.terrainTimer = varTerrainTimer; + } + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; + BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); + effect++; + } } - else if (B_THUNDERSTORM_TERRAIN == TRUE - && GetCurrentWeather() == WEATHER_RAIN_THUNDERSTORM - && !(gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)) - { - // overworld weather started rain, so just do electric terrain anim - gFieldStatuses = (STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_ELECTRIC; - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; - } - else if (B_FOG_TERRAIN == TRUE - && (GetCurrentWeather() == WEATHER_FOG_HORIZONTAL || GetCurrentWeather() == WEATHER_FOG_DIAGONAL) - && !(gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)) - { - gFieldStatuses = (STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_TERRAIN_PERMANENT); - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_TERRAIN_SET_MISTY; - BattleScriptPushCursorAndCallback(BattleScript_OverworldTerrain); - effect++; - } - break; + break; case ABILITYEFFECT_SWITCH_IN_WEATHER: gBattleScripting.battler = battler; if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED)) diff --git a/src/overworld.c b/src/overworld.c index e18ae583c4..e4161a32f6 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -399,10 +399,14 @@ void Overworld_ResetStateAfterDigEscRope(void) } #if B_RESET_FLAGS_VARS_AFTER_WHITEOUT == TRUE - void Overworld_ResetBattleFlagsAndVars(void) +void Overworld_ResetBattleFlagsAndVars(void) { - #if VAR_TERRAIN != 0 - VarSet(VAR_TERRAIN, 0); + #if B_VAR_TERRAIN != 0 + VarSet(B_VAR_TERRAIN, 0); + #endif + + #if B_VAR_TERRAIN_TIMER != 0 + VarSet(B_VAR_TERRAIN_TIMER, 0); #endif #if B_VAR_WILD_AI_FLAGS != 0 From 512ab98bfe27da2d7f3f4487c978f096f69f031b Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 4 Feb 2024 16:13:27 +0100 Subject: [PATCH 15/25] Fix disobedience not resetting multihit moves (#4133) --- src/battle_util.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/battle_util.c b/src/battle_util.c index 167d5bf599..856289d1f1 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3842,6 +3842,10 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) gBattleStruct->beatUpSlot = 0; PREPARE_BYTE_NUMBER_BUFFER(gBattleScripting.multihitString, 1, 0) } + else + { + gMultiHitCounter = 0; + } gBattleStruct->atkCancellerTracker++; break; case CANCELLER_END: @@ -8222,6 +8226,7 @@ u8 IsMonDisobedient(void) } while (gBitTable[gCurrMovePos] & calc); gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + SetAtkCancellerForCalledMove(); gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; gBattlerTarget = GetMoveTarget(gCalledMove, NO_TARGET_OVERRIDE); gHitMarker |= HITMARKER_DISOBEDIENT_MOVE; From 7ae50ea507a10ff99b269313064540019ad59004 Mon Sep 17 00:00:00 2001 From: Nephrite Date: Mon, 5 Feb 2024 04:28:27 +0900 Subject: [PATCH 16/25] Metaprogram (#3968) * metaprogram.h Created by Mr. Griffin. Removed non-relevant parts * Added DEFAULT/DEFAULT_2 macros Also added a demonstration in battle_main * Removed GET_ARGS * Expanded DEFAULT Because why not? * Added EXCEPT Expands to everything but the first x arguments. * Added BIT_INDEX (thanks to MGriffin) and COMPRESS_BIT macros These let you compress a bit up to a word in size inside a single byte and uncompress at the same time. BIT_INDEX just tells you where the bit is. * Updated HANDLE_EXPANDED_MOVE_NAME --------- Co-authored-by: Martin Griffin --- include/global.h | 14 +---- include/metaprogram.h | 131 ++++++++++++++++++++++++++++++++++++++++++ src/battle_main.c | 126 ++++++++++++++++++++-------------------- src/data/moves_info.h | 3 +- 4 files changed, 195 insertions(+), 79 deletions(-) create mode 100644 include/metaprogram.h diff --git a/include/global.h b/include/global.h index e9756df212..49095a5cd9 100644 --- a/include/global.h +++ b/include/global.h @@ -6,6 +6,7 @@ #include "config.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines. #include "gba/gba.h" #include "fpmath.h" +#include "metaprogram.h" #include "constants/global.h" #include "constants/flags.h" #include "constants/vars.h" @@ -123,19 +124,6 @@ #define NUM_FLAG_BYTES ROUND_BITS_TO_BYTES(FLAGS_COUNT) #define NUM_TRENDY_SAYING_BYTES ROUND_BITS_TO_BYTES(NUM_TRENDY_SAYINGS) -// Calls m0/m1/.../m8 depending on how many arguments are passed. -#define VARARG_8(m, ...) CAT(m, NARG_8(__VA_ARGS__))(__VA_ARGS__) - -// This returns the number of arguments passed to it (up to 8). -#define NARG_8(...) NARG_8_(_, ##__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0) -#define NARG_8_(_, a, b, c, d, e, f, g, h, N, ...) N - -#define CAT(a, b) CAT_(a, b) -#define CAT_(a, b) a ## b - -#define STR(...) STR_(__VA_ARGS__) -#define STR_(...) #__VA_ARGS__ - // Converts a string to a compound literal, essentially making it a pointer to const u8 #define COMPOUND_STRING(str) (const u8[]) _(str) diff --git a/include/metaprogram.h b/include/metaprogram.h new file mode 100644 index 0000000000..f0d6d9a81f --- /dev/null +++ b/include/metaprogram.h @@ -0,0 +1,131 @@ +/* Macros to aid with metaprogramming. */ +#ifndef METAPROGRAM_H +#define METAPROGRAM_H + +/* Calls m0/m1/.../m8 depending on how many arguments are passed. */ +#define VARARG_8(m, ...) CAT(m, NARG_8(__VA_ARGS__))(__VA_ARGS__) + +/* Returns the number of arguments passed to it (up to 8). */ +#define NARG_8(...) NARG_8_(_, ##__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0) +#define NARG_8_(_, a, b, c, d, e, f, g, h, N, ...) N + +/* Expands 'a' and 'b' and then concatenates them. */ +#define CAT(a, b) CAT_(a, b) +#define CAT_(a, b) a ## b + +/* Expands '__VA_ARGS__' and then stringizes them. */ +#define STR(...) STR_(__VA_ARGS__) +#define STR_(...) #__VA_ARGS__ + +/* Expands to the first/second/third/fourth argument. */ +#define FIRST(a, ...) a +#define SECOND(a, ...) __VA_OPT__(FIRST(__VA_ARGS__)) +#define THIRD(a, ...) __VA_OPT__(SECOND(__VA_ARGS__)) +#define FOURTH(a, ...) __VA_OPT__(THIRD(__VA_ARGS__)) + +/* Expands to everything but the first x arguments */ +#define EXCEPT_1(a, ...) __VA_OPT__(__VA_ARGS__) +#define EXCEPT_2(a, ...) __VA_OPT__(EXCEPT_1(__VA_ARGS__)) +#define EXCEPT_3(a, ...) __VA_OPT__(EXCEPT_2(__VA_ARGS__)) +#define EXCEPT_4(a, ...) __VA_OPT__(EXCEPT_3(__VA_ARGS__)) + +/* 'UNPACK (x, y, z)' expands to 'x, y, z'. + * Useful for passing arguments which may contain commas into a macro. */ +#define UNPACK(...) __VA_ARGS__ + +/* Expands to 'macro(...args, ...)'. */ +#define INVOKE_WITH(macro, args, ...) INVOKE_WITH_(macro, UNPACK args __VA_OPT__(, __VA_ARGS__)) +#define INVOKE_WITH_(macro, ...) macro(__VA_ARGS__) + +/* Recursive macros. + * Based on https://www.scs.stanford.edu/~dm/blog/va-opt.html + * + * Macros prefixed with R_ are recursive, to correctly expand them the + * top-level macro which references them should use 'RECURSIVELY' around + * them. 'RECURSIVELY' cannot be nested, hence the top-level macro must + * use it so that a recursive macro is able to reference another + * recursive macro. */ + +#define RECURSIVELY(...) RECURSIVELY_4(RECURSIVELY_4(RECURSIVELY_4(RECURSIVELY_4(__VA_ARGS__)))) +#define RECURSIVELY_4(...) RECURSIVELY_3(RECURSIVELY_3(RECURSIVELY_3(RECURSIVELY_3(__VA_ARGS__)))) +#define RECURSIVELY_3(...) RECURSIVELY_2(RECURSIVELY_2(RECURSIVELY_2(RECURSIVELY_2(__VA_ARGS__)))) +#define RECURSIVELY_2(...) RECURSIVELY_1(RECURSIVELY_1(RECURSIVELY_1(RECURSIVELY_1(__VA_ARGS__)))) +#define RECURSIVELY_1(...) __VA_ARGS__ + +/* Useful for deferring expansion until the second scan. See + * https://www.scs.stanford.edu/~dm/blog/va-opt.html for more info. */ +#define PARENS () + +/* Expands to 'macro(a)' for each 'a' in '...' */ +#define R_FOR_EACH(macro, ...) __VA_OPT__(R_FOR_EACH_(macro, __VA_ARGS__)) +#define R_FOR_EACH_(macro, a, ...) macro(a) __VA_OPT__(R_FOR_EACH_P PARENS (macro, __VA_ARGS__)) +#define R_FOR_EACH_P() R_FOR_EACH_ + +/* Expands to 'macro(...args, a)' for each 'a' in '...'. */ +#define R_FOR_EACH_WITH(macro, args, ...) __VA_OPT__(R_FOR_EACH_WITH_(macro, args, __VA_ARGS__)) +#define R_FOR_EACH_WITH_(macro, args, a, ...) INVOKE_WITH(macro, args, a) __VA_OPT__(R_FOR_EACH_WITH_P PARENS (macro, args, __VA_ARGS__)) +#define R_FOR_EACH_WITH_P() R_FOR_EACH_WITH_ + +/* Picks the xth VA_ARG if it exists, otherwise returns a default value */ +#define DEFAULT(_default, ...) FIRST(__VA_OPT__(__VA_ARGS__, ) _default) +#define DEFAULT_2(_default, ...) DEFAULT(_default __VA_OPT__(, SECOND(__VA_ARGS__))) +#define DEFAULT_3(_default, ...) DEFAULT(_default __VA_OPT__(, THIRD(__VA_ARGS__))) +#define DEFAULT_4(_default, ...) DEFAULT(_default __VA_OPT__(, FOURTH(__VA_ARGS__))) + +/* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word. +Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */ +#define BIT_INDEX(n) \ + (n) == (1 << 0) ? 0 : \ + (n) == (1 << 1) ? 1 : \ + (n) == (1 << 2) ? 2 : \ + (n) == (1 << 3) ? 3 : \ + (n) == (1 << 4) ? 4 : \ + (n) == (1 << 5) ? 5 : \ + (n) == (1 << 6) ? 6 : \ + (n) == (1 << 7) ? 7 : \ + (n) == (1 << 8) ? 8 : \ + (n) == (1 << 9) ? 9 : \ + (n) == (1 << 10) ? 10 : \ + (n) == (1 << 11) ? 11 : \ + (n) == (1 << 12) ? 12 : \ + (n) == (1 << 13) ? 13 : \ + (n) == (1 << 14) ? 14 : \ + (n) == (1 << 15) ? 15 : \ + (n) == (1 << 16) ? 16 : \ + (n) == (1 << 17) ? 17 : \ + (n) == (1 << 18) ? 18 : \ + (n) == (1 << 19) ? 19 : \ + (n) == (1 << 20) ? 20 : \ + (n) == (1 << 21) ? 21 : \ + (n) == (1 << 22) ? 22 : \ + (n) == (1 << 23) ? 23 : \ + (n) == (1 << 24) ? 24 : \ + (n) == (1 << 25) ? 25 : \ + (n) == (1 << 26) ? 26 : \ + (n) == (1 << 27) ? 27 : \ + (n) == (1 << 28) ? 28 : \ + (n) == (1 << 29) ? 29 : \ + (n) == (1 << 30) ? 30 : \ + (n) == (1 << 31) ? 31 : \ + *(u32 *)NULL + +#define COMPRESS_BITS_0 0, 1 +#define COMPRESS_BITS_1 1, 1 +#define COMPRESS_BITS_2 2, 1 +#define COMPRESS_BITS_3 3, 1 +#define COMPRESS_BITS_4 4, 1 +#define COMPRESS_BITS_5 5, 1 +#define COMPRESS_BITS_6 6, 1 +#define COMPRESS_BITS_7 7, 1 + +/* Will try and compress a set bit (or up to three sequential bits) into a single byte +Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */ +#define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val +#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked) +#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__) +#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower))) + +/* Will read a compressed bit stored by COMPRESS_BIT into a single byte */ +#define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F)) + +#endif diff --git a/src/battle_main.c b/src/battle_main.c index e4c5c7a784..1764f3d6a5 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -322,85 +322,83 @@ const u8 gTypeNames[NUMBER_OF_MON_TYPES][TYPE_NAME_LENGTH + 1] = [TYPE_FAIRY] = _("Fairy"), }; -#define DEFAULT_MONEY 5 -#define DEFAULT_BALL ITEM_POKE_BALL - -#define TRAINER_CLASS(trainerClass, trainerName, trainerMoney, trainerBall) \ - [TRAINER_CLASS_##trainerClass] = \ - { \ - .name = _(trainerName), \ - .money = trainerMoney, \ - .ball = trainerBall, \ +// extra args are money and ball +#define TRAINER_CLASS(trainerClass, trainerName, ...) \ + [TRAINER_CLASS_##trainerClass] = \ + { \ + .name = _(trainerName), \ + .money = DEFAULT(5, __VA_ARGS__), \ + .ball = DEFAULT_2(ITEM_POKE_BALL, __VA_ARGS__), \ } const struct TrainerClass gTrainerClasses[TRAINER_CLASS_COUNT] = { - TRAINER_CLASS(PKMN_TRAINER_1, "{PKMN} TRAINER", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PKMN_TRAINER_2, "{PKMN} TRAINER", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(HIKER, "HIKER", 10, DEFAULT_BALL), - TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA", 5, DEFAULT_BALL), + TRAINER_CLASS(PKMN_TRAINER_1, "{PKMN} TRAINER"), + TRAINER_CLASS(PKMN_TRAINER_2, "{PKMN} TRAINER"), + TRAINER_CLASS(HIKER, "HIKER", 10), + TRAINER_CLASS(TEAM_AQUA, "TEAM AQUA"), TRAINER_CLASS(PKMN_BREEDER, "{PKMN} BREEDER", 10, B_TRAINER_CLASS_POKE_BALLS >= GEN_8 ? ITEM_HEAL_BALL : ITEM_FRIEND_BALL), TRAINER_CLASS(COOLTRAINER, "COOLTRAINER", 12, ITEM_ULTRA_BALL), - TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER", 8, DEFAULT_BALL), + TRAINER_CLASS(BIRD_KEEPER, "BIRD KEEPER", 8), TRAINER_CLASS(COLLECTOR, "COLLECTOR", 15, ITEM_PREMIER_BALL), TRAINER_CLASS(SWIMMER_M, "SWIMMER♂", 2, ITEM_DIVE_BALL), - TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA", 5, DEFAULT_BALL), - TRAINER_CLASS(EXPERT, "EXPERT", 10, DEFAULT_BALL), - TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN", 10, DEFAULT_BALL), + TRAINER_CLASS(TEAM_MAGMA, "TEAM MAGMA"), + TRAINER_CLASS(EXPERT, "EXPERT", 10), + TRAINER_CLASS(AQUA_ADMIN, "AQUA ADMIN", 10), TRAINER_CLASS(BLACK_BELT, "BLACK BELT", 8, ITEM_ULTRA_BALL), TRAINER_CLASS(AQUA_LEADER, "AQUA LEADER", 20, ITEM_MASTER_BALL), - TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC", 6, DEFAULT_BALL), - TRAINER_CLASS(AROMA_LADY, "AROMA LADY", 10, DEFAULT_BALL), - TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC", 15, DEFAULT_BALL), - TRAINER_CLASS(INTERVIEWER, "INTERVIEWER", 12, DEFAULT_BALL), - TRAINER_CLASS(TUBER_F, "TUBER", 1, DEFAULT_BALL), - TRAINER_CLASS(TUBER_M, "TUBER", 1, DEFAULT_BALL), - TRAINER_CLASS(LADY, "LADY", 50, DEFAULT_BALL), - TRAINER_CLASS(BEAUTY, "BEAUTY", 20, DEFAULT_BALL), - TRAINER_CLASS(RICH_BOY, "RICH BOY", 50, DEFAULT_BALL), - TRAINER_CLASS(POKEMANIAC, "POKéMANIAC", 15, DEFAULT_BALL), - TRAINER_CLASS(GUITARIST, "GUITARIST", 8, DEFAULT_BALL), - TRAINER_CLASS(KINDLER, "KINDLER", 8, DEFAULT_BALL), - TRAINER_CLASS(CAMPER, "CAMPER", 4, DEFAULT_BALL), - TRAINER_CLASS(PICNICKER, "PICNICKER", 4, DEFAULT_BALL), - TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC", 15, DEFAULT_BALL), - TRAINER_CLASS(PSYCHIC, "PSYCHIC", 6, DEFAULT_BALL), + TRAINER_CLASS(HEX_MANIAC, "HEX MANIAC", 6), + TRAINER_CLASS(AROMA_LADY, "AROMA LADY", 10), + TRAINER_CLASS(RUIN_MANIAC, "RUIN MANIAC", 15), + TRAINER_CLASS(INTERVIEWER, "INTERVIEWER", 12), + TRAINER_CLASS(TUBER_F, "TUBER", 1), + TRAINER_CLASS(TUBER_M, "TUBER", 1), + TRAINER_CLASS(LADY, "LADY", 50), + TRAINER_CLASS(BEAUTY, "BEAUTY", 20), + TRAINER_CLASS(RICH_BOY, "RICH BOY", 50), + TRAINER_CLASS(POKEMANIAC, "POKéMANIAC", 15), + TRAINER_CLASS(GUITARIST, "GUITARIST", 8), + TRAINER_CLASS(KINDLER, "KINDLER", 8), + TRAINER_CLASS(CAMPER, "CAMPER", 4), + TRAINER_CLASS(PICNICKER, "PICNICKER", 4), + TRAINER_CLASS(BUG_MANIAC, "BUG MANIAC", 15), + TRAINER_CLASS(PSYCHIC, "PSYCHIC", 6), TRAINER_CLASS(GENTLEMAN, "GENTLEMAN", 20, ITEM_LUXURY_BALL), TRAINER_CLASS(ELITE_FOUR, "ELITE FOUR", 25, ITEM_ULTRA_BALL), - TRAINER_CLASS(LEADER, "LEADER", 25, DEFAULT_BALL), - TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID", 5, DEFAULT_BALL), - TRAINER_CLASS(SR_AND_JR, "SR. AND JR.", 4, DEFAULT_BALL), - TRAINER_CLASS(WINSTRATE, "WINSTRATE", 10, DEFAULT_BALL), - TRAINER_CLASS(POKEFAN, "POKéFAN", 20, DEFAULT_BALL), - TRAINER_CLASS(YOUNGSTER, "YOUNGSTER", 4, DEFAULT_BALL), - TRAINER_CLASS(CHAMPION, "CHAMPION", 50, DEFAULT_BALL), + TRAINER_CLASS(LEADER, "LEADER", 25), + TRAINER_CLASS(SCHOOL_KID, "SCHOOL KID"), + TRAINER_CLASS(SR_AND_JR, "SR. AND JR.", 4), + TRAINER_CLASS(WINSTRATE, "WINSTRATE", 10), + TRAINER_CLASS(POKEFAN, "POKéFAN", 20), + TRAINER_CLASS(YOUNGSTER, "YOUNGSTER", 4), + TRAINER_CLASS(CHAMPION, "CHAMPION", 50), TRAINER_CLASS(FISHERMAN, "FISHERMAN", 10, B_TRAINER_CLASS_POKE_BALLS >= GEN_8 ? ITEM_DIVE_BALL : ITEM_LURE_BALL), - TRAINER_CLASS(TRIATHLETE, "TRIATHLETE", 10, DEFAULT_BALL), - TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER", 12, DEFAULT_BALL), - TRAINER_CLASS(NINJA_BOY, "NINJA BOY", 3, DEFAULT_BALL), - TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL", 6, DEFAULT_BALL), - TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY", 10, DEFAULT_BALL), + TRAINER_CLASS(TRIATHLETE, "TRIATHLETE", 10), + TRAINER_CLASS(DRAGON_TAMER, "DRAGON TAMER", 12), + TRAINER_CLASS(NINJA_BOY, "NINJA BOY", 3), + TRAINER_CLASS(BATTLE_GIRL, "BATTLE GIRL", 6), + TRAINER_CLASS(PARASOL_LADY, "PARASOL LADY", 10), TRAINER_CLASS(SWIMMER_F, "SWIMMER♀", 2, ITEM_DIVE_BALL), - TRAINER_CLASS(TWINS, "TWINS", 3, DEFAULT_BALL), - TRAINER_CLASS(SAILOR, "SAILOR", 8, DEFAULT_BALL), - TRAINER_CLASS(COOLTRAINER_2, "COOLTRAINER", DEFAULT_MONEY, ITEM_ULTRA_BALL), - TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN", 10, DEFAULT_BALL), - TRAINER_CLASS(RIVAL, "{PKMN} TRAINER", 15, DEFAULT_BALL), - TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER", 4, DEFAULT_BALL), - TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER", 12, DEFAULT_BALL), + TRAINER_CLASS(TWINS, "TWINS", 3), + TRAINER_CLASS(SAILOR, "SAILOR", 8), + TRAINER_CLASS(COOLTRAINER_2, "COOLTRAINER", 5, ITEM_ULTRA_BALL), + TRAINER_CLASS(MAGMA_ADMIN, "MAGMA ADMIN", 10), + TRAINER_CLASS(RIVAL, "{PKMN} TRAINER", 15), + TRAINER_CLASS(BUG_CATCHER, "BUG CATCHER", 4), + TRAINER_CLASS(PKMN_RANGER, "{PKMN} RANGER", 12), TRAINER_CLASS(MAGMA_LEADER, "MAGMA LEADER", 20, ITEM_MASTER_BALL), - TRAINER_CLASS(LASS, "LASS", 4, DEFAULT_BALL), - TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE", 8, DEFAULT_BALL), - TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE", 10, DEFAULT_BALL), - TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO", 3, DEFAULT_BALL), - TRAINER_CLASS(SALON_MAIDEN, "SALON MAIDEN", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(DOME_ACE, "DOME ACE", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PALACE_MAVEN, "PALACE MAVEN", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(ARENA_TYCOON, "ARENA TYCOON", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(FACTORY_HEAD, "FACTORY HEAD", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PIKE_QUEEN, "PIKE QUEEN", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(PYRAMID_KING, "PYRAMID KING", DEFAULT_MONEY, DEFAULT_BALL), - TRAINER_CLASS(RS_PROTAG, "{PKMN} TRAINER", DEFAULT_MONEY, DEFAULT_BALL), + TRAINER_CLASS(LASS, "LASS", 4), + TRAINER_CLASS(YOUNG_COUPLE, "YOUNG COUPLE", 8), + TRAINER_CLASS(OLD_COUPLE, "OLD COUPLE", 10), + TRAINER_CLASS(SIS_AND_BRO, "SIS AND BRO", 3), + TRAINER_CLASS(SALON_MAIDEN, "SALON MAIDEN"), + TRAINER_CLASS(DOME_ACE, "DOME ACE"), + TRAINER_CLASS(PALACE_MAVEN, "PALACE MAVEN"), + TRAINER_CLASS(ARENA_TYCOON, "ARENA TYCOON"), + TRAINER_CLASS(FACTORY_HEAD, "FACTORY HEAD"), + TRAINER_CLASS(PIKE_QUEEN, "PIKE QUEEN"), + TRAINER_CLASS(PYRAMID_KING, "PYRAMID KING"), + TRAINER_CLASS(RS_PROTAG, "{PKMN} TRAINER"), }; static void (* const sTurnActionsFuncsTable[])(void) = diff --git a/src/data/moves_info.h b/src/data/moves_info.h index b68aecb319..10cda85a43 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -9,9 +9,8 @@ // The Gen. 4+ contest data comes from urpg's contest movedex. -#define FIRST(a, ...) a #if B_EXPANDED_MOVE_NAMES == TRUE -#define HANDLE_EXPANDED_MOVE_NAME(_name, ...) COMPOUND_STRING(FIRST(__VA_OPT__(__VA_ARGS__, ) _name)) +#define HANDLE_EXPANDED_MOVE_NAME(_name, ...) COMPOUND_STRING(DEFAULT(_name, __VA_ARGS__)) #else #define HANDLE_EXPANDED_MOVE_NAME(_name, ...) COMPOUND_STRING(_name) #endif From 65c508d1937514e6faf1ada022b0b317af141cf1 Mon Sep 17 00:00:00 2001 From: Nephrite Date: Mon, 5 Feb 2024 07:02:59 +0900 Subject: [PATCH 17/25] Secondary effects overhaul minor follow-up (#4062) * settwoturnstring command * Unified two-turn attacks and Meteor Beam To do: Solar Beam * Solar Beam Also fixed various function, removed EFFECT_GUST (who knows why that exists?) * Updated Solar Beam + tests * Redid two turn move + animations logic Removed pointless various function; to do: remove Skull Bash, fix AI test * Removed now-pointless flag * Removed Skull Bash And temporarily commented out failing AI tests * Removed Sky Uppercut effect Not sure when or why this was ever necessary * Removed BattleScript_EffectSemiInvulnerable Now uses BattleScript_EffectTwoTurnsAttack. Kept the effect; used the argument field to determine which STATUS3 such moves should apply but added a function to jump over weather checks in BattleScript_EffectTwoTurnsAttack if the current move is semi-invulnerable (since the instant-fire weather check and STATUS3 use the same field) * Applied review changes * Replaced VARIOUS with callnative Tried to fix test but couldn't :/ wtf is going on * Fixed one AI test Cant fix the other... * Added KNOWN_FAILING to failing AI tests Separated them out into their own test * Optimised script, overhauled charge turn string setting Condensed multiple confusing macros into one, jumpifweathercheckchargeeffects. Script now tweaked and trimmed, string ids for charge turns now added to argument along with status3 (thanks to compression macro) and instant-fire-weather for semi-invulnerable and two-turn moves respectively. Also introduced a savedStringId in gBattleScripting to make string selection work. * Unified two turn move tests + minor corrections * Added semi-invulnerable move tests Set the Razor Wind test to known failing - something to do with its animation? --------- Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- asm/macros/battle_script.inc | 45 +- data/battle_scripts_1.s | 229 ++------- include/battle.h | 7 +- include/battle_ai_util.h | 2 +- include/battle_scripts.h | 1 - include/battle_util.h | 1 + include/constants/battle_move_effects.h | 4 - include/constants/battle_script_commands.h | 43 +- include/constants/battle_string_ids.h | 23 +- include/global.h | 56 +++ src/battle_ai_main.c | 12 +- src/battle_ai_util.c | 11 +- src/battle_message.c | 25 +- src/battle_script_commands.c | 91 ++-- src/battle_util.c | 12 +- src/data/battle_move_effects.h | 34 +- src/data/moves_info.h | 40 +- test/battle/ability/sheer_force.c | 3 +- test/battle/ai.c | 29 +- test/battle/move_effect/meteor_beam.c | 61 --- .../move_effect/semi_invulnerable_moves.c | 250 ++++++++++ test/battle/move_effect/solar_beam.c | 167 ------- test/battle/move_effect/two_turn_moves.c | 449 ++++++++++++++++++ 23 files changed, 1000 insertions(+), 595 deletions(-) delete mode 100644 test/battle/move_effect/meteor_beam.c create mode 100644 test/battle/move_effect/semi_invulnerable_moves.c delete mode 100644 test/battle/move_effect/solar_beam.c create mode 100644 test/battle/move_effect/two_turn_moves.c diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 80e498d2b0..b3a5c77716 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -72,6 +72,10 @@ .2byte \id .endm + .macro printsavedstring + printstring 0 + .endm + .macro printselectionstring id:req .byte 0x11 .2byte \id @@ -776,8 +780,21 @@ .byte 0x8b .endm - .macro unused0x8C + .macro twoturnmoveschargestringandanimation .byte 0x8c + .4byte 1f @animation then attack string + @default - attack string then animation + printsavedstring + waitmessage B_WAIT_TIME_LONG + attackanimation + waitanimation + goto 2f + 1: + attackanimation + waitanimation + printsavedstring + waitmessage B_WAIT_TIME_LONG + 2: .endm .macro setmultihitcounter value:req @@ -1035,12 +1052,20 @@ .4byte \failInstr .endm - .macro setsemiinvulnerablebit + .macro setsemiinvulnerablebit clear=FALSE .byte 0xc5 + .byte \clear .endm .macro clearsemiinvulnerablebit + setsemiinvulnerablebit TRUE + .endm + + .macro jumpifweathercheckchargeeffects battler:req, checkChargeTurnEffects:req, jumpInstr:req .byte 0xc6 + .byte \battler + .byte \checkChargeTurnEffects + .4byte \jumpInstr .endm .macro setminimize @@ -1337,13 +1362,6 @@ .4byte \jumpInstr .endm - .macro jumpifholdeffect battler:req, holdEffect:req, jumpInstr:req - callnative BS_JumpIfHoldEffect - .byte \battler - .2byte \holdEffect - .4byte \jumpInstr - .endm - .macro dostockpilestatchangeswearoff, battler:req, statChangeInstr:req callnative BS_DoStockpileStatChangesWearOff .byte \battler @@ -2005,10 +2023,15 @@ .4byte \jumpInstr .endm - .macro jumpifnoholdeffect battler:req, holdEffect:req, jumpInstr:req - various \battler, VARIOUS_JUMP_IF_NO_HOLD_EFFECT + .macro jumpifholdeffect battler:req, holdEffect:req, jumpInstr:req, equal=TRUE + various \battler, VARIOUS_JUMP_IF_HOLD_EFFECT .byte \holdEffect .4byte \jumpInstr + .byte \equal + .endm + + .macro jumpifnoholdeffect battler:req, holdEffect:req, jumpInstr:req + jumpifholdeffect \battler, \holdEffect, \jumpInstr, FALSE .endm .macro infatuatewithbattler battler:req, infatuateWith:req diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index c814b85510..6798c0e8e8 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -585,46 +585,9 @@ BattleScript_BeakBlastBurn:: call BattleScript_MoveEffectBurn return -BattleScript_EffectMeteorBeam:: - @ DecideTurn - jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn - jumpifmove MOVE_METEOR_BEAM, BattleScript_SetStringMeteorBeam - jumpifmove MOVE_ELECTRO_SHOT, BattleScript_SetStringElectroShock -BattleScript_TryCharging: - call BattleScript_FirstChargingTurnMeteorBeam - jumpifmove MOVE_METEOR_BEAM, BattleScript_TryMeteorBeam - jumpifweatheraffected BS_ATTACKER, B_WEATHER_RAIN, BattleScript_TwoTurnMovesSecondTurn @ Check for move Electro Shot -BattleScript_TryMeteorBeam: - jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd - call BattleScript_PowerHerbActivation - goto BattleScript_TwoTurnMovesSecondTurn - -BattleScript_SetStringMeteorBeam: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_METEOR_BEAM - goto BattleScript_TryCharging - -BattleScript_SetStringElectroShock: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_ELECTRO_SHOCK - goto BattleScript_TryCharging - -BattleScript_FirstChargingTurnMeteorBeam:: - attackcanceler - flushtextbox - ppreduce - attackanimation - waitanimation - orword gHitMarker, HITMARKER_CHARGING - seteffectprimary MOVE_EFFECT_CHARGING | MOVE_EFFECT_AFFECTS_USER - copybyte cMULTISTRING_CHOOSER, sTWOTURN_STRINGID - printfromtable gFirstTurnOfTwoStringIds - waitmessage B_WAIT_TIME_LONG - setadditionaleffects @ only onChargeTurnOnly effects will work here - return - BattleScript_EffectSkyDrop:: - jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_SkyDropTurn2 attackcanceler + jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_SkyDropTurn2 ppreduce accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring @@ -638,16 +601,10 @@ BattleScript_EffectSkyDrop:: BattleScript_SkyDropWork: setskydrop - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_SKY_DROP - setsemiinvulnerablebit - call BattleScriptFirstChargingTurnAfterAttackString + call BattleScript_FirstChargingTurnAfterAttackString goto BattleScript_MoveEnd BattleScript_SkyDropTurn2: - attackcanceler - setbyte sB_ANIM_TURN, 0x1 - clearstatusfromeffect BS_ATTACKER, MOVE_EFFECT_CHARGING - orword gHitMarker, HITMARKER_NO_PPDEDUCT - clearsemiinvulnerablebit + call BattleScript_TwoTurnMovesSecondTurnRet attackstring clearskydrop BattleScript_SkyDropChangedTarget jumpiftype BS_TARGET, TYPE_FLYING, BattleScript_SkyDropFlyingType @@ -3485,29 +3442,6 @@ BattleScript_KOFail:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_TwoTurnMovesSecondTurn:: - attackcanceler - setbyte sB_ANIM_TURN, 1 - clearstatusfromeffect BS_ATTACKER, MOVE_EFFECT_CHARGING - orword gHitMarker, HITMARKER_NO_PPDEDUCT - goto BattleScript_HitFromAccCheck - -BattleScriptFirstChargingTurn:: - attackcanceler - flushtextbox - ppreduce - attackstring -BattleScriptFirstChargingTurnAfterAttackString: - pause B_WAIT_TIME_LONG - copybyte cMULTISTRING_CHOOSER, sTWOTURN_STRINGID - printfromtable gFirstTurnOfTwoStringIds - waitmessage B_WAIT_TIME_LONG - attackanimation - waitanimation - orword gHitMarker, HITMARKER_CHARGING - seteffectprimary MOVE_EFFECT_CHARGING | MOVE_EFFECT_AFFECTS_USER - return - BattleScript_EffectSuperFang:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE @@ -3784,34 +3718,16 @@ BattleScript_PowerHerbActivation: BattleScript_EffectTwoTurnsAttack:: jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn - jumpifmove MOVE_SKY_ATTACK, BattleScript_EffectTwoTurnsAttackSkyAttack - jumpifmove MOVE_RAZOR_WIND, BattleScript_EffectTwoTurnsAttackRazorWind - jumpifmove MOVE_ICE_BURN, BattleScript_EffectTwoTurnsAttackIceBurn - jumpifmove MOVE_FREEZE_SHOCK, BattleScript_EffectTwoTurnsAttackFreezeShock - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_RAZOR_WIND -BattleScript_EffectTwoTurnsAttackContinue: - call BattleScriptFirstChargingTurn - jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd - call BattleScript_PowerHerbActivation - goto BattleScript_TwoTurnMovesSecondTurn -BattleScript_EffectTwoTurnsAttackSkyAttack: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_SKY_ATTACK - goto BattleScript_EffectTwoTurnsAttackContinue -BattleScript_EffectTwoTurnsAttackRazorWind: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_RAZOR_WIND - goto BattleScript_EffectTwoTurnsAttackContinue -BattleScript_EffectTwoTurnsAttackIceBurn: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_RAZOR_WIND - goto BattleScript_EffectTwoTurnsAttackContinue -BattleScript_EffectTwoTurnsAttackFreezeShock: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_FREEZE_SHOCK - goto BattleScript_EffectTwoTurnsAttackContinue + jumpifweathercheckchargeeffects BS_ATTACKER, TRUE, BattleScript_EffectHit + call BattleScript_FirstChargingTurn + jumpifweathercheckchargeeffects BS_ATTACKER, FALSE, BattleScript_TwoTurnMovesSecondTurn + jumpifholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_TwoTurnMovesSecondPowerHerbActivates + goto BattleScript_MoveEnd BattleScript_EffectGeomancy:: jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_GeomancySecondTurn jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_GeomancySecondTurn - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_GEOMANCY - call BattleScriptFirstChargingTurn + call BattleScript_FirstChargingTurn jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd call BattleScript_PowerHerbActivation BattleScript_GeomancySecondTurn: @@ -3848,6 +3764,43 @@ BattleScript_GeomancyTrySpeed:: BattleScript_GeomancyEnd:: goto BattleScript_MoveEnd +BattleScript_FirstChargingTurn:: + attackcanceler +.if B_UPDATED_MOVE_DATA >= GEN_5 @ before Gen 5, charge moves did not print an attack string on the charge turn + flushtextbox + attackstring + waitmessage B_WAIT_TIME_LONG +.endif + ppreduce +BattleScript_FirstChargingTurnAfterAttackString: + setsemiinvulnerablebit @ only for moves with EFFECT_SEMI_INVULNERABLE/EFFECT_SKY_DROP + orword gHitMarker, HITMARKER_CHARGING + seteffectprimary MOVE_EFFECT_CHARGING | MOVE_EFFECT_AFFECTS_USER + twoturnmoveschargestringandanimation + setadditionaleffects @ only onChargeTurnOnly effects will work here + return + +BattleScript_TwoTurnMovesSecondPowerHerbActivates: + call BattleScript_PowerHerbActivation + call BattleScript_TwoTurnMovesSecondTurnRet + accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE +.if B_UPDATED_MOVE_DATA < GEN_5 @ before Gen 5, charge moves did not print an attack string on the charge turn + attackstring +.endif + goto BattleScript_HitFromCritCalc + +BattleScript_TwoTurnMovesSecondTurn:: + attackcanceler + call BattleScript_TwoTurnMovesSecondTurnRet + orword gHitMarker, HITMARKER_NO_PPDEDUCT + goto BattleScript_HitFromAccCheck + +BattleScript_TwoTurnMovesSecondTurnRet: + setbyte sB_ANIM_TURN, 1 + clearstatusfromeffect BS_ATTACKER, MOVE_EFFECT_CHARGING + clearsemiinvulnerablebit @ only for moves with EFFECT_SEMI_INVULNERABLE/EFFECT_SKY_DROP + return + BattleScript_EffectSubstitute:: attackcanceler ppreduce @@ -4178,17 +4131,6 @@ BattleScript_PartyHealEnd:: waitstate goto BattleScript_MoveEnd -BattleScript_EffectTripleKick:: - attackcanceler - accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE - jumpifmove MOVE_TRIPLE_AXEL BS_TripleAxel - addbyte sTRIPLE_KICK_POWER, 10 @ triple kick gets +10 power - goto BattleScript_HitFromAtkString - -BS_TripleAxel: - addbyte sTRIPLE_KICK_POWER, 20 @ triple axel gets +20 power - goto BattleScript_HitFromAtkString - BattleScript_EffectMeanLook:: attackcanceler attackstring @@ -4654,23 +4596,6 @@ BattleScript_EffectMirrorCoat:: adjustdamage goto BattleScript_HitFromAtkAnimation -BattleScript_EffectSkullBash:: - jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_SKULL_BASH - call BattleScriptFirstChargingTurn - setstatchanger STAT_DEF, 1, FALSE - statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_SkullBashEnd - jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_SkullBashEnd - setgraphicalstatchangevalues - playanimation BS_ATTACKER, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 - printfromtable gStatUpStringIds - waitmessage B_WAIT_TIME_LONG -BattleScript_SkullBashEnd:: - jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd - call BattleScript_PowerHerbActivation - goto BattleScript_TwoTurnMovesSecondTurn - BattleScript_EffectFutureSight:: attackcanceler attackstring @@ -4682,25 +4607,6 @@ BattleScript_EffectFutureSight:: waitmessage B_WAIT_TIME_LONG goto BattleScript_MoveEnd -BattleScript_EffectGust:: - goto BattleScript_EffectHit - -BattleScript_EffectSolarBeam:: - jumpifweatheraffected BS_ATTACKER, B_WEATHER_SUN, BattleScript_SolarBeamOnFirstTurn -BattleScript_SolarBeamDecideTurn:: - jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_TwoTurnMovesSecondTurn - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_TwoTurnMovesSecondTurn - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_SOLAR_BEAM - call BattleScriptFirstChargingTurn - jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd - call BattleScript_PowerHerbActivation - goto BattleScript_TwoTurnMovesSecondTurn -BattleScript_SolarBeamOnFirstTurn:: - orword gHitMarker, HITMARKER_CHARGING - seteffectprimary MOVE_EFFECT_CHARGING | MOVE_EFFECT_AFFECTS_USER - ppreduce - goto BattleScript_TwoTurnMovesSecondTurn - BattleScript_EffectTeleport:: .if B_TELEPORT_BEHAVIOR >= GEN_7 jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_EffectBatonPass @@ -4765,46 +4671,6 @@ BattleScript_BeatUpEnd:: end .endif -BattleScript_EffectSemiInvulnerable:: - jumpifstatus2 BS_ATTACKER, STATUS2_MULTIPLETURNS, BattleScript_SecondTurnSemiInvulnerable - jumpifword CMP_COMMON_BITS, gHitMarker, HITMARKER_NO_ATTACKSTRING, BattleScript_SecondTurnSemiInvulnerable - jumpifmove MOVE_FLY, BattleScript_FirstTurnFly - jumpifmove MOVE_DIVE, BattleScript_FirstTurnDive - jumpifmove MOVE_BOUNCE, BattleScript_FirstTurnBounce - jumpifmove MOVE_PHANTOM_FORCE, BattleScript_FirstTurnPhantomForce - jumpifmove MOVE_SHADOW_FORCE, BattleScript_FirstTurnPhantomForce - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_DIG - goto BattleScript_FirstTurnSemiInvulnerable -BattleScript_FirstTurnBounce:: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_BOUNCE - goto BattleScript_FirstTurnSemiInvulnerable -BattleScript_FirstTurnDive:: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_DIVE - goto BattleScript_FirstTurnSemiInvulnerable -BattleScript_FirstTurnPhantomForce: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_PHANTOM_FORCE - goto BattleScript_FirstTurnSemiInvulnerable -BattleScript_FirstTurnFly:: - setbyte sTWOTURN_STRINGID, B_MSG_TURN1_FLY -BattleScript_FirstTurnSemiInvulnerable:: - call BattleScriptFirstChargingTurn - setsemiinvulnerablebit - jumpifnoholdeffect BS_ATTACKER, HOLD_EFFECT_POWER_HERB, BattleScript_MoveEnd - call BattleScript_PowerHerbActivation -BattleScript_SecondTurnSemiInvulnerable:: - attackcanceler - setbyte sB_ANIM_TURN, 1 - clearstatusfromeffect BS_ATTACKER, MOVE_EFFECT_CHARGING - orword gHitMarker, HITMARKER_NO_PPDEDUCT -BattleScript_SemiInvulnerableTryHit:: - accuracycheck BattleScript_SemiInvulnerableMiss, ACC_CURR_MOVE - clearsemiinvulnerablebit - goto BattleScript_HitFromAtkString - -BattleScript_SemiInvulnerableMiss:: - clearsemiinvulnerablebit - goto BattleScript_PrintMoveMissed - BattleScript_EffectDefenseCurl:: attackcanceler attackstring @@ -5544,9 +5410,6 @@ BattleScript_CosmicPowerTrySpDef:: BattleScript_CosmicPowerEnd:: goto BattleScript_MoveEnd -BattleScript_EffectSkyUppercut:: - goto BattleScript_EffectHit - BattleScript_EffectBulkUp:: attackcanceler attackstring diff --git a/include/battle.h b/include/battle.h index 5f18b5dcf2..1fd7c5db00 100644 --- a/include/battle.h +++ b/include/battle.h @@ -54,7 +54,8 @@ struct __attribute__((packed, aligned(2))) BattleMoveEffect const u8 *battleScript; u16 battleTvScore:3; u16 encourageEncore:1; - u16 flags:12; // coming soon... + u16 semiInvulnerableEffect:1; + u16 flags:11; // coming soon... }; #define GET_MOVE_BATTLESCRIPT(move) gBattleMoveEffects[gMovesInfo[move].effect].battleScript @@ -846,10 +847,10 @@ struct BattleScripting s32 bideDmg; u8 multihitString[6]; bool8 expOnCatch; - u8 twoTurnsMoveStringId; + u8 unused; u8 animArg1; u8 animArg2; - u16 tripleKickPower; + u16 savedStringId; u8 moveendState; u8 savedStatChanger; // For further use, if attempting to change stat two times(ex. Moody) u8 shiftSwitched; // When the game tells you the next enemy's pokemon and you switch. Option for noobs but oh well. diff --git a/include/battle_ai_util.h b/include/battle_ai_util.h index 8cfa5b2cb6..cfdb791e0e 100644 --- a/include/battle_ai_util.h +++ b/include/battle_ai_util.h @@ -108,7 +108,7 @@ bool32 IsStatLoweringMoveEffect(u32 moveEffect); bool32 IsMoveRedirectionPrevented(u32 move, u32 atkAbility); bool32 IsMoveEncouragedToHit(u32 battlerAtk, u32 battlerDef, u32 move); bool32 IsHazardMoveEffect(u32 moveEffect); -bool32 IsChargingMove(u32 battlerAtk, u32 effect); +bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move); void ProtectChecks(u32 battlerAtk, u32 battlerDef, u32 move, u32 predictedMove, s32 *score); bool32 ShouldSetSandstorm(u32 battler, u32 ability, u32 holdEffect); bool32 ShouldSetHail(u32 battler, u32 ability, u32 holdEffect); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 44db02987f..3ff275d3bf 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -611,7 +611,6 @@ extern const u8 BattleScript_EffectSleepTalk[]; extern const u8 BattleScript_EffectDestinyBond[]; extern const u8 BattleScript_EffectSpite[]; extern const u8 BattleScript_EffectHealBell[]; -extern const u8 BattleScript_EffectTripleKick[]; extern const u8 BattleScript_EffectMeanLook[]; extern const u8 BattleScript_EffectNightmare[]; extern const u8 BattleScript_EffectMinimize[]; diff --git a/include/battle_util.h b/include/battle_util.h index e9b0c6f472..02eec4870f 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -225,6 +225,7 @@ bool32 MoveHasMoveEffect(u32 move, u32 moveEffect); bool32 MoveHasMoveEffectWithChance(u32 move, u32 moveEffect, u32 chance); bool32 MoveHasMoveEffectSelf(u32 move, u32 moveEffect); bool32 MoveHasMoveEffectSelfArg(u32 move, u32 moveEffect, u32 argument); +bool32 MoveHasChargeTurnMoveEffect(u32 move); bool32 CanSleep(u32 battler); bool32 CanBePoisoned(u32 battlerAttacker, u32 battlerTarget); diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 004d675701..7390f3e05b 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -117,10 +117,8 @@ enum { EFFECT_BELLY_DRUM, EFFECT_PSYCH_UP, EFFECT_MIRROR_COAT, - EFFECT_SKULL_BASH, EFFECT_EARTHQUAKE, EFFECT_FUTURE_SIGHT, - EFFECT_GUST, EFFECT_SOLAR_BEAM, EFFECT_THUNDER, EFFECT_TELEPORT, @@ -172,7 +170,6 @@ enum { EFFECT_WEATHER_BALL, EFFECT_TICKLE, EFFECT_COSMIC_POWER, - EFFECT_SKY_UPPERCUT, EFFECT_BULK_UP, EFFECT_WATER_SPORT, EFFECT_CALM_MIND, @@ -318,7 +315,6 @@ enum { EFFECT_BOLT_BEAK, EFFECT_SKY_DROP, EFFECT_EXPANDING_FORCE, - EFFECT_METEOR_BEAM, EFFECT_RISING_VOLTAGE, EFFECT_BEAK_BLAST, EFFECT_COURT_CHANGE, diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 4e653cf9e6..6d635fe848 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -6,10 +6,10 @@ #define sBIDE_DMG (gBattleScripting + 0x04) // bideDmg #define sMULTIHIT_STRING (gBattleScripting + 0x08) // multihitString #define sEXP_CATCH (gBattleScripting + 0x0E) // expOnCatch -#define sTWOTURN_STRINGID (gBattleScripting + 0x0F) // twoTurnsMoveStringId +#define sUNUSED (gBattleScripting + 0x0F) // unused #define sB_ANIM_ARG1 (gBattleScripting + 0x10) // animArg1 #define sB_ANIM_ARG2 (gBattleScripting + 0x11) // animArg2 -#define sTRIPLE_KICK_POWER (gBattleScripting + 0x12) // tripleKickPower +#define sSAVED_STRINID (gBattleScripting + 0x12) // savedStringId #define sMOVEEND_STATE (gBattleScripting + 0x14) // moveendState #define sSAVED_STAT_CHANGER (gBattleScripting + 0x15) // savedStatChanger #define sSHIFT_SWITCHED (gBattleScripting + 0x16) // shiftSwitched @@ -181,7 +181,7 @@ #define VARIOUS_TRY_FAIRY_LOCK 89 #define VARIOUS_JUMP_IF_NO_ALLY 90 #define VARIOUS_POISON_TYPE_IMMUNITY 91 -#define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 92 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 92 #define VARIOUS_INFATUATE_WITH_BATTLER 93 #define VARIOUS_SET_LAST_USED_ITEM 94 #define VARIOUS_PARALYZE_TYPE_IMMUNITY 95 @@ -220,25 +220,24 @@ #define VARIOUS_SET_SKY_DROP 128 #define VARIOUS_CLEAR_SKY_DROP 129 #define VARIOUS_SKY_DROP_YAWN 130 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 131 -#define VARIOUS_CURE_CERTAIN_STATUSES 132 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 133 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 134 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 135 -#define VARIOUS_SAVE_BATTLER_ITEM 136 -#define VARIOUS_RESTORE_BATTLER_ITEM 137 -#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 138 -#define VARIOUS_SET_BEAK_BLAST 139 -#define VARIOUS_SWAP_SIDE_STATUSES 140 -#define VARIOUS_SWAP_STATS 141 -#define VARIOUS_TEATIME_INVUL 142 -#define VARIOUS_TEATIME_TARGETS 143 -#define VARIOUS_TRY_WIND_RIDER_POWER 144 -#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 145 -#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 146 -#define VARIOUS_STORE_HEALING_WISH 147 -#define VARIOUS_HIT_SWITCH_TARGET_FAILED 148 -#define VARIOUS_TRY_REVIVAL_BLESSING 149 +#define VARIOUS_CURE_CERTAIN_STATUSES 131 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 132 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 133 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 134 +#define VARIOUS_SAVE_BATTLER_ITEM 135 +#define VARIOUS_RESTORE_BATTLER_ITEM 136 +#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 137 +#define VARIOUS_SET_BEAK_BLAST 138 +#define VARIOUS_SWAP_SIDE_STATUSES 139 +#define VARIOUS_SWAP_STATS 140 +#define VARIOUS_TEATIME_INVUL 141 +#define VARIOUS_TEATIME_TARGETS 142 +#define VARIOUS_TRY_WIND_RIDER_POWER 143 +#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 144 +#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 145 +#define VARIOUS_STORE_HEALING_WISH 146 +#define VARIOUS_HIT_SWITCH_TARGET_FAILED 147 +#define VARIOUS_TRY_REVIVAL_BLESSING 148 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index dc971b7f21..852e9a26c6 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -697,13 +697,14 @@ #define STRINGID_THESWAMPDISAPPEARED 695 #define STRINGID_PKMNTELLCHILLINGRECEPTIONJOKE 696 #define STRINGID_HOSPITALITYRESTORATION 697 -#define STRINGID_ELECTROSHOCKCHARGING 698 +#define STRINGID_ELECTROSHOTCHARGING 698 #define STRINGID_ITEMWASUSEDUP 699 #define STRINGID_ATTACKERLOSTITSTYPE 700 #define STRINGID_SHEDITSTAIL 701 -#define STRINGID_SUPERSWEETAROMAWAFTS 702 +#define STRINGID_CLOAKEDINAHARSHLIGHT 702 +#define STRINGID_SUPERSWEETAROMAWAFTS 703 -#define BATTLESTRINGS_COUNT 703 +#define BATTLESTRINGS_COUNT 704 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, @@ -747,22 +748,6 @@ #define B_MSG_LEECH_SEED_DRAIN 3 #define B_MSG_LEECH_SEED_OOZE 4 -// gFirstTurnOfTwoStringIds -#define B_MSG_TURN1_RAZOR_WIND 0 -#define B_MSG_TURN1_SOLAR_BEAM 1 -#define B_MSG_TURN1_SKULL_BASH 2 -#define B_MSG_TURN1_SKY_ATTACK 3 -#define B_MSG_TURN1_FLY 4 -#define B_MSG_TURN1_DIG 5 -#define B_MSG_TURN1_DIVE 6 -#define B_MSG_TURN1_BOUNCE 7 -#define B_MSG_TURN1_PHANTOM_FORCE 8 -#define B_MSG_TURN1_GEOMANCY 9 -#define B_MSG_TURN1_FREEZE_SHOCK 10 -#define B_MSG_TURN1_SKY_DROP 11 -#define B_MSG_TURN1_METEOR_BEAM 12 -#define B_MSG_TURN1_ELECTRO_SHOCK 13 - // gMoveWeatherChangeStringIds #define B_MSG_STARTED_RAIN 0 #define B_MSG_STARTED_DOWNPOUR 1 diff --git a/include/global.h b/include/global.h index 49095a5cd9..17790a3cc1 100644 --- a/include/global.h +++ b/include/global.h @@ -83,6 +83,62 @@ // Extracts the lower 16 bits of a 32-bit number #define LOHALF(n) ((n) & 0xFFFF) +/* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word. +Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */ +#define BIT_INDEX(n) \ + (n) == (1 << 0) ? 0 : \ + (n) == (1 << 1) ? 1 : \ + (n) == (1 << 2) ? 2 : \ + (n) == (1 << 3) ? 3 : \ + (n) == (1 << 4) ? 4 : \ + (n) == (1 << 5) ? 5 : \ + (n) == (1 << 6) ? 6 : \ + (n) == (1 << 7) ? 7 : \ + (n) == (1 << 8) ? 8 : \ + (n) == (1 << 9) ? 9 : \ + (n) == (1 << 10) ? 10 : \ + (n) == (1 << 11) ? 11 : \ + (n) == (1 << 12) ? 12 : \ + (n) == (1 << 13) ? 13 : \ + (n) == (1 << 14) ? 14 : \ + (n) == (1 << 15) ? 15 : \ + (n) == (1 << 16) ? 16 : \ + (n) == (1 << 17) ? 17 : \ + (n) == (1 << 18) ? 18 : \ + (n) == (1 << 19) ? 19 : \ + (n) == (1 << 20) ? 20 : \ + (n) == (1 << 21) ? 21 : \ + (n) == (1 << 22) ? 22 : \ + (n) == (1 << 23) ? 23 : \ + (n) == (1 << 24) ? 24 : \ + (n) == (1 << 25) ? 25 : \ + (n) == (1 << 26) ? 26 : \ + (n) == (1 << 27) ? 27 : \ + (n) == (1 << 28) ? 28 : \ + (n) == (1 << 29) ? 29 : \ + (n) == (1 << 30) ? 30 : \ + (n) == (1 << 31) ? 31 : \ + *(u32 *)NULL + +#define COMPRESS_BITS_0 0, 1 +#define COMPRESS_BITS_1 1, 1 +#define COMPRESS_BITS_2 2, 1 +#define COMPRESS_BITS_3 3, 1 +#define COMPRESS_BITS_4 4, 1 +#define COMPRESS_BITS_5 5, 1 +#define COMPRESS_BITS_6 6, 1 +#define COMPRESS_BITS_7 7, 1 + +/* Will try and compress a set bit (or up to three sequential bits) into a single byte +Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */ +#define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val +#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked) +#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__) +#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower))) + +/* Will read a compressed bit stored by COMPRESS_BIT into a single byte */ +#define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F)) + // There are many quirks in the source code which have overarching behavioral differences from // a number of other files. For example, diploma.c seems to declare rodata before each use while // other files declare out of order and must be at the beginning. There are also a number of diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 4945a7d873..d3ef2dca0e 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -813,7 +813,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) if (IsSemiInvulnerable(battlerDef, move) && moveEffect != EFFECT_SEMI_INVULNERABLE && AI_WhoStrikesFirst(battlerAtk, battlerDef, move) == AI_IS_FASTER) RETURN_SCORE_MINUS(20); // if target off screen and we go first, don't use move - if (IsChargingMove(battlerAtk, moveEffect) && CanTargetFaintAi(battlerDef, battlerAtk)) + if (IsTwoTurnNotSemiInvulnerableMove(battlerAtk, move) && CanTargetFaintAi(battlerDef, battlerAtk)) RETURN_SCORE_MINUS(10); // check if negates type @@ -3133,7 +3133,7 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId) s32 score = 0; s32 leastHits = 1000; u16 *moves = GetMovesArray(battlerAtk); - bool8 isChargingMoveEffect[MAX_MON_MOVES]; + bool8 isTwoTurnNotSemiInvulnerableMove[MAX_MON_MOVES]; for (i = 0; i < MAX_MON_MOVES; i++) { @@ -3145,13 +3145,13 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId) leastHits = noOfHits[i]; } viableMoveScores[i] = AI_SCORE_DEFAULT; - isChargingMoveEffect[i] = IsChargingMove(battlerAtk, gMovesInfo[moves[i]].effect); + isTwoTurnNotSemiInvulnerableMove[i] = IsTwoTurnNotSemiInvulnerableMove(battlerAtk, moves[i]); } else { noOfHits[i] = -1; viableMoveScores[i] = 0; - isChargingMoveEffect[i] = FALSE; + isTwoTurnNotSemiInvulnerableMove[i] = FALSE; } /* MgbaPrintf_("%S: required hits: %d Dmg: %d", gMoveNames[moves[i]], noOfHits[i], AI_DATA->simulatedDmg[battlerAtk][battlerDef][i]); @@ -3175,9 +3175,9 @@ static s32 AI_CompareDamagingMoves(u32 battlerAtk, u32 battlerDef, u32 currId) { multipleBestMoves = TRUE; // We need to make sure it's the current move which is objectively better. - if (isChargingMoveEffect[i] && !isChargingMoveEffect[currId]) + if (isTwoTurnNotSemiInvulnerableMove[i] && !isTwoTurnNotSemiInvulnerableMove[currId]) viableMoveScores[i] -= 3; - else if (!isChargingMoveEffect[i] && isChargingMoveEffect[currId]) + else if (!isTwoTurnNotSemiInvulnerableMove[i] && isTwoTurnNotSemiInvulnerableMove[currId]) viableMoveScores[currId] -= 3; switch (CompareMoveAccuracies(battlerAtk, battlerDef, currId, i)) diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 4d3e69485d..fae5f684d7 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -2016,17 +2016,14 @@ bool32 HasSnatchAffectedMove(u32 battler) CHECK_MOVE_FLAG(snatchAffected); } -bool32 IsChargingMove(u32 battlerAtk, u32 effect) +bool32 IsTwoTurnNotSemiInvulnerableMove(u32 battlerAtk, u32 move) { - switch (effect) + switch (gMovesInfo[move].effect) { case EFFECT_SOLAR_BEAM: - if (AI_GetWeather(AI_DATA) & B_WEATHER_SUN) - return FALSE; - case EFFECT_SKULL_BASH: - case EFFECT_METEOR_BEAM: case EFFECT_TWO_TURNS_ATTACK: - return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB); + return !(AI_DATA->holdEffects[battlerAtk] == HOLD_EFFECT_POWER_HERB + || (AI_GetWeather(AI_DATA) & gMovesInfo[move].argument)); default: return FALSE; } diff --git a/src/battle_message.c b/src/battle_message.c index 258b103af7..97ea9794a5 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -151,6 +151,7 @@ static const u8 sText_PkmnWhippedWhirlwind[] = _("{B_ATK_NAME_WITH_PREFIX} whipp static const u8 sText_PkmnTookSunlight[] = _("{B_ATK_NAME_WITH_PREFIX} took\nin sunlight!"); static const u8 sText_PkmnLoweredHead[] = _("{B_ATK_NAME_WITH_PREFIX} lowered\nits head!"); static const u8 sText_PkmnIsGlowing[] = _("{B_ATK_NAME_WITH_PREFIX} is glowing!"); +static const u8 sText_PkmnIsCloakedInAHarshLight[] = _("{B_ATK_NAME_WITH_PREFIX} became\ncloaked in a harsh light!"); static const u8 sText_PkmnFlewHigh[] = _("{B_ATK_NAME_WITH_PREFIX} flew\nup high!"); static const u8 sText_PkmnDugHole[] = _("{B_ATK_NAME_WITH_PREFIX} dug a hole!"); static const u8 sText_PkmnHidUnderwater[] = _("{B_ATK_NAME_WITH_PREFIX} hid\nunderwater!"); @@ -834,7 +835,7 @@ static const u8 sText_TheSeaOfFireDisappeared[] = _("The sea of fire around {B_A static const u8 sText_SwampEnvelopedSide[] = _("A swamp enveloped\n{B_DEF_TEAM2} team!"); static const u8 sText_TheSwampDisappeared[] = _("The swamp around {B_ATK_TEAM2}\nteam disappeared!"); static const u8 sText_HospitalityRestoration[] = _("The {B_ATK_PARTNER_NAME} drank down all\nthe matcha that Sinistcha made!"); -static const u8 sText_ElectroShockCharging[] = _("{B_ATK_NAME_WITH_PREFIX} absorbed\nelectricity!"); +static const u8 sText_ElectroShotCharging[] = _("{B_ATK_NAME_WITH_PREFIX} absorbed\nelectricity!"); static const u8 sText_ItemWasUsedUp[] = _("The {B_LAST_ITEM}\nwas used up..."); static const u8 sText_AttackerLostItsType[] = _("{B_ATK_NAME_WITH_PREFIX} lost\nits {B_BUFF1} type!"); static const u8 sText_ShedItsTail[] = _("{B_ATK_NAME_WITH_PREFIX} shed its tail\nto create a decoy!"); @@ -844,7 +845,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { [STRINGID_SUPERSWEETAROMAWAFTS - BATTLESTRINGS_TABLE_START] = sText_SupersweetAromaWafts, [STRINGID_SHEDITSTAIL - BATTLESTRINGS_TABLE_START] = sText_ShedItsTail, - [STRINGID_ELECTROSHOCKCHARGING - BATTLESTRINGS_TABLE_START] = sText_ElectroShockCharging, + [STRINGID_ELECTROSHOTCHARGING - BATTLESTRINGS_TABLE_START] = sText_ElectroShotCharging, [STRINGID_HOSPITALITYRESTORATION - BATTLESTRINGS_TABLE_START] = sText_HospitalityRestoration, [STRINGID_THESWAMPDISAPPEARED - BATTLESTRINGS_TABLE_START] = sText_TheSwampDisappeared, [STRINGID_SWAMPENVELOPEDSIDE - BATTLESTRINGS_TABLE_START] = sText_SwampEnvelopedSide, @@ -1533,6 +1534,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_TARGETCOVEREDINSTICKYCANDYSYRUP - BATTLESTRINGS_TABLE_START] = sText_TargetCoveredInStickyCandySyrup, [STRINGID_ITEMWASUSEDUP - BATTLESTRINGS_TABLE_START] = sText_ItemWasUsedUp, [STRINGID_ATTACKERLOSTITSTYPE - BATTLESTRINGS_TABLE_START] = sText_AttackerLostItsType, + [STRINGID_CLOAKEDINAHARSHLIGHT - BATTLESTRINGS_TABLE_START] = sText_PkmnIsCloakedInAHarshLight, }; const u16 gTrainerUsedItemStringIds[] = @@ -1758,25 +1760,6 @@ const u16 gStatDownStringIds[] = [B_MSG_STAT_FELL_EMPTY] = STRINGID_EMPTYSTRING3, }; -// Index read from sTWOTURN_STRINGID -const u16 gFirstTurnOfTwoStringIds[] = -{ - [B_MSG_TURN1_RAZOR_WIND] = STRINGID_PKMNWHIPPEDWHIRLWIND, - [B_MSG_TURN1_SOLAR_BEAM] = STRINGID_PKMNTOOKSUNLIGHT, - [B_MSG_TURN1_SKULL_BASH] = STRINGID_PKMNLOWEREDHEAD, - [B_MSG_TURN1_SKY_ATTACK] = STRINGID_PKMNISGLOWING, - [B_MSG_TURN1_FLY] = STRINGID_PKMNFLEWHIGH, - [B_MSG_TURN1_DIG] = STRINGID_PKMNDUGHOLE, - [B_MSG_TURN1_DIVE] = STRINGID_PKMNHIDUNDERWATER, - [B_MSG_TURN1_BOUNCE] = STRINGID_PKMNSPRANGUP, - [B_MSG_TURN1_PHANTOM_FORCE] = STRINGID_VANISHEDINSTANTLY, - [B_MSG_TURN1_GEOMANCY] = STRINGID_PKNMABSORBINGPOWER, - [B_MSG_TURN1_FREEZE_SHOCK] = STRINGID_CLOAKEDINAFREEZINGLIGHT, - [B_MSG_TURN1_SKY_DROP] = STRINGID_PKMNTOOKTARGETHIGH, - [B_MSG_TURN1_METEOR_BEAM] = STRINGID_METEORBEAMCHARGING, - [B_MSG_TURN1_ELECTRO_SHOCK] = STRINGID_ELECTROSHOCKCHARGING, -}; - // Index copied from move's index in sTrappingMoves const u16 gWrappedStringIds[NUM_TRAPPING_MOVES] = { diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 5ea9d6563a..47246d9356 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -498,7 +498,7 @@ static void Cmd_setdrainedhp(void); static void Cmd_statbuffchange(void); static void Cmd_normalisebuffs(void); static void Cmd_setbide(void); -static void Cmd_unused0x8C(void); +static void Cmd_twoturnmoveschargestringandanimation(void); static void Cmd_setmultihitcounter(void); static void Cmd_initmultihitstring(void); static void Cmd_forcerandomswitch(void); @@ -556,7 +556,7 @@ static void Cmd_selectfirstvalidtarget(void); static void Cmd_trysetfutureattack(void); static void Cmd_trydobeatup(void); static void Cmd_setsemiinvulnerablebit(void); -static void Cmd_clearsemiinvulnerablebit(void); +static void Cmd_jumpifweathercheckchargeeffects(void); static void Cmd_setminimize(void); static void Cmd_sethail(void); static void Cmd_trymemento(void); @@ -757,7 +757,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_statbuffchange, //0x89 Cmd_normalisebuffs, //0x8A Cmd_setbide, //0x8B - Cmd_unused0x8C, //0x8C + Cmd_twoturnmoveschargestringandanimation, //0x8C Cmd_setmultihitcounter, //0x8D Cmd_initmultihitstring, //0x8E Cmd_forcerandomswitch, //0x8F @@ -815,7 +815,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_trysetfutureattack, //0xC3 Cmd_trydobeatup, //0xC4 Cmd_setsemiinvulnerablebit, //0xC5 - Cmd_clearsemiinvulnerablebit, //0xC6 + Cmd_jumpifweathercheckchargeeffects, //0xC6 Cmd_setminimize, //0xC7 Cmd_sethail, //0xC8 Cmd_trymemento, //0xC9 @@ -845,7 +845,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_unused2, //0xE1 Cmd_switchoutabilities, //0xE2 Cmd_jumpifhasnohp, //0xE3 - Cmd_jumpifnotcurrentmoveargtype, //0xE4 + Cmd_jumpifnotcurrentmoveargtype, //0xE4 Cmd_pickup, //0xE5 Cmd_unused3, //0xE6 Cmd_unused4, //0xE7 @@ -2622,7 +2622,7 @@ static void Cmd_printstring(void) if (gBattleControllerExecFlags == 0) { - u16 id = cmd->id; + u16 id = (cmd->id == 0 ? gBattleScripting.savedStringId : cmd->id); gBattlescriptCurrInstr = cmd->nextInstr; PrepareStringBattle(id, gBattlerAttacker); @@ -8694,16 +8694,19 @@ static void Cmd_various(void) } return; } - case VARIOUS_JUMP_IF_NO_HOLD_EFFECT: + case VARIOUS_JUMP_IF_HOLD_EFFECT: { - VARIOUS_ARGS(u8 holdEffect, const u8 *jumpInstr); - if (GetBattlerHoldEffect(battler, TRUE) != cmd->holdEffect) + VARIOUS_ARGS(u8 holdEffect, const u8 *jumpInstr, u8 equal); + if ((GetBattlerHoldEffect(battler, TRUE) == cmd->holdEffect) == cmd->equal) { + if (cmd->equal) + gLastUsedItem = gBattleMons[battler].item; // For B_LAST_USED_ITEM gBattlescriptCurrInstr = cmd->jumpInstr; } else { - gLastUsedItem = gBattleMons[battler].item; // For B_LAST_USED_ITEM + if (!cmd->equal) + gLastUsedItem = gBattleMons[battler].item; // For B_LAST_USED_ITEM gBattlescriptCurrInstr = cmd->nextInstr; } return; @@ -11690,8 +11693,15 @@ static void Cmd_setbide(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_unused0x8C(void) +static void Cmd_twoturnmoveschargestringandanimation(void) { + CMD_ARGS(const u8 *animationThenStringPtr); + + gBattleScripting.savedStringId = LOHALF(gMovesInfo[gCurrentMove].argument); + if (B_UPDATED_MOVE_DATA < GEN_5 || MoveHasChargeTurnMoveEffect(gCurrentMove)) + gBattlescriptCurrInstr = cmd->animationThenStringPtr; + else + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_setmultihitcounter(void) @@ -13646,36 +13656,36 @@ static void Cmd_trydobeatup(void) static void Cmd_setsemiinvulnerablebit(void) { - CMD_ARGS(); + CMD_ARGS(bool8 clear); - switch (gCurrentMove) + if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == TRUE) { - case MOVE_FLY: - case MOVE_BOUNCE: - case MOVE_SKY_DROP: - gStatuses3[gBattlerAttacker] |= STATUS3_ON_AIR; - break; - case MOVE_DIG: - gStatuses3[gBattlerAttacker] |= STATUS3_UNDERGROUND; - break; - case MOVE_DIVE: - gStatuses3[gBattlerAttacker] |= STATUS3_UNDERWATER; - break; - case MOVE_PHANTOM_FORCE: - case MOVE_SHADOW_FORCE: - gStatuses3[gBattlerAttacker] |= STATUS3_PHANTOM_FORCE; - break; + u32 semiInvulnerableEffect = UNCOMPRESS_BITS(HIHALF(gMovesInfo[gCurrentMove].argument)); + if (cmd->clear) + gStatuses3[gBattlerAttacker] &= ~semiInvulnerableEffect; + else + gStatuses3[gBattlerAttacker] |= semiInvulnerableEffect; } gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_clearsemiinvulnerablebit(void) +static void Cmd_jumpifweathercheckchargeeffects(void) { - CMD_ARGS(); + CMD_ARGS(u8 battler, bool8 checkChargeTurnEffects, const u8 *jumpInstr); - gStatuses3[gBattlerAttacker] &= ~STATUS3_SEMI_INVULNERABLE; - gBattlescriptCurrInstr = cmd->nextInstr; + /* If this is NOT semi-invulnerable move and we don't have charge turn effects + yet to fire, we can fire the move right away so long as the weather matches + the argument and the battler is affected by it (not blocked by Cloud Nine etc) */ + if (gBattleMoveEffects[gMovesInfo[gCurrentMove].effect].semiInvulnerableEffect == FALSE + && !(cmd->checkChargeTurnEffects && MoveHasChargeTurnMoveEffect(gCurrentMove)) + && IsBattlerWeatherAffected(cmd->battler, HIHALF(gMovesInfo[gCurrentMove].argument))) + { + gBattleScripting.animTurn = 1; + gBattlescriptCurrInstr = cmd->jumpInstr; + } + else + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_setminimize(void) @@ -15552,23 +15562,6 @@ void BS_JumpIfMoreThanHalfHP(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_JumpIfHoldEffect(void) -{ - u8 battler = gBattlescriptCurrInstr[5]; - u16 holdEffect = T1_READ_16(gBattlescriptCurrInstr + 6); - - if (GetBattlerHoldEffect(battler, TRUE) == holdEffect) - { - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 8); - } - else - { - RecordItemEffectBattle(battler, holdEffect); - gLastUsedItem = gBattleMons[battler].item; // For B_LAST_USED_ITEM - gBattlescriptCurrInstr += 12; - } -} - void BS_DoStockpileStatChangesWearOff(void) { NATIVE_ARGS(u8 battler, const u8 *statChangeInstr); diff --git a/src/battle_util.c b/src/battle_util.c index 735b286e24..f3321b71f8 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -3192,7 +3192,6 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_DESTINY_BOND; gStatuses3[gBattlerAttacker] &= ~STATUS3_GRUDGE; gStatuses4[gBattlerAttacker] &= ~ STATUS4_GLAIVE_RUSH; - gBattleScripting.tripleKickPower = 0; gBattleStruct->atkCancellerTracker++; break; case CANCELLER_SKY_DROP: @@ -11050,6 +11049,17 @@ bool32 MoveHasMoveEffectSelfArg(u32 move, u32 moveEffect, u32 argument) return (gMovesInfo[move].argument == argument) && MoveHasMoveEffectSelf(move, moveEffect); } +bool32 MoveHasChargeTurnMoveEffect(u32 move) +{ + u8 i = 0; + for (i = 0; i < gMovesInfo[move].numAdditionalEffects; i++) + { + if (gMovesInfo[move].additionalEffects[i].onChargeTurnOnly) + return TRUE; + } + return FALSE; +} + bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES); diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 09234f6fdf..5a11be96cc 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -383,7 +383,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_TWO_TURNS_ATTACK] = { .battleScript = BattleScript_EffectTwoTurnsAttack, - .battleTvScore = 0, // TODO: Assign points + .battleTvScore = 3, }, [EFFECT_SUBSTITUTE] = @@ -527,7 +527,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_TRIPLE_KICK] = { - .battleScript = BattleScript_EffectTripleKick, + .battleScript = BattleScript_EffectHit, .battleTvScore = 1, }, @@ -748,12 +748,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .encourageEncore = TRUE, }, - [EFFECT_SKULL_BASH] = - { - .battleScript = BattleScript_EffectSkullBash, - .battleTvScore = 3, - }, - [EFFECT_EARTHQUAKE] = { .battleScript = BattleScript_EffectHit, @@ -767,15 +761,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .encourageEncore = TRUE, }, - [EFFECT_GUST] = - { - .battleScript = BattleScript_EffectGust, - .battleTvScore = 1, - }, - [EFFECT_SOLAR_BEAM] = { - .battleScript = BattleScript_EffectSolarBeam, + .battleScript = BattleScript_EffectTwoTurnsAttack, .battleTvScore = 1, }, @@ -799,8 +787,9 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_SEMI_INVULNERABLE] = { - .battleScript = BattleScript_EffectSemiInvulnerable, + .battleScript = BattleScript_EffectTwoTurnsAttack, .battleTvScore = 3, + .semiInvulnerableEffect = TRUE, }, [EFFECT_DEFENSE_CURL] = @@ -1101,12 +1090,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .encourageEncore = TRUE, }, - [EFFECT_SKY_UPPERCUT] = - { - .battleScript = BattleScript_EffectSkyUppercut, - .battleTvScore = 1, - }, - [EFFECT_BULK_UP] = { .battleScript = BattleScript_EffectBulkUp, @@ -2016,6 +1999,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = { .battleScript = BattleScript_EffectSkyDrop, .battleTvScore = 0, // TODO: Assign points + .semiInvulnerableEffect = TRUE, }, [EFFECT_EXPANDING_FORCE] = @@ -2024,12 +2008,6 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points }, - [EFFECT_METEOR_BEAM] = - { - .battleScript = BattleScript_EffectMeteorBeam, - .battleTvScore = 0, // TODO: Assign points - }, - [EFFECT_RISING_VOLTAGE] = { .battleScript = BattleScript_EffectHit, diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 10cda85a43..f0abe00515 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -2,6 +2,7 @@ #include "constants/battle.h" #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" +#include "constants/battle_string_ids.h" #include "constants/battle_z_move_effects.h" #include "constants/hold_effects.h" #include "constants/moves.h" @@ -21,6 +22,11 @@ #define BINDING_TURNS "2 to 5" #endif +/* First arg is the charge turn string id, second arg depends on effect +EFFECT_SEMI_INVULNERABLE/EFFECT_SKY_DROP: semi-invulnerable STATUS3 to apply to battler +EFFECT_TWO_TURNS_ATTACK/EFFECT_SOLAR_BEAM: weather in which to skip charge turn */ +#define TWO_TURN_ARG(stringid, ...) (stringid) __VA_OPT__(| ((__VA_ARGS__) << 16)) + // Shared Move Description entries const u8 gNotDoneYetDescription[] = _( @@ -427,6 +433,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .windMove = B_EXTRAPOLATED_MOVE_FLAGS, + .argument = TWO_TURN_ARG(STRINGID_PKMNWHIPPEDWHIRLWIND), .contestEffect = CONTEST_EFFECT_AFFECTED_BY_PREV_APPEAL, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -484,7 +491,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Strikes the foe with a gust\n" "of wind whipped up by wings."), - .effect = EFFECT_GUST, + .effect = EFFECT_HIT, .power = 40, .type = TYPE_FLYING, .accuracy = 100, @@ -569,6 +576,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNFLEWHIGH, COMPRESS_BITS(STATUS3_ON_AIR)), .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -1932,6 +1940,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .twoTurnMove = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNTOOKSUNLIGHT, B_WEATHER_SUN), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_COOL, .contestComboStarterId = 0, @@ -2291,6 +2300,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .instructBanned = TRUE, .assistBanned = TRUE, .skyBattleBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNDUGHOLE, COMPRESS_BITS(STATUS3_UNDERGROUND)), .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -3221,7 +3231,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Tucks in the head, then\n" "attacks on the next turn."), - .effect = EFFECT_SKULL_BASH, + .effect = EFFECT_TWO_TURNS_ATTACK, .power = B_UPDATED_MOVE_DATA >= GEN_6 ? 130 : 100, .type = TYPE_NORMAL, .accuracy = 100, @@ -3233,6 +3243,12 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .makesContact = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNLOWEREDHEAD), + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_DEF_PLUS_1, + .self = TRUE, + .onChargeTurnOnly = TRUE, + }), .contestEffect = CONTEST_EFFECT_BADLY_STARTLE_FRONT_MON, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, @@ -3541,11 +3557,12 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_PHYSICAL, - .criticalHitStage = B_UPDATED_MOVE_DATA >= GEN_3 ? 1 : 0, + .criticalHitStage = B_UPDATED_MOVE_DATA >= GEN_3, .twoTurnMove = TRUE, .sheerForceBoost = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(B_UPDATED_MOVE_DATA >= GEN_4 ? STRINGID_CLOAKEDINAHARSHLIGHT : STRINGID_PKMNISGLOWING), #if B_UPDATED_MOVE_DATA >= GEN_3 .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FLINCH, @@ -7140,6 +7157,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .instructBanned = TRUE, .assistBanned = TRUE, .skyBattleBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNHIDUNDERWATER, COMPRESS_BITS(STATUS3_UNDERWATER)), .contestEffect = CONTEST_EFFECT_AVOID_STARTLE_ONCE, .contestCategory = CONTEST_CATEGORY_BEAUTY, .contestComboStarterId = COMBO_STARTER_DIVE, @@ -8000,7 +8018,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "An uppercut thrown as if\n" "leaping into the sky."), - .effect = EFFECT_SKY_UPPERCUT, + .effect = EFFECT_HIT, .power = 85, .type = TYPE_FIGHTING, .accuracy = 90, @@ -8312,6 +8330,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNSPRANGUP, COMPRESS_BITS(STATUS3_ON_AIR)), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, @@ -11319,6 +11338,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_VANISHEDINSTANTLY, COMPRESS_BITS(STATUS3_PHANTOM_FORCE)), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), @@ -12252,6 +12272,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNTOOKTARGETHIGH, COMPRESS_BITS(STATUS3_ON_AIR)), .contestEffect = CONTEST_EFFECT_AVOID_STARTLE, .contestCategory = CONTEST_CATEGORY_SMART, .contestComboStarterId = 0, @@ -13318,6 +13339,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .metronomeBanned = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_CLOAKEDINAFREEZINGLIGHT), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_PARALYSIS, .chance = 30, @@ -13347,6 +13369,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .metronomeBanned = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_CLOAKEDINAFREEZINGLIGHT), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_BURN, .chance = 30, @@ -13648,6 +13671,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .assistBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_VANISHEDINSTANTLY, COMPRESS_BITS(STATUS3_PHANTOM_FORCE)), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_FEINT, }), @@ -14475,6 +14499,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .sleepTalkBanned = TRUE, .instructBanned = TRUE, .skyBattleBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKNMABSORBINGPOWER), .contestEffect = CONTEST_EFFECT_IMPROVE_CONDITION_PREVENT_NERVOUSNESS, .contestCategory = CONTEST_CATEGORY_CUTE, .contestComboStarterId = 0, @@ -15218,6 +15243,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .slicingMove = TRUE, .sleepTalkBanned = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_PKMNTOOKSUNLIGHT, B_WEATHER_SUN), .contestEffect = CONTEST_EFFECT_HIGHLY_APPEALING, .contestCategory = CONTEST_CATEGORY_TOUGH, .contestComboStarterId = 0, @@ -17458,7 +17484,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "A 2-turn move that raises\n" "Sp. Attack before attacking."), - .effect = EFFECT_METEOR_BEAM, + .effect = EFFECT_TWO_TURNS_ATTACK, .power = 120, .type = TYPE_ROCK, .accuracy = 90, @@ -17468,6 +17494,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .category = DAMAGE_CATEGORY_SPECIAL, .twoTurnMove = TRUE, .instructBanned = TRUE, + .argument = TWO_TURN_ARG(STRINGID_METEORBEAMCHARGING), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_SP_ATK_PLUS_1, .self = TRUE, @@ -19714,7 +19741,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Absorbs electricity in one turn,\n" "then attacks next turn."), - .effect = EFFECT_METEOR_BEAM, + .effect = EFFECT_TWO_TURNS_ATTACK, .power = 130, .type = TYPE_ELECTRIC, .accuracy = 100, @@ -19723,6 +19750,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .sheerForceBoost = TRUE, + .argument = TWO_TURN_ARG(STRINGID_ELECTROSHOTCHARGING, B_WEATHER_RAIN), .additionalEffects = ADDITIONAL_EFFECTS({ .moveEffect = MOVE_EFFECT_SP_ATK_PLUS_1, .self = TRUE, diff --git a/test/battle/ability/sheer_force.c b/test/battle/ability/sheer_force.c index be115ee918..e50ead4bdb 100644 --- a/test/battle/ability/sheer_force.c +++ b/test/battle/ability/sheer_force.c @@ -28,8 +28,7 @@ SINGLE_BATTLE_TEST("Sheer Force boosts power, but removes secondary effects of m TURN { MOVE(opponent, MOVE_QUICK_ATTACK); MOVE(player, move); } else TURN { MOVE(player, move); } - if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE - || gMovesInfo[move].effect == EFFECT_METEOR_BEAM) { + if (gMovesInfo[move].effect == EFFECT_TWO_TURNS_ATTACK || gMovesInfo[move].effect == EFFECT_SEMI_INVULNERABLE) { TURN { SKIP_TURN(player); } TURN { ; } } diff --git a/test/battle/ai.c b/test/battle/ai.c index 7d7da10947..7b9d07429e 100644 --- a/test/battle/ai.c +++ b/test/battle/ai.c @@ -292,16 +292,39 @@ AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking // Psychic and Solar Beam are chosen because user is holding Power Herb PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SOLAR_BEAM; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE; expectedMove = MOVE_PSYCHIC; expectedMove2 = MOVE_SOLAR_BEAM; } - // Psychic and Skull Bash are chosen because user is holding Power Herb - PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_PSYCHIC; move4 = MOVE_DOUBLE_EDGE; - expectedMove = MOVE_PSYCHIC; expectedMove2 = MOVE_SKULL_BASH; } // Skull Bash is chosen because it's the most accurate and is holding Power Herb PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_SLAM; move4 = MOVE_DOUBLE_EDGE; expectedMove = MOVE_SKULL_BASH; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET) { HP(5); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_GEODUDE) { Moves(move1, move2, move3, move4); Ability(abilityAtk); Item(holdItemAtk); } + } WHEN { + TURN { if (expectedMove2 == MOVE_NONE) { EXPECT_MOVE(opponent, expectedMove); SEND_OUT(player, 1); } + else {EXPECT_MOVES(opponent, expectedMove, expectedMove2); SCORE_EQ(opponent, expectedMove, expectedMove2); SEND_OUT(player, 1);} + } + } + SCENE { + MESSAGE("Wobbuffet fainted!"); + } +} + +AI_SINGLE_BATTLE_TEST("AI chooses the safest option to faint the target, taking into account accuracy and move effect failing") +{ + u16 move1 = MOVE_NONE, move2 = MOVE_NONE, move3 = MOVE_NONE, move4 = MOVE_NONE; + u16 expectedMove, expectedMove2 = MOVE_NONE; + u16 abilityAtk = ABILITY_NONE, holdItemAtk = ITEM_NONE; + + // Fiery Dance and Skull Bash are chosen because user is holding Power Herb + PARAMETRIZE { abilityAtk = ABILITY_STURDY; holdItemAtk = ITEM_POWER_HERB; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_FIERY_DANCE; move4 = MOVE_DOUBLE_EDGE; + expectedMove = MOVE_FIERY_DANCE; expectedMove2 = MOVE_SKULL_BASH; } // Crabhammer is chosen even if Skull Bash is more accurate, the user has no Power Herb PARAMETRIZE { abilityAtk = ABILITY_STURDY; move1 = MOVE_FOCUS_BLAST; move2 = MOVE_SKULL_BASH; move3 = MOVE_SLAM; move4 = MOVE_CRABHAMMER; expectedMove = MOVE_CRABHAMMER; } + KNOWN_FAILING; GIVEN { AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); PLAYER(SPECIES_WOBBUFFET) { HP(5); } diff --git a/test/battle/move_effect/meteor_beam.c b/test/battle/move_effect/meteor_beam.c deleted file mode 100644 index d9ae6fb99e..0000000000 --- a/test/battle/move_effect/meteor_beam.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].effect == EFFECT_METEOR_BEAM); -} - -SINGLE_BATTLE_TEST("Electro Shot needs a charging Turn") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_ELECTRO_SHOT); } - TURN { SKIP_TURN(player); } - } SCENE { - // Charging turn - ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_SHOT, player); - MESSAGE("Wobbuffet absorbed electricity!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Sp. Atk rose!"); - // Attack turn - MESSAGE("Wobbuffet used Electro Shot!"); - } -} - -SINGLE_BATTLE_TEST("Electro Shot doesn't need to charge when it's raining") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, MOVE_RAIN_DANCE); MOVE(player, MOVE_ELECTRO_SHOT); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, opponent); - ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_SHOT, player); - MESSAGE("Wobbuffet absorbed electricity!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Sp. Atk rose!"); - MESSAGE("Wobbuffet used Electro Shot!"); - } -} - -SINGLE_BATTLE_TEST("Electro Shot doesn't need to charge with Power Herb") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_ELECTRO_SHOT); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_SHOT, player); - MESSAGE("Wobbuffet absorbed electricity!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); - MESSAGE("Wobbuffet's Sp. Atk rose!"); - ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); - MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); - MESSAGE("Wobbuffet used Electro Shot!"); - } -} diff --git a/test/battle/move_effect/semi_invulnerable_moves.c b/test/battle/move_effect/semi_invulnerable_moves.c new file mode 100644 index 0000000000..97760225d1 --- /dev/null +++ b/test/battle/move_effect/semi_invulnerable_moves.c @@ -0,0 +1,250 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_FLY].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_FLY].argument)) == STATUS3_ON_AIR); + ASSUME(gMovesInfo[MOVE_DIG].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_DIG].argument)) == STATUS3_UNDERGROUND); + ASSUME(gMovesInfo[MOVE_BOUNCE].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_BOUNCE].argument)) == STATUS3_ON_AIR); + ASSUME(gMovesInfo[MOVE_DIVE].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_DIVE].argument)) == STATUS3_UNDERWATER); + ASSUME(gMovesInfo[MOVE_PHANTOM_FORCE].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_PHANTOM_FORCE].argument)) == STATUS3_PHANTOM_FORCE); + ASSUME(gMovesInfo[MOVE_SHADOW_FORCE].effect == EFFECT_SEMI_INVULNERABLE); + ASSUME(UNCOMPRESS_BITS(HIHALF(gMovesInfo[MOVE_SHADOW_FORCE].argument)) == STATUS3_PHANTOM_FORCE); +} + +SINGLE_BATTLE_TEST("Semi-invulnerable moves make the user semi-invulnerable turn 1, then strike turn 2") +{ + u16 move; + + PARAMETRIZE { move = MOVE_FLY; } + PARAMETRIZE { move = MOVE_DIG; } + PARAMETRIZE { move = MOVE_BOUNCE; } + PARAMETRIZE { move = MOVE_DIVE; } + PARAMETRIZE { move = MOVE_PHANTOM_FORCE; } + PARAMETRIZE { move = MOVE_SHADOW_FORCE; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); MOVE(opponent, MOVE_AERIAL_ACE); } + TURN { SKIP_TURN(player); } + } SCENE { + // Charging turn + if (B_UPDATED_MOVE_DATA >= GEN_5) + { + switch (move) + { + case MOVE_FLY: + NOT MESSAGE("Wobbuffet flew up high!"); + MESSAGE("Wobbuffet used Fly!"); + break; + case MOVE_DIG: + NOT MESSAGE("Wobbuffet dug a hole!"); + MESSAGE("Wobbuffet used Dig!"); + break; + case MOVE_BOUNCE: + NOT MESSAGE("Wobbuffet sprang up!"); + MESSAGE("Wobbuffet used Bounce!"); + break; + case MOVE_DIVE: + NOT MESSAGE("Wobbuffet hid underwater!"); + MESSAGE("Wobbuffet used Dive!"); + break; + case MOVE_PHANTOM_FORCE: + NOT MESSAGE("Wobbuffet vanished instantly!"); + MESSAGE("Wobbuffet used PhantomForce!"); + break; + case MOVE_SHADOW_FORCE: + NOT MESSAGE("Wobbuffet vanished instantly!"); + MESSAGE("Wobbuffet used Shadow Force!"); + break; + } + } else { + ANIMATION(ANIM_TYPE_MOVE, move, player); + } + if (B_UPDATED_MOVE_DATA < GEN_5) + { + switch (move) + { + case MOVE_FLY: + MESSAGE("Wobbuffet flew up high!"); + break; + case MOVE_DIG: + MESSAGE("Wobbuffet dug a hole!"); + break; + case MOVE_BOUNCE: + MESSAGE("Wobbuffet sprang up!"); + break; + case MOVE_DIVE: + MESSAGE("Wobbuffet hid underwater!"); + break; + case MOVE_PHANTOM_FORCE: + case MOVE_SHADOW_FORCE: + MESSAGE("Wobbuffet vanished instantly!"); + break; + } + } + else + ANIMATION(ANIM_TYPE_MOVE, move, player); + + // Aerial Ace cannot miss unless the target is semi-invulnerable + MESSAGE("Foe Wobbuffet used Aerial Ace!"); + MESSAGE("Foe Wobbuffet's attack missed!"); + // Attack turn + switch (move) + { + case MOVE_FLY: + MESSAGE("Wobbuffet used Fly!"); + break; + case MOVE_DIG: + MESSAGE("Wobbuffet used Dig!"); + break; + case MOVE_BOUNCE: + MESSAGE("Wobbuffet used Bounce!"); + break; + case MOVE_DIVE: + MESSAGE("Wobbuffet used Dive!"); + break; + case MOVE_PHANTOM_FORCE: + MESSAGE("Wobbuffet used PhantomForce!"); + break; + case MOVE_SHADOW_FORCE: + MESSAGE("Wobbuffet used Shadow Force!"); + break; + } + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Semi-invulnerable moves don't need to charge with Power Herb") +{ + u16 move; + + PARAMETRIZE { move = MOVE_FLY; } + PARAMETRIZE { move = MOVE_DIG; } + PARAMETRIZE { move = MOVE_BOUNCE; } + PARAMETRIZE { move = MOVE_DIVE; } + PARAMETRIZE { move = MOVE_PHANTOM_FORCE; } + PARAMETRIZE { move = MOVE_SHADOW_FORCE; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + // Charging turn + if (B_UPDATED_MOVE_DATA >= GEN_5) + { + switch (move) + { + case MOVE_FLY: + NOT MESSAGE("Wobbuffet flew up high!"); + MESSAGE("Wobbuffet used Fly!"); + break; + case MOVE_DIG: + NOT MESSAGE("Wobbuffet dug a hole!"); + MESSAGE("Wobbuffet used Dig!"); + break; + case MOVE_BOUNCE: + NOT MESSAGE("Wobbuffet sprang up!"); + MESSAGE("Wobbuffet used Bounce!"); + break; + case MOVE_DIVE: + NOT MESSAGE("Wobbuffet hid underwater!"); + MESSAGE("Wobbuffet used Dive!"); + break; + case MOVE_PHANTOM_FORCE: + NOT MESSAGE("Wobbuffet vanished instantly!"); + MESSAGE("Wobbuffet used PhantomForce!"); + break; + case MOVE_SHADOW_FORCE: + NOT MESSAGE("Wobbuffet vanished instantly!"); + MESSAGE("Wobbuffet used Shadow Force!"); + break; + } + } else { + ANIMATION(ANIM_TYPE_MOVE, move, player); + } + if (B_UPDATED_MOVE_DATA < GEN_5) + { + switch (move) + { + case MOVE_FLY: + MESSAGE("Wobbuffet flew up high!"); + break; + case MOVE_DIG: + MESSAGE("Wobbuffet dug a hole!"); + break; + case MOVE_BOUNCE: + MESSAGE("Wobbuffet sprang up!"); + break; + case MOVE_DIVE: + MESSAGE("Wobbuffet hid underwater!"); + break; + case MOVE_PHANTOM_FORCE: + case MOVE_SHADOW_FORCE: + MESSAGE("Wobbuffet vanished instantly!"); + break; + } + } + else + ANIMATION(ANIM_TYPE_MOVE, move, player); + MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); + if (B_UPDATED_MOVE_DATA < GEN_5) + { + switch (move) + { + case MOVE_FLY: + MESSAGE("Wobbuffet used Fly!"); + break; + case MOVE_DIG: + MESSAGE("Wobbuffet used Dig!"); + break; + case MOVE_BOUNCE: + MESSAGE("Wobbuffet used Bounce!"); + break; + case MOVE_DIVE: + MESSAGE("Wobbuffet used Dive!"); + break; + case MOVE_PHANTOM_FORCE: + MESSAGE("Wobbuffet used PhantomForce!"); + break; + case MOVE_SHADOW_FORCE: + MESSAGE("Wobbuffet used Shadow Force!"); + break; + } + } + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + } +} + +// No way to apply this test with Shadow Force/Phantom Force +SINGLE_BATTLE_TEST("Semi-invulnerable moves apply a status that won't block certain moves") +{ + u16 move, opMove; + + PARAMETRIZE { move = MOVE_FLY; opMove = MOVE_SKY_UPPERCUT; } + PARAMETRIZE { move = MOVE_DIG; opMove = MOVE_EARTHQUAKE; } + PARAMETRIZE { move = MOVE_BOUNCE; opMove = MOVE_THUNDER; } + PARAMETRIZE { move = MOVE_DIVE; opMove = MOVE_SURF; } + + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); MOVE(opponent, opMove); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + ANIMATION(ANIM_TYPE_MOVE, opMove, opponent); + HP_BAR(player); + } +} diff --git a/test/battle/move_effect/solar_beam.c b/test/battle/move_effect/solar_beam.c deleted file mode 100644 index 11edb61ba0..0000000000 --- a/test/battle/move_effect/solar_beam.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); - ASSUME(gMovesInfo[MOVE_SOLAR_BLADE].effect == EFFECT_SOLAR_BEAM); -} - -SINGLE_BATTLE_TEST("Solar Beam and Solar Blade can be used instantly in Sunlight") -{ - u32 move; - PARAMETRIZE { move = MOVE_SOLAR_BEAM; } - PARAMETRIZE { move = MOVE_SOLAR_BLADE; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, MOVE_SUNNY_DAY); MOVE(player, move); } - } SCENE { - NOT MESSAGE("Wobbuffet took in sunlight!"); - } -} - -SINGLE_BATTLE_TEST("Solar Beam's power is halved in Rain", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_RAIN_DANCE; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Blade's power is halved in Rain", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_RAIN_DANCE; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT); - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Beam's power is halved in a Sandstorm", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_SANDSTORM; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Blade's power is halved in a Sandstorm", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_SANDSTORM; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Beam's power is halved in Hail", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_HAIL; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Blade's power is halved in Hail", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_HAIL; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Beam's power is halved in Snow", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_SNOWSCAPE; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} - -SINGLE_BATTLE_TEST("Solar Blade's power is halved in Snow", s16 damage) -{ - u16 move; - PARAMETRIZE{ move = MOVE_CELEBRATE; } - PARAMETRIZE{ move = MOVE_SNOWSCAPE; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT); - } WHEN { - TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } - TURN { SKIP_TURN(player); } - } SCENE { - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); - } -} diff --git a/test/battle/move_effect/two_turn_moves.c b/test/battle/move_effect/two_turn_moves.c new file mode 100644 index 0000000000..3011656756 --- /dev/null +++ b/test/battle/move_effect/two_turn_moves.c @@ -0,0 +1,449 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_RAZOR_WIND].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(gMovesInfo[MOVE_SKULL_BASH].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(MoveHasMoveEffectSelf(MOVE_SKULL_BASH, MOVE_EFFECT_DEF_PLUS_1) == TRUE); + ASSUME(gMovesInfo[MOVE_SKY_ATTACK].effect == EFFECT_TWO_TURNS_ATTACK); + + // Solar Beam - check for sun + ASSUME(gMovesInfo[MOVE_SOLAR_BEAM].effect == EFFECT_SOLAR_BEAM); + ASSUME(HIHALF(gMovesInfo[MOVE_SOLAR_BLADE].argument) == B_WEATHER_SUN); + ASSUME(gMovesInfo[MOVE_SOLAR_BLADE].effect == EFFECT_SOLAR_BEAM); + ASSUME(HIHALF(gMovesInfo[MOVE_SOLAR_BLADE].argument) == B_WEATHER_SUN); + + // Electro shot - check for rain + ASSUME(HIHALF(gMovesInfo[MOVE_ELECTRO_SHOT].argument) == B_WEATHER_RAIN); + ASSUME(gMovesInfo[MOVE_ELECTRO_SHOT].effect == EFFECT_TWO_TURNS_ATTACK); + ASSUME(MoveHasMoveEffectSelf(MOVE_ELECTRO_SHOT, MOVE_EFFECT_SP_ATK_PLUS_1) == TRUE); +} + +SINGLE_BATTLE_TEST("Razor Wind needs a charging turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAZOR_WIND); } + TURN { SKIP_TURN(player); } + } SCENE { + // Charging turn + if (B_UPDATED_MOVE_DATA >= GEN_5) { + NOT MESSAGE("Wobbuffet whipped up a whirlwind!"); + MESSAGE("Wobbuffet used Razor Wind!"); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); + } + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet whipped up a whirlwind!"); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); + // Attack turn + MESSAGE("Wobbuffet used Razor Wind!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Razor Wind doesn't need to charge with Power Herb") +{ + KNOWN_FAILING; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_RAZOR_WIND); } + } SCENE { + if (B_UPDATED_MOVE_DATA >= GEN_5) { + NOT MESSAGE("Wobbuffet whipped up a whirlwind!"); + MESSAGE("Wobbuffet used Razor Wind!"); + } else + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet whipped up a whirlwind!"); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet used Razor Wind!"); + // For some reason, this breaks with and only with Razor Wind... + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAZOR_WIND, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Skull Bash needs a charging turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SKULL_BASH); } + TURN { SKIP_TURN(player); } + } SCENE { + // Charging turn + if (B_UPDATED_MOVE_DATA >= GEN_5) { + NOT MESSAGE("Wobbuffet lowered its head!"); + MESSAGE("Wobbuffet used Skull Bash!"); + } else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKULL_BASH, player); + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet lowered its head!"); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKULL_BASH, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Defense rose!"); + // Attack turn + MESSAGE("Wobbuffet used Skull Bash!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKULL_BASH, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Skull Bash doesn't need to charge with Power Herb") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SKULL_BASH); } + } SCENE { + if (B_UPDATED_MOVE_DATA >= GEN_5) { + NOT MESSAGE("Wobbuffet lowered its head!"); + MESSAGE("Wobbuffet used Skull Bash!"); + } else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKULL_BASH, player); + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet lowered its head!"); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKULL_BASH, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Defense rose!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet used Skull Bash!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKULL_BASH, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Sky Attack needs a charging turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SKY_ATTACK); } + TURN { SKIP_TURN(player); } + } SCENE { + // Charging turn + if (B_UPDATED_MOVE_DATA >= GEN_5) { + NONE_OF { + MESSAGE("Wobbuffet became cloaked in a harsh light!"); + MESSAGE("Wobbuffet is glowing!"); + } + MESSAGE("Wobbuffet used Sky Attack!"); + } else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_ATTACK, player); + if (B_UPDATED_MOVE_DATA < GEN_4) + MESSAGE("Wobbuffet is glowing!"); + else if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet became cloaked in a harsh light!"); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_ATTACK, player); + // Attack turn + MESSAGE("Wobbuffet used Sky Attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_ATTACK, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Sky Attack doesn't need to charge with Power Herb") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_SKY_ATTACK); } + } SCENE { + if (B_UPDATED_MOVE_DATA >= GEN_5) { + NONE_OF { + MESSAGE("Wobbuffet became cloaked in a harsh light!"); + MESSAGE("Wobbuffet is glowing!"); + } + MESSAGE("Wobbuffet used Sky Attack!"); + } else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_ATTACK, player); + if (B_UPDATED_MOVE_DATA < GEN_4) + MESSAGE("Wobbuffet is glowing!"); + else if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet became cloaked in a harsh light!"); + else + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_ATTACK, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); + if (B_UPDATED_MOVE_DATA < GEN_5) + MESSAGE("Wobbuffet used Sky Attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_ATTACK, player); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Solar Beam and Solar Blade can be used instantly in Sunlight") +{ + u32 move1, move2; + PARAMETRIZE { move1 = MOVE_SPLASH; move2 = MOVE_SOLAR_BEAM; } + PARAMETRIZE { move1 = MOVE_SUNNY_DAY; move2 = MOVE_SOLAR_BEAM; } + PARAMETRIZE { move1 = MOVE_SPLASH; move2 = MOVE_SOLAR_BLADE; } + PARAMETRIZE { move1 = MOVE_SUNNY_DAY; move2 = MOVE_SOLAR_BLADE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move1); MOVE(player, move2); } + TURN { SKIP_TURN(player); } + } SCENE { + if (move1 == MOVE_SUNNY_DAY) { + NOT MESSAGE("Wobbuffet took in sunlight!"); + } else { + if (move2 == MOVE_SOLAR_BEAM) { + if (B_UPDATED_MOVE_DATA >= GEN_5) + { + MESSAGE("Wobbuffet used Solar Beam!"); + MESSAGE("Wobbuffet took in sunlight!"); + ANIMATION(ANIM_TYPE_MOVE, move2, player); + } else { + NOT MESSAGE("Wobbuffet used Solar Beam!"); + ANIMATION(ANIM_TYPE_MOVE, move2, player); + MESSAGE("Wobbuffet took in sunlight!"); + } + MESSAGE("Wobbuffet used Solar Beam!"); + } else { + if (B_UPDATED_MOVE_DATA >= GEN_5) { + MESSAGE("Wobbuffet used Solar Blade!"); + MESSAGE("Wobbuffet took in sunlight!"); + ANIMATION(ANIM_TYPE_MOVE, move2, player); + } else { + NOT MESSAGE("Wobbuffet used Solar Blade!"); + ANIMATION(ANIM_TYPE_MOVE, move2, player); + MESSAGE("Wobbuffet took in sunlight!"); + } + MESSAGE("Wobbuffet used Solar Blade!"); + } + ANIMATION(ANIM_TYPE_MOVE, move2, player); + HP_BAR(opponent); + } + } +} + +SINGLE_BATTLE_TEST("Solar Beam's power is halved in Rain", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_RAIN_DANCE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Blade's power is halved in Rain", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_RAIN_DANCE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Beam's power is halved in a Sandstorm", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SANDSTORM; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Blade's power is halved in a Sandstorm", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SANDSTORM; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Beam's power is halved in Hail", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_HAIL; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Blade's power is halved in Hail", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_HAIL; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_SAFETY_GOGGLES); }; + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Beam's power is halved in Snow", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SNOWSCAPE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BEAM); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Solar Blade's power is halved in Snow", s16 damage) +{ + u16 move; + PARAMETRIZE{ move = MOVE_CELEBRATE; } + PARAMETRIZE{ move = MOVE_SNOWSCAPE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponent, move); MOVE(player, MOVE_SOLAR_BLADE); } + TURN { SKIP_TURN(player); } + } SCENE { + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Electro Shot needs a charging Turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRO_SHOT); } + TURN { SKIP_TURN(player); } + } SCENE { + // Charging turn + MESSAGE("Wobbuffet used Electro Shot!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_SHOT, player); + MESSAGE("Wobbuffet absorbed electricity!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Sp. Atk rose!"); + // Attack turn + MESSAGE("Wobbuffet used Electro Shot!"); + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Electro Shot doesn't need to charge when it's raining") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_RAIN_DANCE); MOVE(player, MOVE_ELECTRO_SHOT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, opponent); + MESSAGE("Wobbuffet used Electro Shot!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_SHOT, player); + MESSAGE("Wobbuffet absorbed electricity!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Sp. Atk rose!"); + NONE_OF { + MESSAGE("Wobbuffet used Electro Shot!"); + } + HP_BAR(opponent); + } +} + +SINGLE_BATTLE_TEST("Electro Shot doesn't need to charge with Power Herb") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_POWER_HERB); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ELECTRO_SHOT); } + } SCENE { + MESSAGE("Wobbuffet used Electro Shot!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRO_SHOT, player); + MESSAGE("Wobbuffet absorbed electricity!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Sp. Atk rose!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet became fully charged due to its Power Herb!"); + NONE_OF { + MESSAGE("Wobbuffet used Electro Shot!"); + } + HP_BAR(opponent); + } +} From 065c0ec5887baba3fc374deaf63ef0a599dc6b7a Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sun, 4 Feb 2024 23:23:03 +0100 Subject: [PATCH 18/25] Fairy Lock animation fix (#4111) * Fairy Lock animation fix * remove comment * fairy lock anim hopefully works --------- Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- data/battle_anim_scripts.s | 5 ++--- include/battle_anim.h | 1 + src/battle_anim_electric.c | 27 ++++++++++++++++++++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 4145679f34..4cf2bfdc13 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -9210,13 +9210,12 @@ Boomburst_Doubles: goto Boomburst_Last Move_FAIRY_LOCK:: - loadspritegfx ANIM_TAG_CHAIN_LINK @Chain Colour - loadspritegfx ANIM_TAG_FAIRY_LOCK_CHAINS @AnimTask is missing for Fairy Lock Chain + loadspritegfx ANIM_TAG_FAIRY_LOCK_CHAINS setalpha 8, 8 monbg ANIM_ATK_PARTNER createvisualtask AnimTask_BlendBattleAnimPal, 0xa, F_PAL_BG, 0x1, 0x0, 0x8, 0x6B1F waitforvisualfinish - loopsewithpan SE_M_SCRATCH, SOUND_PAN_TARGET, 0x6, 0x4 + loopsewithpan SE_M_SCRATCH, SOUND_PAN_TARGET, 0x6, 0x9 createvisualtask AnimTask_VoltTackleBolt, 0x5, 0x7 createvisualtask AnimTask_VoltTackleBolt, 0x5, 0x33 createvisualtask AnimTask_VoltTackleBolt, 0x5, 0x2 diff --git a/include/battle_anim.h b/include/battle_anim.h index f8f0dff969..250a3ac447 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -415,6 +415,7 @@ extern const struct OamData gOamData_AffineDouble_ObjNormal_64x64; extern const struct OamData gOamData_AffineDouble_ObjBlend_64x64; extern const struct OamData gOamData_AffineDouble_ObjBlend_64x32; extern const struct OamData gOamData_AffineDouble_ObjNormal_8x16; +extern const struct OamData gOamData_AffineDouble_ObjNormal_64x32; extern const struct OamData gOamData_AffineOff_ObjBlend_16x16; extern const struct OamData gOamData_AffineDouble_ObjBlend_16x16; extern const struct OamData gOamData_AffineNormal_ObjNormal_8x8; diff --git a/src/battle_anim_electric.c b/src/battle_anim_electric.c index 415f112d30..38ca948749 100644 --- a/src/battle_anim_electric.c +++ b/src/battle_anim_electric.c @@ -479,6 +479,17 @@ const struct SpriteTemplate gVoltTackleBoltSpriteTemplate = .callback = AnimVoltTackleBolt, }; +const struct SpriteTemplate gFairyLockChainsSpriteTemplate = +{ + .tileTag = ANIM_TAG_FAIRY_LOCK_CHAINS, + .paletteTag = ANIM_TAG_FAIRY_LOCK_CHAINS, + .oam = &gOamData_AffineOff_ObjNormal_64x32, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = AnimVoltTackleBolt, +}; + const struct SpriteTemplate gGrowingShockWaveOrbSpriteTemplate = { .tileTag = ANIM_TAG_CIRCLE_OF_LIGHT, @@ -1190,11 +1201,20 @@ void AnimTask_VoltTackleBolt(u8 taskId) static bool8 CreateVoltTackleBolt(struct Task *task, u8 taskId) { - u8 spriteId = CreateSprite(&gVoltTackleBoltSpriteTemplate, task->data[3], task->data[5], 35); + u32 spriteId; + bool32 isFairyLock = (gAnimMoveIndex == MOVE_FAIRY_LOCK); + + if (isFairyLock) + spriteId = CreateSprite(&gFairyLockChainsSpriteTemplate, task->data[3], task->data[5] + 10, 35); + else + spriteId = CreateSprite(&gVoltTackleBoltSpriteTemplate, task->data[3], task->data[5], 35); + if (spriteId != MAX_SPRITES) { gSprites[spriteId].data[6] = taskId; gSprites[spriteId].data[7] = 7; + gSprites[spriteId].data[1] = isFairyLock ? 25 : 12; // How long the chains / bolts stay on screen. + gSprites[spriteId].data[2] = isFairyLock; // Whether to destroy the Oam Matrix. task->data[7]++; } @@ -1220,10 +1240,11 @@ static bool8 CreateVoltTackleBolt(struct Task *task, u8 taskId) static void AnimVoltTackleBolt(struct Sprite *sprite) { - if (++sprite->data[0] > 12) + if (++sprite->data[0] > sprite->data[1]) { gTasks[sprite->data[6]].data[sprite->data[7]]--; - FreeOamMatrix(sprite->oam.matrixNum); + if (!sprite->data[2]) + FreeOamMatrix(sprite->oam.matrixNum); DestroySprite(sprite); } } From 521ef8bf866ca23f89be5c47b2be43cc5db395dd Mon Sep 17 00:00:00 2001 From: ghoulslash <41651341+ghoulslash@users.noreply.github.com> Date: Sun, 4 Feb 2024 17:30:30 -0500 Subject: [PATCH 19/25] battle debug menu can cycle through battlers in ai score/dmg window (#4134) Co-authored-by: ghoulslash Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- src/battle_debug.c | 53 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/battle_debug.c b/src/battle_debug.c index b01ff6bd5e..cdda88e236 100644 --- a/src/battle_debug.c +++ b/src/battle_debug.c @@ -764,6 +764,22 @@ static void PutMovesPointsText(struct BattleDebugMenu *data) Free(text); } +static void CleanUpAiInfoWindow(u8 taskId) +{ + u32 i; + struct BattleDebugMenu *data = GetStructPtr(taskId); + + FreeMonIconPalettes(); + for (i = 0; i < MAX_BATTLERS_COUNT; i++) + { + if (data->spriteIds.aiIconSpriteIds[i] != 0xFF) + FreeAndDestroyMonIconSprite(&gSprites[data->spriteIds.aiIconSpriteIds[i]]); + } + FreeAndDestroyMonPicSprite(data->aiMonSpriteId); + ClearWindowTilemap(data->aiMovesWindowId); + RemoveWindow(data->aiMovesWindowId); +} + static void Task_ShowAiPoints(u8 taskId) { u32 i, count; @@ -784,6 +800,7 @@ static void Task_ShowAiPoints(u8 taskId) if (++data->aiBattlerId >= gBattlersCount) data->aiBattlerId = 0; } + data->battlerId = data->aiBattlerId; LoadMonIconPalettes(); for (count = 0, i = 0; i < MAX_BATTLERS_COUNT; i++) @@ -822,7 +839,27 @@ static void Task_ShowAiPoints(u8 taskId) break; // Input case 2: - if (JOY_NEW(SELECT_BUTTON | B_BUTTON)) + if (JOY_NEW(R_BUTTON) && IsDoubleBattle()) + { + CleanUpAiInfoWindow(taskId); + do { + data->battlerId++; + data->battlerId %= gBattlersCount; + } while (!IsBattlerAlive(data->battlerId)); + data->aiViewState = 0; + } + else if (JOY_NEW(L_BUTTON) && IsDoubleBattle()) + { + CleanUpAiInfoWindow(taskId); + do { + if (data->battlerId == 0) + data->battlerId = gBattlersCount - 1; + else + data->battlerId--; + } while (!IsBattlerAlive(data->battlerId) || !BattlerHasAi(data->battlerId)); + data->aiViewState = 0; + } + else if (JOY_NEW(SELECT_BUTTON | B_BUTTON)) { SwitchToDebugView(taskId); HideBg(1); @@ -1093,19 +1130,7 @@ static void SwitchToDebugViewFromAiParty(u8 taskId) static void SwitchToDebugView(u8 taskId) { - u32 i; - struct BattleDebugMenu *data = GetStructPtr(taskId); - - FreeMonIconPalettes(); - for (i = 0; i < MAX_BATTLERS_COUNT; i++) - { - if (data->spriteIds.aiIconSpriteIds[i] != 0xFF) - FreeAndDestroyMonIconSprite(&gSprites[data->spriteIds.aiIconSpriteIds[i]]); - } - FreeAndDestroyMonPicSprite(data->aiMonSpriteId); - ClearWindowTilemap(data->aiMovesWindowId); - RemoveWindow(data->aiMovesWindowId); - + CleanUpAiInfoWindow(taskId); gTasks[taskId].func = Task_DebugMenuProcessInput; } From 8b70cea7254ccaf789da8e3363bb1177ada2a0a2 Mon Sep 17 00:00:00 2001 From: ravepossum <145081120+ravepossum@users.noreply.github.com> Date: Mon, 5 Feb 2024 09:40:25 -0500 Subject: [PATCH 20/25] Fix screen select bar popping in too early for area screen in HGSS dex (#4094) * fixing screen select bar popping in too early for area screen in HGSS pokedex * exit early from select bar load function if dex is disabled * remove unnecessary early exit --------- Co-authored-by: ravepossum Co-authored-by: Bassoonian Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- src/pokedex_area_screen.c | 11 +++++++++++ src/pokedex_plus_hgss.c | 8 -------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/pokedex_area_screen.c b/src/pokedex_area_screen.c index d5aa3f96c9..1c155bf5ec 100755 --- a/src/pokedex_area_screen.c +++ b/src/pokedex_area_screen.c @@ -107,9 +107,11 @@ static void CreateAreaUnknownSprites(void); static void Task_HandlePokedexAreaScreenInput(u8); static void ResetPokedexAreaMapBg(void); static void DestroyAreaScreenSprites(void); +static void LoadHGSSScreenSelectBarSubmenu(void); static const u32 sAreaGlow_Pal[] = INCBIN_U32("graphics/pokedex/area_glow.gbapal"); static const u32 sAreaGlow_Gfx[] = INCBIN_U32("graphics/pokedex/area_glow.4bpp.lz"); +static const u32 sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap[] = INCBIN_U32("graphics/pokedex/hgss/SelectBar.bin.lz"); static const u16 sSpeciesHiddenFromAreaScreen[] = { SPECIES_WYNAUT }; @@ -639,6 +641,9 @@ static void Task_ShowPokedexAreaScreen(u8 taskId) BeginNormalPaletteFade(PALETTES_ALL & ~(0x14), 0, 16, 0, RGB_BLACK); break; case 10: + if (POKEDEX_PLUS_HGSS) + LoadHGSSScreenSelectBarSubmenu(); + SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG0 | BLDCNT_EFFECT_BLEND | BLDCNT_TGT2_BG0 | BLDCNT_TGT2_ALL); StartAreaGlow(); ShowBg(2); @@ -806,3 +811,9 @@ static void CreateAreaUnknownSprites(void) } } } + +static void LoadHGSSScreenSelectBarSubmenu(void) +{ + CopyToBgTilemapBuffer(1, sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap, 0, 0); + CopyBgTilemapBufferToVram(1); +} diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 905fdae97e..a1c8b795f5 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -528,7 +528,6 @@ static void Task_LoadSizeScreen(u8); static void Task_HandleSizeScreenInput(u8); static void Task_SwitchScreensFromSizeScreen(u8); static void LoadScreenSelectBarMain(u16); -static void LoadScreenSelectBarSubmenu(u16); static void HighlightScreenSelectBarItem(u8, u16); static void Task_HandleCaughtMonPageInput(u8); static void Task_ExitCaughtMonPage(u8); @@ -4031,7 +4030,6 @@ static void Task_LoadAreaScreen(u8 taskId) } break; case 1: - LoadScreenSelectBarSubmenu(0xD); LoadPokedexBgPalette(sPokedexView->isSearchResults); SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(0) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(13) | BGCNT_16COLOR | BGCNT_TXT256x256); gMain.state++; @@ -4086,12 +4084,6 @@ static void LoadScreenSelectBarMain(u16 unused) CopyBgTilemapBufferToVram(1); } -static void LoadScreenSelectBarSubmenu(u16 unused) -{ - CopyToBgTilemapBuffer(1, sPokedexPlusHGSS_ScreenSelectBarSubmenu_Tilemap, 0, 0); - CopyBgTilemapBufferToVram(1); -} - static void UNUSED HighlightScreenSelectBarItem(u8 selectedScreen, u16 unused) { u8 i; From c2c97d3c1c224b39cddcf3033301fd5c898301c7 Mon Sep 17 00:00:00 2001 From: ghoulslash <41651341+ghoulslash@users.noreply.github.com> Date: Tue, 6 Feb 2024 03:05:26 -0500 Subject: [PATCH 21/25] GetBattleAnimMoveTargets fill absolute battler ids instead of relative anim ids (#4139) Co-authored-by: ghoulslash Co-authored-by: DizzyEggg --- include/constants/battle_anim.h | 4 +- src/battle_anim.c | 67 ++++++++++++++++++++++----------- src/battle_anim_mons.c | 36 ++++++++++-------- 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index ddd7b37843..b085d305ab 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -414,8 +414,8 @@ // Below are used by AnimTask_ShakeMon2 and AnimTask_SetGrayscaleOrOriginalPal #define ANIM_PLAYER_LEFT (MAX_BATTLERS_COUNT + 0) -#define ANIM_PLAYER_RIGHT (MAX_BATTLERS_COUNT + 1) -#define ANIM_OPPONENT_LEFT (MAX_BATTLERS_COUNT + 2) +#define ANIM_OPPONENT_LEFT (MAX_BATTLERS_COUNT + 1) +#define ANIM_PLAYER_RIGHT (MAX_BATTLERS_COUNT + 2) #define ANIM_OPPONENT_RIGHT (MAX_BATTLERS_COUNT + 3) #define ANIM_ATTACKER_FORCE (MAX_BATTLERS_COUNT + 4) diff --git a/src/battle_anim.c b/src/battle_anim.c index c9e3789ee5..af1a5a262a 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -442,28 +442,44 @@ static void Cmd_unloadspritegfx(void) static u8 GetBattleAnimMoveTargets(u8 battlerArgIndex, u8 *targets) { u8 numTargets = 0; - int idx = 0; - u32 battler = gBattleAnimArgs[battlerArgIndex]; - switch (GetBattlerMoveTargetType(gBattleAnimAttacker, gAnimMoveIndex)) + u32 battlerAnimId = gBattleAnimArgs[battlerArgIndex]; // ANIM_xx input + u32 i; + u32 ignoredTgt = gBattlerAttacker; + u32 target = GetBattlerMoveTargetType(gBattleAnimAttacker, gAnimMoveIndex); + + switch (battlerAnimId) + { + case ANIM_ATTACKER: + case ANIM_ATK_PARTNER: + ignoredTgt = gBattlerTarget; + break; + case ANIM_TARGET: + case ANIM_DEF_PARTNER: + ignoredTgt = gBattlerAttacker; + break; + } + + switch (target) { case MOVE_TARGET_FOES_AND_ALLY: - if (IS_ALIVE_AND_PRESENT(BATTLE_PARTNER(BATTLE_OPPOSITE(battler)))) + if (battlerAnimId == ANIM_ATTACKER) { - targets[idx++] = BATTLE_PARTNER(BATTLE_OPPOSITE(battler)); - numTargets++; + targets[numTargets++] = gBattleAnimAttacker; } - // fallthrough - case MOVE_TARGET_BOTH: - if (IS_ALIVE_AND_PRESENT(battler)) + else { - targets[idx++] = battler; - numTargets++; + for (i = 0; i < gBattlersCount; i++) + { + if (i != gBattleAnimAttacker && IS_ALIVE_AND_PRESENT(i)) + targets[numTargets++] = i + MAX_BATTLERS_COUNT; // anim ids for battler ids + } } - battler = BATTLE_PARTNER(battler); - if (IS_ALIVE_AND_PRESENT(battler)) + break; + case MOVE_TARGET_BOTH: // all opponents + for (i = 0; i < gBattlersCount; i++) { - targets[idx++] = battler; - numTargets++; + if (i != ignoredTgt && !IsAlly(i, ignoredTgt) && IS_ALIVE_AND_PRESENT(i)) + targets[numTargets++] = i + MAX_BATTLERS_COUNT; } break; default: @@ -541,7 +557,7 @@ static void Cmd_createsprite(void) static void CreateSpriteOnTargets(const struct SpriteTemplate *template, u8 argVar, u8 battlerArgIndex, u8 argsCount, bool32 overwriteAnimTgt) { - u32 i; + u32 i, battler; u8 targets[MAX_BATTLERS_COUNT]; int ntargets; s16 subpriority; @@ -560,12 +576,13 @@ static void CreateSpriteOnTargets(const struct SpriteTemplate *template, u8 argV for (i = 0; i < ntargets; i++) { + battler = GetAnimBattlerId(targets[i]); if (overwriteAnimTgt) gBattleAnimArgs[battlerArgIndex] = targets[i]; if (CreateSpriteAndAnimate(template, - GetBattlerSpriteCoord(targets[i], BATTLER_COORD_X_2), - GetBattlerSpriteCoord(targets[i], BATTLER_COORD_Y_PIC_OFFSET), + GetBattlerSpriteCoord(battler, BATTLER_COORD_X_2), + GetBattlerSpriteCoord(battler, BATTLER_COORD_Y_PIC_OFFSET), subpriority) != MAX_SPRITES) // Don't increment the task count if the sprite couldn't be created(i.e. there are too many created sprites atm). { gAnimVisualTaskCount++; @@ -904,14 +921,20 @@ static void Cmd_monbg(void) u8 GetAnimBattlerId(u8 wantedBattler) { - if (wantedBattler == ANIM_ATTACKER) + switch (wantedBattler) + { + case ANIM_ATTACKER: + default: return gBattleAnimAttacker; - else if (wantedBattler == ANIM_TARGET) + case ANIM_TARGET: return gBattleAnimTarget; - else if (wantedBattler == ANIM_ATK_PARTNER) + case ANIM_ATK_PARTNER: return BATTLE_PARTNER(gBattleAnimAttacker); - else + case ANIM_DEF_PARTNER: return BATTLE_PARTNER(gBattleAnimTarget); + case ANIM_PLAYER_LEFT ... ANIM_OPPONENT_RIGHT: + return wantedBattler - MAX_BATTLERS_COUNT; + } } bool8 IsBattlerSpriteVisible(u8 battlerId) diff --git a/src/battle_anim_mons.c b/src/battle_anim_mons.c index 0faf15c0f1..542a179d6a 100644 --- a/src/battle_anim_mons.c +++ b/src/battle_anim_mons.c @@ -309,45 +309,51 @@ u8 GetBattlerYCoordWithElevation(u8 battlerId) u8 GetAnimBattlerSpriteId(u8 animBattler) { - u8 *sprites; + u32 partner; - if (animBattler == ANIM_ATTACKER) + switch (animBattler) { + case ANIM_ATTACKER: if (IsBattlerSpritePresent(gBattleAnimAttacker)) { - sprites = gBattlerSpriteIds; - return sprites[gBattleAnimAttacker]; + return gBattlerSpriteIds[gBattleAnimAttacker]; } else { return SPRITE_NONE; } - } - else if (animBattler == ANIM_TARGET) - { + break; + case ANIM_TARGET: if (IsBattlerSpritePresent(gBattleAnimTarget)) { - sprites = gBattlerSpriteIds; - return sprites[gBattleAnimTarget]; + return gBattlerSpriteIds[gBattleAnimTarget]; } else { return SPRITE_NONE; } - } - else if (animBattler == ANIM_ATK_PARTNER) - { + break; + case ANIM_ATK_PARTNER: if (!IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimAttacker))) return SPRITE_NONE; else return gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimAttacker)]; - } - else - { + break; + case ANIM_DEF_PARTNER: if (IsBattlerSpriteVisible(BATTLE_PARTNER(gBattleAnimTarget))) return gBattlerSpriteIds[BATTLE_PARTNER(gBattleAnimTarget)]; else return SPRITE_NONE; + break; + case ANIM_PLAYER_LEFT ... ANIM_OPPONENT_RIGHT: + partner = animBattler - MAX_BATTLERS_COUNT; + if (IsBattlerSpriteVisible(partner)) + return gBattlerSpriteIds[partner]; + else + return SPRITE_NONE; + break; + default: + return SPRITE_NONE; } } From f7ec44c2ea44433811e469a1f53587c9adcc3d7b Mon Sep 17 00:00:00 2001 From: Nephrite Date: Tue, 6 Feb 2024 17:19:37 +0900 Subject: [PATCH 22/25] Fixed Shield Dust, added tests (#4137) * Fixed Shield Dust, added tests Also fixed a duplicate macro caused by near-simultaneous PR merges (oops) * Added KNOWN_FAILING Sparkling Aria test --------- Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- include/global.h | 59 ------------- include/metaprogram.h | 3 + src/battle_script_commands.c | 6 +- src/data/moves_info.h | 3 +- test/battle/ability/shield_dust.c | 139 ++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 65 deletions(-) create mode 100644 test/battle/ability/shield_dust.c diff --git a/include/global.h b/include/global.h index 18a8f8199c..b6d10b14ae 100644 --- a/include/global.h +++ b/include/global.h @@ -83,62 +83,6 @@ // Extracts the lower 16 bits of a 32-bit number #define LOHALF(n) ((n) & 0xFFFF) -/* (Credit to MGriffin) A rather monstrous way of finding the set bit in a word. -Invalid input causes a compiler error. Sample: https://cexplore.karathan.at/z/x1hm7B */ -#define BIT_INDEX(n) \ - (n) == (1 << 0) ? 0 : \ - (n) == (1 << 1) ? 1 : \ - (n) == (1 << 2) ? 2 : \ - (n) == (1 << 3) ? 3 : \ - (n) == (1 << 4) ? 4 : \ - (n) == (1 << 5) ? 5 : \ - (n) == (1 << 6) ? 6 : \ - (n) == (1 << 7) ? 7 : \ - (n) == (1 << 8) ? 8 : \ - (n) == (1 << 9) ? 9 : \ - (n) == (1 << 10) ? 10 : \ - (n) == (1 << 11) ? 11 : \ - (n) == (1 << 12) ? 12 : \ - (n) == (1 << 13) ? 13 : \ - (n) == (1 << 14) ? 14 : \ - (n) == (1 << 15) ? 15 : \ - (n) == (1 << 16) ? 16 : \ - (n) == (1 << 17) ? 17 : \ - (n) == (1 << 18) ? 18 : \ - (n) == (1 << 19) ? 19 : \ - (n) == (1 << 20) ? 20 : \ - (n) == (1 << 21) ? 21 : \ - (n) == (1 << 22) ? 22 : \ - (n) == (1 << 23) ? 23 : \ - (n) == (1 << 24) ? 24 : \ - (n) == (1 << 25) ? 25 : \ - (n) == (1 << 26) ? 26 : \ - (n) == (1 << 27) ? 27 : \ - (n) == (1 << 28) ? 28 : \ - (n) == (1 << 29) ? 29 : \ - (n) == (1 << 30) ? 30 : \ - (n) == (1 << 31) ? 31 : \ - *(u32 *)NULL - -#define COMPRESS_BITS_0 0, 1 -#define COMPRESS_BITS_1 1, 1 -#define COMPRESS_BITS_2 2, 1 -#define COMPRESS_BITS_3 3, 1 -#define COMPRESS_BITS_4 4, 1 -#define COMPRESS_BITS_5 5, 1 -#define COMPRESS_BITS_6 6, 1 -#define COMPRESS_BITS_7 7, 1 - -/* Will try and compress a set bit (or up to three sequential bits) into a single byte -Input must be of the form (upper << lower) where upper can be up to 3, lower up to 31 */ -#define COMPRESS_BITS(_val) COMPRESS_BITS_STEP_2 _val -#define COMPRESS_BITS_STEP_2(_unpacked) COMPRESS_BITS_STEP_3(COMPRESS_BITS_## _unpacked) -#define COMPRESS_BITS_STEP_3(...) COMPRESS_BITS_STEP_4(__VA_ARGS__) -#define COMPRESS_BITS_STEP_4(upper, lower) (((upper % 8) << 5) + (BIT_INDEX(lower))) - -/* Will read a compressed bit stored by COMPRESS_BIT into a single byte */ -#define UNCOMPRESS_BITS(compressed) ((compressed >> 5) << (compressed & 0x1F)) - // There are many quirks in the source code which have overarching behavioral differences from // a number of other files. For example, diploma.c seems to declare rodata before each use while // other files declare out of order and must be at the beginning. There are also a number of @@ -180,9 +124,6 @@ Input must be of the form (upper << lower) where upper can be up to 3, lower up #define NUM_FLAG_BYTES ROUND_BITS_TO_BYTES(FLAGS_COUNT) #define NUM_TRENDY_SAYING_BYTES ROUND_BITS_TO_BYTES(NUM_TRENDY_SAYINGS) -// Converts a string to a compound literal, essentially making it a pointer to const u8 -#define COMPOUND_STRING(str) (const u8[]) _(str) - // This produces an error at compile-time if expr is zero. // It looks like file.c:line: size of array `id' is negative #define STATIC_ASSERT(expr, id) typedef char id[(expr) ? 1 : -1]; diff --git a/include/metaprogram.h b/include/metaprogram.h index f0d6d9a81f..eee79b73b1 100644 --- a/include/metaprogram.h +++ b/include/metaprogram.h @@ -17,6 +17,9 @@ #define STR(...) STR_(__VA_ARGS__) #define STR_(...) #__VA_ARGS__ +/* Converts a string to a compound literal, essentially making it a pointer to const u8 */ +#define COMPOUND_STRING(str) (const u8[]) _(str) + /* Expands to the first/second/third/fourth argument. */ #define FIRST(a, ...) a #define SECOND(a, ...) __VA_OPT__(FIRST(__VA_ARGS__)) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 47246d9356..df023953f4 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2806,11 +2806,9 @@ void SetMoveEffect(bool32 primary, bool32 certain) // Just in case this flag is still set gBattleScripting.moveEffect &= ~MOVE_EFFECT_CERTAIN; - if ((battlerAbility == ABILITY_SHIELD_DUST - || GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_COVERT_CLOAK) + if (!primary && affectsUser != MOVE_EFFECT_AFFECTS_USER && !(gHitMarker & HITMARKER_STATUS_ABILITY_EFFECT) - && !primary - && (gBattleScripting.moveEffect <= MOVE_EFFECT_TRI_ATTACK || gBattleScripting.moveEffect >= MOVE_EFFECT_SMACK_DOWN)) // Exclude stat lowering effects + && (battlerAbility == ABILITY_SHIELD_DUST || GetBattlerHoldEffect(gEffectBattler, TRUE) == HOLD_EFFECT_COVERT_CLOAK)) { if (battlerAbility == ABILITY_SHIELD_DUST) RecordAbilityBattle(gEffectBattler, battlerAbility); diff --git a/src/data/moves_info.h b/src/data/moves_info.h index f0abe00515..5fc35dba83 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -14969,9 +14969,8 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .ignoresSubstitute = TRUE, .metronomeBanned = TRUE, .sketchBanned = (B_SKETCH_BANS >= GEN_9), - .additionalEffects = ADDITIONAL_EFFECTS( + .additionalEffects = ADDITIONAL_EFFECTS({ // Feint move effect handled in script as it goes before animation - { .moveEffect = MOVE_EFFECT_DEF_MINUS_1, .self = TRUE, }), diff --git a/test/battle/ability/shield_dust.c b/test/battle/ability/shield_dust.c new file mode 100644 index 0000000000..4cd95de619 --- /dev/null +++ b/test/battle/ability/shield_dust.c @@ -0,0 +1,139 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Shield Dust blocks secondary effects") +{ + u16 move; + PARAMETRIZE { move = MOVE_NUZZLE; } + PARAMETRIZE { move = MOVE_INFERNO; } + PARAMETRIZE { move = MOVE_MORTAL_SPIN; } + PARAMETRIZE { move = MOVE_FAKE_OUT; } + PARAMETRIZE { move = MOVE_ROCK_TOMB; } + PARAMETRIZE { move = MOVE_SPIRIT_SHACKLE; } + PARAMETRIZE { move = MOVE_PSYCHIC_NOISE; } + + GIVEN { + ASSUME(MoveHasMoveEffectWithChance(MOVE_NUZZLE, MOVE_EFFECT_PARALYSIS, 100) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_INFERNO, MOVE_EFFECT_BURN, 100) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_MORTAL_SPIN, MOVE_EFFECT_POISON, 100) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_FAKE_OUT, MOVE_EFFECT_FLINCH, 100) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_ROCK_TOMB, MOVE_EFFECT_SPD_MINUS_1, 100) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_SPIRIT_SHACKLE, MOVE_EFFECT_PREVENT_ESCAPE, 100) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_PSYCHIC_NOISE, MOVE_EFFECT_PSYCHIC_NOISE, 100) == TRUE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + NONE_OF { + MESSAGE("Foe Vivillon is paralyzed! It may be unable to move!"); + MESSAGE("Foe Vivillon was burned!"); + MESSAGE("Foe Vivillon was poisoned!"); + MESSAGE("Foe Vivillon flinched!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); + MESSAGE("Foe Vivillon was prevented from healing!"); + } + } THEN { // Can't find good way to test trapping + EXPECT(!(opponent->status2 & STATUS2_ESCAPE_PREVENTION)); + } +} + +SINGLE_BATTLE_TEST("Shield Dust does not block primary effects") +{ + u16 move; + PARAMETRIZE { move = MOVE_INFESTATION; } + PARAMETRIZE { move = MOVE_THOUSAND_ARROWS; } + PARAMETRIZE { move = MOVE_JAW_LOCK; } + PARAMETRIZE { move = MOVE_PAY_DAY; } + + GIVEN { + ASSUME(MoveHasMoveEffectWithChance(MOVE_INFESTATION, MOVE_EFFECT_WRAP, 0) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_THOUSAND_ARROWS, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_JAW_LOCK, MOVE_EFFECT_TRAP_BOTH, 0) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_PAY_DAY, MOVE_EFFECT_PAYDAY, 0) == TRUE); + ASSUME(MoveHasMoveEffectWithChance(MOVE_SMACK_DOWN, MOVE_EFFECT_SMACK_DOWN, 0) == TRUE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); } + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + switch (move) + { + case MOVE_INFESTATION: + MESSAGE("Foe Vivillon has been afflicted with an infestation by Wobbuffet!"); + break; + case MOVE_THOUSAND_ARROWS: + MESSAGE("Foe Vivillon fell straight down!"); + break; + case MOVE_JAW_LOCK: + MESSAGE("Neither Pokémon can run away!"); + break; + case MOVE_PAY_DAY: + MESSAGE("Coins scattered everywhere!"); + break; + } + } THEN { // Can't find good way to test trapping + if (move == MOVE_JAW_LOCK) { + EXPECT(opponent->status2 & STATUS2_ESCAPE_PREVENTION); + EXPECT(player->status2 & STATUS2_ESCAPE_PREVENTION); + } + } +} + +SINGLE_BATTLE_TEST("Shield Dust does not block self-targeting effects, primary or secondary") +{ + u16 move; + PARAMETRIZE { move = MOVE_POWER_UP_PUNCH; } + PARAMETRIZE { move = MOVE_RAPID_SPIN; } + PARAMETRIZE { move = MOVE_LEAF_STORM; } + PARAMETRIZE { move = MOVE_METEOR_ASSAULT; } + + GIVEN { + ASSUME(MoveHasMoveEffectSelf(MOVE_POWER_UP_PUNCH, MOVE_EFFECT_ATK_PLUS_1) == TRUE); + ASSUME(MoveHasMoveEffectSelf(MOVE_RAPID_SPIN, MOVE_EFFECT_RAPIDSPIN) == TRUE); + ASSUME(MoveHasMoveEffectSelf(MOVE_LEAF_STORM, MOVE_EFFECT_SP_ATK_TWO_DOWN) == TRUE); + ASSUME(MoveHasMoveEffectSelf(MOVE_METEOR_ASSAULT, MOVE_EFFECT_RECHARGE) == TRUE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); } + } WHEN { + TURN { MOVE(player, move); } + if (move == MOVE_METEOR_ASSAULT) { + TURN { SKIP_TURN(player); } + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + HP_BAR(opponent); + switch (move) + { + case MOVE_POWER_UP_PUNCH: + case MOVE_RAPID_SPIN: + case MOVE_LEAF_STORM: + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + break; + case MOVE_METEOR_ASSAULT: // second turn + MESSAGE("Wobbuffet must recharge!"); + break; + } + } +} + +DOUBLE_BATTLE_TEST("Shield Dust does not block Sparkling Aria in doubles") +{ + KNOWN_FAILING; + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_VIVILLON) { Ability(ABILITY_SHIELD_DUST); Status1(STATUS1_BURN); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(playerLeft, MOVE_SPARKLING_ARIA); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPARKLING_ARIA, playerLeft); + MESSAGE("Foe Vivillion's burn was healed."); + STATUS_ICON(opponentLeft, burn: TRUE); + } +} From 273110ebae92b4e5a69ce2aec0bc33e39027520b Mon Sep 17 00:00:00 2001 From: PCG <75729017+PCG06@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:25:08 +0530 Subject: [PATCH 23/25] Jet Punch animation (#4067) * Jet Punch animation * Tabs * Jet Punch anim makeover * Fix anim glitch in doubles and whitespace --------- Co-authored-by: ghoulslash <41651341+ghoulslash@users.noreply.github.com> --- data/battle_anim_scripts.s | 43 +++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 0c29a1604f..b9bd3efaf0 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -17186,12 +17186,53 @@ Move_UPPER_HAND:: blendoff end +Move_JET_PUNCH: + loadspritegfx ANIM_TAG_ICE_CRYSTALS + loadspritegfx ANIM_TAG_HANDS_AND_FEET + loadspritegfx ANIM_TAG_IMPACT + loadspritegfx ANIM_TAG_SPLASH + loadspritegfx ANIM_TAG_WATER_IMPACT + loadspritegfx ANIM_TAG_SMALL_BUBBLES + monbg ANIM_DEF_PARTNER + setalpha 12, 8 + playsewithpan SE_M_DIVE, SOUND_PAN_TARGET + createvisualtask AnimTask_AttackerStretchAndDisappear, 2 + createvisualtask AnimTask_TranslateMonEllipticalRespectSide, 1, ANIM_ATTACKER, 24, 6, 1, 5 + createvisualtask AnimTask_TraceMonBlended, 2, 0, 4, 7, 3 + delay 18 + createvisualtask AnimTask_SetAttackerInvisibleWaitForSignal, 2 + createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 2, 0, 9, RGB_BLUE + delay 8 + createvisualtask AnimTask_ExtremeSpeedMonReappear, 2 + createsprite gSmallBubblePairSpriteTemplate, ANIM_TARGET, 2, 0x14, 0xffec, 0x14, ANIM_TARGET + createsprite gSmallBubblePairSpriteTemplate, ANIM_TARGET, 2, 0xa, 0xa, 0x14, ANIM_TARGET + createsprite gFistFootSpriteTemplate, ANIM_TARGET, 3, 0, 0, 8, 1, 0 + playsewithpan SE_M_DIVE, SOUND_PAN_TARGET + createsprite gBasicHitSplatSpriteTemplate, ANIM_TARGET, 2, 0, 0, ANIM_TARGET, 1 + createvisualtask AnimTask_ShakeMon, 2, ANIM_TARGET, 0, 3, 15, 1 + delay 6 + createsprite gSmallBubblePairSpriteTemplate, ANIM_TARGET, 2, 0x14, 0xffec, 0x14, ANIM_TARGET + createsprite gSmallBubblePairSpriteTemplate, ANIM_TARGET, 2, 0xa, 0xa, 0x14, ANIM_TARGET + createsprite gWaterHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 0, 13, ANIM_TARGET, 1 + createsprite gSmallDriftingBubblesSpriteTemplate, ANIM_ATTACKER, 4, 0, 13 + createsprite gSmallDriftingBubblesSpriteTemplate, ANIM_ATTACKER, 4, 0, 13 + delay 2 + createsprite gWaterHitSplatSpriteTemplate, ANIM_ATTACKER, 3, 0, 8, ANIM_TARGET, 1 + createsprite gSmallDriftingBubblesSpriteTemplate, ANIM_ATTACKER, 4, 0, 8 + createsprite gSmallDriftingBubblesSpriteTemplate, ANIM_ATTACKER, 4, 0, 8 + delay 2 + call DiveSetUpWaterDroplets + waitforvisualfinish + createvisualtask AnimTask_BlendBattleAnimPal, 10, F_PAL_TARGET, 0, 9, 0, RGB_BLUE + clearmonbg ANIM_DEF_PARTNER + blendoff + end + Move_TERA_BLAST:: Move_AXE_KICK:: Move_LAST_RESPECTS:: Move_LUMINA_CRASH:: Move_ORDER_UP:: -Move_JET_PUNCH:: Move_SPICY_EXTRACT:: Move_SPIN_OUT:: Move_POPULATION_BOMB:: From dd3228aa14981b817c0628f5d3d89ae1ecd0e6b6 Mon Sep 17 00:00:00 2001 From: Frank DeBlasio <35279583+fdeblasio@users.noreply.github.com> Date: Tue, 6 Feb 2024 06:55:49 -0500 Subject: [PATCH 24/25] Updated Mew teachable moves to SV (#4142) --- src/pokemon.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/pokemon.c b/src/pokemon.c index 0538d00b49..8bb215f901 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -5127,27 +5127,19 @@ u8 CanLearnTeachableMove(u16 species, u16 move) switch (move) { case MOVE_BADDY_BAD: - case MOVE_BLAST_BURN: case MOVE_BOUNCY_BUBBLE: case MOVE_BUZZY_BUZZ: - case MOVE_DRACO_METEOR: case MOVE_DRAGON_ASCENT: - case MOVE_FIRE_PLEDGE: case MOVE_FLOATY_FALL: case MOVE_FREEZY_FROST: - case MOVE_FRENZY_PLANT: case MOVE_GLITZY_GLOW: - case MOVE_GRASS_PLEDGE: - case MOVE_HYDRO_CANNON: case MOVE_RELIC_SONG: case MOVE_SAPPY_SEED: case MOVE_SECRET_SWORD: case MOVE_SIZZLY_SLIDE: case MOVE_SPARKLY_SWIRL: case MOVE_SPLISHY_SPLASH: - case MOVE_STEEL_BEAM: case MOVE_VOLT_TACKLE: - case MOVE_WATER_PLEDGE: case MOVE_ZIPPY_ZAP: return FALSE; default: From 7f50c0b9c35ea8f36da1d9afa73215b6ec10ae72 Mon Sep 17 00:00:00 2001 From: Frank DeBlasio <35279583+fdeblasio@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:24:36 -0500 Subject: [PATCH 25/25] Simplify gTrainerSprites (#4140) * Simplified y_offset equations * Removed trainer pic animation from gTrainerSprites * Used metaprogram to simplify trainer sprites without mugshots * Incorporated comments --------- Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com> --- include/data.h | 1 + src/battle_controller_link_opponent.c | 4 +- src/battle_controller_opponent.c | 4 +- src/battle_controller_player.c | 2 +- src/battle_controller_player_partner.c | 4 +- src/battle_controller_recorded_opponent.c | 4 +- src/battle_controller_recorded_player.c | 2 +- src/battle_controllers.c | 5 +- src/data.c | 4 + src/data/graphics/trainers.h | 195 +++++++++++----------- src/pokemon.c | 4 +- src/trainer_pokemon_sprites.c | 2 +- 12 files changed, 113 insertions(+), 118 deletions(-) diff --git a/include/data.h b/include/data.h index 09a1db7f7e..e80768f68c 100644 --- a/include/data.h +++ b/include/data.h @@ -123,6 +123,7 @@ extern const union AffineAnimCmd *const gAffineAnims_BattleSpriteContest[]; extern const union AnimCmd sAnim_GeneralFrame0[]; extern const union AnimCmd sAnim_GeneralFrame3[]; extern const union AnimCmd *const gAnims_MonPic[]; +extern const union AnimCmd *const sAnims_Trainer[]; extern const struct TrainerSprite gTrainerSprites[]; extern const struct TrainerBacksprite gTrainerBacksprites[]; diff --git a/src/battle_controller_link_opponent.c b/src/battle_controller_link_opponent.c index c9197bc5df..0c71d0a1da 100644 --- a/src/battle_controller_link_opponent.c +++ b/src/battle_controller_link_opponent.c @@ -462,9 +462,7 @@ static void LinkOpponentHandleDrawTrainerPic(u32 battler) } } - BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, - xPos, 40 + 4 * (8 - gTrainerSprites[trainerPicId].y_offset), - -1); + BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, xPos, 40, -1); } static void LinkOpponentHandleTrainerSlide(u32 battler) diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 4e272f4d0d..aeb13ec9a5 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -484,9 +484,7 @@ static void OpponentHandleDrawTrainerPic(u32 battler) xPos = 176; } - BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, - xPos, 40 + 4 * (8 - gTrainerSprites[trainerPicId].y_offset), - -1); + BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, xPos, 40, -1); } static void OpponentHandleTrainerSlide(u32 battler) diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index e70784e153..f1bdbdc668 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -1882,7 +1882,7 @@ static void PlayerHandleDrawTrainerPic(u32 battler) if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && gPartnerTrainerId < TRAINER_PARTNER(PARTNER_NONE)) { xPos = 90; - yPos = (8 - gTrainerSprites[trainerPicId].y_offset) * 4 + 80; + yPos = 80; } else { diff --git a/src/battle_controller_player_partner.c b/src/battle_controller_player_partner.c index 6ede6587b2..b9dbfdd2c6 100644 --- a/src/battle_controller_player_partner.c +++ b/src/battle_controller_player_partner.c @@ -307,13 +307,13 @@ static void PlayerPartnerHandleDrawTrainerPic(u32 battler) { trainerPicId = gTrainers[gPartnerTrainerId].trainerPic; xPos = 60; - yPos = (8 - gTrainerSprites[trainerPicId].y_offset) * 4 + 80; + yPos = 80; } else { trainerPicId = GetFrontierTrainerFrontSpriteId(gPartnerTrainerId); xPos = 32; - yPos = (8 - gTrainerSprites[trainerPicId].y_offset) * 4 + 80; + yPos = 80; } // Use back pic only if the partner Steven or is custom. diff --git a/src/battle_controller_recorded_opponent.c b/src/battle_controller_recorded_opponent.c index 36caa14c14..abadcc231c 100644 --- a/src/battle_controller_recorded_opponent.c +++ b/src/battle_controller_recorded_opponent.c @@ -420,9 +420,7 @@ static void RecordedOpponentHandleDrawTrainerPic(u32 battler) } } - BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, - xPos, 40 + 4 * (8 - gTrainerSprites[trainerPicId].y_offset), - -1); + BtlController_HandleDrawTrainerPic(battler, trainerPicId, TRUE, xPos, 40, -1); } static void RecordedOpponentHandleTrainerSlideBack(u32 battler) diff --git a/src/battle_controller_recorded_player.c b/src/battle_controller_recorded_player.c index b8322b3eaf..53860990c4 100644 --- a/src/battle_controller_recorded_player.c +++ b/src/battle_controller_recorded_player.c @@ -393,7 +393,7 @@ static void RecordedPlayerHandleDrawTrainerPic(u32 battler) if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) { xPos = 90; - yPos = (8 - gTrainerSprites[trainerPicId].y_offset) * 4 + 80; + yPos = 80; } else { diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 27623c97bc..a7d9610dac 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -2542,10 +2542,7 @@ void BtlController_HandleTrainerSlide(u32 battler, u32 trainerPicId) { DecompressTrainerFrontPic(trainerPicId, battler); SetMultiuseSpriteTemplateToTrainerBack(trainerPicId, GetBattlerPosition(battler)); - gBattlerSpriteIds[battler] = CreateSprite(&gMultiuseSpriteTemplate, - 176, - (8 - gTrainerSprites[trainerPicId].y_offset) * 4 + 40, - 30); + gBattlerSpriteIds[battler] = CreateSprite(&gMultiuseSpriteTemplate, 176, 40, 30); gSprites[gBattlerSpriteIds[battler]].oam.affineParam = trainerPicId; gSprites[gBattlerSpriteIds[battler]].oam.paletteNum = IndexOfSpritePaletteTag(gTrainerSprites[trainerPicId].palette.tag); gSprites[gBattlerSpriteIds[battler]].x2 = 96; diff --git a/src/data.c b/src/data.c index f559656d35..074b067ac9 100644 --- a/src/data.c +++ b/src/data.c @@ -220,5 +220,9 @@ const union AnimCmd *const gAnims_MonPic[MAX_MON_PIC_FRAMES] = sAnim_MonPic_1, }; +const union AnimCmd *const sAnims_Trainer[] ={ + sAnim_GeneralFrame0, +}; + #include "data/trainer_parties.h" #include "data/trainers.h" diff --git a/src/data/graphics/trainers.h b/src/data/graphics/trainers.h index e20d13ec16..309fd0b80c 100644 --- a/src/data/graphics/trainers.h +++ b/src/data/graphics/trainers.h @@ -292,116 +292,115 @@ const u8 gTrainerBackPic_Steven[] = INCBIN_U8("graphics/trainers/back_pics/steve const u32 gTrainerBackPicPalette_Red[] = INCBIN_U32("graphics/trainers/back_pics/red.gbapal.lz"); const u32 gTrainerBackPicPalette_Leaf[] = INCBIN_U32("graphics/trainers/back_pics/leaf.gbapal.lz"); -static const union AnimCmd *const sAnims_Trainer[] ={ - sAnim_GeneralFrame0, -}; - -#define TRAINER_SPRITE(trainerPic, file, x, y, rotation) \ +// The first two parameters invoke a front pic and palette by +// calling a "TRAINER_PIC" constant (e.g. TRAINER_PIC_HIKER), and +// gTrainerFrontPic/gTrainerPalette pointers, (e.g "gTrainerFrontPic_Hiker" and "gTrainerPalette_Hiker"). +// The last three parameters control the X and Y coordinates and rotation of the mugshot on the screen. +// They default to 0, 0, and 0x200 which are default values used by the majority of the game's trainer sprites. +#define TRAINER_SPRITE(trainerPic, file, ...) \ [TRAINER_PIC_##trainerPic] = \ { \ - .y_offset = 8, \ .frontPic = {gTrainerFrontPic_##file, TRAINER_PIC_SIZE, TRAINER_PIC_##trainerPic},\ .palette = {gTrainerPalette_##file, TRAINER_PIC_##trainerPic}, \ - .animation = sAnims_Trainer, \ - .mugshotCoords = {x, y}, \ - .mugshotRotation = rotation, \ + .mugshotCoords = {DEFAULT(0, __VA_ARGS__), DEFAULT_2(0, __VA_ARGS__)}, \ + .mugshotRotation = DEFAULT_3(0x200, __VA_ARGS__), \ } const struct TrainerSprite gTrainerSprites[] = { - TRAINER_SPRITE(HIKER, Hiker, 0, 0, 0x200), - TRAINER_SPRITE(AQUA_GRUNT_M, AquaGruntM, 0, 0, 0x200), - TRAINER_SPRITE(POKEMON_BREEDER_F, PokemonBreederF, 0, 0, 0x200), - TRAINER_SPRITE(COOLTRAINER_M, CoolTrainerM, 0, 0, 0x200), - TRAINER_SPRITE(BIRD_KEEPER, BirdKeeper, 0, 0, 0x200), - TRAINER_SPRITE(COLLECTOR, Collector, 0, 0, 0x200), - TRAINER_SPRITE(AQUA_GRUNT_F, AquaGruntF, 0, 0, 0x200), - TRAINER_SPRITE(SWIMMER_M, SwimmerM, 0, 0, 0x200), - TRAINER_SPRITE(MAGMA_GRUNT_M, MagmaGruntM, 0, 0, 0x200), - TRAINER_SPRITE(EXPERT_M, ExpertM, 0, 0, 0x200), - TRAINER_SPRITE(AQUA_ADMIN_M, AquaAdminM, 0, 0, 0x200), - TRAINER_SPRITE(BLACK_BELT, BlackBelt, 0, 0, 0x200), - TRAINER_SPRITE(AQUA_ADMIN_F, AquaAdminF, 0, 0, 0x200), - TRAINER_SPRITE(AQUA_LEADER_ARCHIE, AquaLeaderArchie, 0, 0, 0x200), - TRAINER_SPRITE(HEX_MANIAC, HexManiac, 0, 0, 0x200), - TRAINER_SPRITE(AROMA_LADY, AromaLady, 0, 0, 0x200), - TRAINER_SPRITE(RUIN_MANIAC, RuinManiac, 0, 0, 0x200), - TRAINER_SPRITE(INTERVIEWER, Interviewer, 0, 0, 0x200), - TRAINER_SPRITE(TUBER_F, TuberF, 0, 0, 0x200), - TRAINER_SPRITE(TUBER_M, TuberM, 0, 0, 0x200), - TRAINER_SPRITE(COOLTRAINER_F, CoolTrainerF, 0, 0, 0x200), - TRAINER_SPRITE(LADY, Lady, 0, 0, 0x200), - TRAINER_SPRITE(BEAUTY, Beauty, 0, 0, 0x200), - TRAINER_SPRITE(RICH_BOY, RichBoy, 0, 0, 0x200), - TRAINER_SPRITE(EXPERT_F, ExpertF, 0, 0, 0x200), - TRAINER_SPRITE(POKEMANIAC, Pokemaniac, 0, 0, 0x200), - TRAINER_SPRITE(MAGMA_GRUNT_F, MagmaGruntF, 0, 0, 0x200), - TRAINER_SPRITE(GUITARIST, Guitarist, 0, 0, 0x200), - TRAINER_SPRITE(KINDLER, Kindler, 0, 0, 0x200), - TRAINER_SPRITE(CAMPER, Camper, 0, 0, 0x200), - TRAINER_SPRITE(PICNICKER, Picnicker, 0, 0, 0x200), - TRAINER_SPRITE(BUG_MANIAC, BugManiac, 0, 0, 0x200), - TRAINER_SPRITE(POKEMON_BREEDER_M, PokemonBreederM, 0, 0, 0x200), - TRAINER_SPRITE(PSYCHIC_M, PsychicM, 0, 0, 0x200), - TRAINER_SPRITE(PSYCHIC_F, PsychicF, 0, 0, 0x200), - TRAINER_SPRITE(GENTLEMAN, Gentleman, 0, 0, 0x200), - TRAINER_SPRITE(ELITE_FOUR_SIDNEY, EliteFourSidney, 0, 0, 0x200), - TRAINER_SPRITE(ELITE_FOUR_PHOEBE, EliteFourPhoebe, 0, 0, 0x200), + TRAINER_SPRITE(HIKER, Hiker), + TRAINER_SPRITE(AQUA_GRUNT_M, AquaGruntM), + TRAINER_SPRITE(POKEMON_BREEDER_F, PokemonBreederF), + TRAINER_SPRITE(COOLTRAINER_M, CoolTrainerM), + TRAINER_SPRITE(BIRD_KEEPER, BirdKeeper), + TRAINER_SPRITE(COLLECTOR, Collector), + TRAINER_SPRITE(AQUA_GRUNT_F, AquaGruntF), + TRAINER_SPRITE(SWIMMER_M, SwimmerM), + TRAINER_SPRITE(MAGMA_GRUNT_M, MagmaGruntM), + TRAINER_SPRITE(EXPERT_M, ExpertM), + TRAINER_SPRITE(AQUA_ADMIN_M, AquaAdminM), + TRAINER_SPRITE(BLACK_BELT, BlackBelt), + TRAINER_SPRITE(AQUA_ADMIN_F, AquaAdminF), + TRAINER_SPRITE(AQUA_LEADER_ARCHIE, AquaLeaderArchie), + TRAINER_SPRITE(HEX_MANIAC, HexManiac), + TRAINER_SPRITE(AROMA_LADY, AromaLady), + TRAINER_SPRITE(RUIN_MANIAC, RuinManiac), + TRAINER_SPRITE(INTERVIEWER, Interviewer), + TRAINER_SPRITE(TUBER_F, TuberF), + TRAINER_SPRITE(TUBER_M, TuberM), + TRAINER_SPRITE(COOLTRAINER_F, CoolTrainerF), + TRAINER_SPRITE(LADY, Lady), + TRAINER_SPRITE(BEAUTY, Beauty), + TRAINER_SPRITE(RICH_BOY, RichBoy), + TRAINER_SPRITE(EXPERT_F, ExpertF), + TRAINER_SPRITE(POKEMANIAC, Pokemaniac), + TRAINER_SPRITE(MAGMA_GRUNT_F, MagmaGruntF), + TRAINER_SPRITE(GUITARIST, Guitarist), + TRAINER_SPRITE(KINDLER, Kindler), + TRAINER_SPRITE(CAMPER, Camper), + TRAINER_SPRITE(PICNICKER, Picnicker), + TRAINER_SPRITE(BUG_MANIAC, BugManiac), + TRAINER_SPRITE(POKEMON_BREEDER_M, PokemonBreederM), + TRAINER_SPRITE(PSYCHIC_M, PsychicM), + TRAINER_SPRITE(PSYCHIC_F, PsychicF), + TRAINER_SPRITE(GENTLEMAN, Gentleman), + TRAINER_SPRITE(ELITE_FOUR_SIDNEY, EliteFourSidney), + TRAINER_SPRITE(ELITE_FOUR_PHOEBE, EliteFourPhoebe), TRAINER_SPRITE(ELITE_FOUR_GLACIA, EliteFourGlacia, -4, 4, 0x1B0), TRAINER_SPRITE(ELITE_FOUR_DRAKE, EliteFourDrake, 0, 5, 0x1A0), - TRAINER_SPRITE(LEADER_ROXANNE, LeaderRoxanne, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_BRAWLY, LeaderBrawly, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_WATTSON, LeaderWattson, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_FLANNERY, LeaderFlannery, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_NORMAN, LeaderNorman, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_WINONA, LeaderWinona, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_TATE_AND_LIZA, LeaderTateAndLiza, 0, 0, 0x200), - TRAINER_SPRITE(LEADER_JUAN, LeaderJuan, 0, 0, 0x200), - TRAINER_SPRITE(SCHOOL_KID_M, SchoolKidM, 0, 0, 0x200), - TRAINER_SPRITE(SCHOOL_KID_F, SchoolKidF, 0, 0, 0x200), - TRAINER_SPRITE(SR_AND_JR, SrAndJr, 0, 0, 0x200), - TRAINER_SPRITE(POKEFAN_M, PokefanM, 0, 0, 0x200), - TRAINER_SPRITE(POKEFAN_F, PokefanF, 0, 0, 0x200), - TRAINER_SPRITE(YOUNGSTER, Youngster, 0, 0, 0x200), + TRAINER_SPRITE(LEADER_ROXANNE, LeaderRoxanne), + TRAINER_SPRITE(LEADER_BRAWLY, LeaderBrawly), + TRAINER_SPRITE(LEADER_WATTSON, LeaderWattson), + TRAINER_SPRITE(LEADER_FLANNERY, LeaderFlannery), + TRAINER_SPRITE(LEADER_NORMAN, LeaderNorman), + TRAINER_SPRITE(LEADER_WINONA, LeaderWinona), + TRAINER_SPRITE(LEADER_TATE_AND_LIZA, LeaderTateAndLiza), + TRAINER_SPRITE(LEADER_JUAN, LeaderJuan), + TRAINER_SPRITE(SCHOOL_KID_M, SchoolKidM), + TRAINER_SPRITE(SCHOOL_KID_F, SchoolKidF), + TRAINER_SPRITE(SR_AND_JR, SrAndJr), + TRAINER_SPRITE(POKEFAN_M, PokefanM), + TRAINER_SPRITE(POKEFAN_F, PokefanF), + TRAINER_SPRITE(YOUNGSTER, Youngster), TRAINER_SPRITE(CHAMPION_WALLACE, ChampionWallace, -8, 7, 0x188), - TRAINER_SPRITE(FISHERMAN, Fisherman, 0, 0, 0x200), - TRAINER_SPRITE(CYCLING_TRIATHLETE_M, CyclingTriathleteM, 0, 0, 0x200), - TRAINER_SPRITE(CYCLING_TRIATHLETE_F, CyclingTriathleteF, 0, 0, 0x200), - TRAINER_SPRITE(RUNNING_TRIATHLETE_M, RunningTriathleteM, 0, 0, 0x200), - TRAINER_SPRITE(RUNNING_TRIATHLETE_F, RunningTriathleteF, 0, 0, 0x200), - TRAINER_SPRITE(SWIMMING_TRIATHLETE_M, SwimmingTriathleteM, 0, 0, 0x200), - TRAINER_SPRITE(SWIMMING_TRIATHLETE_F, SwimmingTriathleteF, 0, 0, 0x200), - TRAINER_SPRITE(DRAGON_TAMER, DragonTamer, 0, 0, 0x200), - TRAINER_SPRITE(NINJA_BOY, NinjaBoy, 0, 0, 0x200), - TRAINER_SPRITE(BATTLE_GIRL, BattleGirl, 0, 0, 0x200), - TRAINER_SPRITE(PARASOL_LADY, ParasolLady, 0, 0, 0x200), - TRAINER_SPRITE(SWIMMER_F, SwimmerF, 0, 0, 0x200), - TRAINER_SPRITE(TWINS, Twins, 0, 0, 0x200), - TRAINER_SPRITE(SAILOR, Sailor, 0, 0, 0x200), - TRAINER_SPRITE(MAGMA_ADMIN, MagmaAdmin, 0, 0, 0x200), - TRAINER_SPRITE(WALLY, Wally, 0, 0, 0x200), - TRAINER_SPRITE(BRENDAN, Brendan, 0, 0, 0x200), - TRAINER_SPRITE(MAY, May, 0, 0, 0x200), - TRAINER_SPRITE(BUG_CATCHER, BugCatcher, 0, 0, 0x200), - TRAINER_SPRITE(POKEMON_RANGER_M, PokemonRangerM, 0, 0, 0x200), - TRAINER_SPRITE(POKEMON_RANGER_F, PokemonRangerF, 0, 0, 0x200), - TRAINER_SPRITE(MAGMA_LEADER_MAXIE, MagmaLeaderMaxie, 0, 0, 0x200), - TRAINER_SPRITE(LASS, Lass, 0, 0, 0x200), - TRAINER_SPRITE(YOUNG_COUPLE, YoungCouple, 0, 0, 0x200), - TRAINER_SPRITE(OLD_COUPLE, OldCouple, 0, 0, 0x200), - TRAINER_SPRITE(SIS_AND_BRO, SisAndBro, 0, 0, 0x200), + TRAINER_SPRITE(FISHERMAN, Fisherman), + TRAINER_SPRITE(CYCLING_TRIATHLETE_M, CyclingTriathleteM), + TRAINER_SPRITE(CYCLING_TRIATHLETE_F, CyclingTriathleteF), + TRAINER_SPRITE(RUNNING_TRIATHLETE_M, RunningTriathleteM), + TRAINER_SPRITE(RUNNING_TRIATHLETE_F, RunningTriathleteF), + TRAINER_SPRITE(SWIMMING_TRIATHLETE_M, SwimmingTriathleteM), + TRAINER_SPRITE(SWIMMING_TRIATHLETE_F, SwimmingTriathleteF), + TRAINER_SPRITE(DRAGON_TAMER, DragonTamer), + TRAINER_SPRITE(NINJA_BOY, NinjaBoy), + TRAINER_SPRITE(BATTLE_GIRL, BattleGirl), + TRAINER_SPRITE(PARASOL_LADY, ParasolLady), + TRAINER_SPRITE(SWIMMER_F, SwimmerF), + TRAINER_SPRITE(TWINS, Twins), + TRAINER_SPRITE(SAILOR, Sailor), + TRAINER_SPRITE(MAGMA_ADMIN, MagmaAdmin), + TRAINER_SPRITE(WALLY, Wally), + TRAINER_SPRITE(BRENDAN, Brendan), + TRAINER_SPRITE(MAY, May), + TRAINER_SPRITE(BUG_CATCHER, BugCatcher), + TRAINER_SPRITE(POKEMON_RANGER_M, PokemonRangerM), + TRAINER_SPRITE(POKEMON_RANGER_F, PokemonRangerF), + TRAINER_SPRITE(MAGMA_LEADER_MAXIE, MagmaLeaderMaxie), + TRAINER_SPRITE(LASS, Lass), + TRAINER_SPRITE(YOUNG_COUPLE, YoungCouple), + TRAINER_SPRITE(OLD_COUPLE, OldCouple), + TRAINER_SPRITE(SIS_AND_BRO, SisAndBro), TRAINER_SPRITE(STEVEN, Steven, 0, 7, 0x188), - TRAINER_SPRITE(SALON_MAIDEN_ANABEL, SalonMaidenAnabel, 0, 0, 0x200), - TRAINER_SPRITE(DOME_ACE_TUCKER, DomeAceTucker, 0, 0, 0x200), - TRAINER_SPRITE(PALACE_MAVEN_SPENSER, PalaceMavenSpenser, 0, 0, 0x200), - TRAINER_SPRITE(ARENA_TYCOON_GRETA, ArenaTycoonGreta, 0, 0, 0x200), - TRAINER_SPRITE(FACTORY_HEAD_NOLAND, FactoryHeadNoland, 0, 0, 0x200), - TRAINER_SPRITE(PIKE_QUEEN_LUCY, PikeQueenLucy, 0, 0, 0x200), - TRAINER_SPRITE(PYRAMID_KING_BRANDON, PyramidKingBrandon, 0, 0, 0x200), - TRAINER_SPRITE(RED, Red, 0, 0, 0x200), - TRAINER_SPRITE(LEAF, Leaf, 0, 0, 0x200), - TRAINER_SPRITE(RS_BRENDAN, RubySapphireBrendan, 0, 0, 0x200), - TRAINER_SPRITE(RS_MAY, RubySapphireMay, 0, 0, 0x200), + TRAINER_SPRITE(SALON_MAIDEN_ANABEL, SalonMaidenAnabel), + TRAINER_SPRITE(DOME_ACE_TUCKER, DomeAceTucker), + TRAINER_SPRITE(PALACE_MAVEN_SPENSER, PalaceMavenSpenser), + TRAINER_SPRITE(ARENA_TYCOON_GRETA, ArenaTycoonGreta), + TRAINER_SPRITE(FACTORY_HEAD_NOLAND, FactoryHeadNoland), + TRAINER_SPRITE(PIKE_QUEEN_LUCY, PikeQueenLucy), + TRAINER_SPRITE(PYRAMID_KING_BRANDON, PyramidKingBrandon), + TRAINER_SPRITE(RED, Red), + TRAINER_SPRITE(LEAF, Leaf), + TRAINER_SPRITE(RS_BRENDAN, RubySapphireBrendan), + TRAINER_SPRITE(RS_MAY, RubySapphireMay), }; static const union AnimCmd sAnimCmd_Hoenn[] = diff --git a/src/pokemon.c b/src/pokemon.c index 8bb215f901..da5bb15175 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -1927,7 +1927,7 @@ void SetMultiuseSpriteTemplateToTrainerBack(u16 trainerPicId, u8 battlerPosition gMultiuseSpriteTemplate = gMonSpritesGfxPtr->templates[battlerPosition]; else gMultiuseSpriteTemplate = gBattlerSpriteTemplates[battlerPosition]; - gMultiuseSpriteTemplate.anims = gTrainerSprites[trainerPicId].animation; + gMultiuseSpriteTemplate.anims = sAnims_Trainer; } } @@ -1939,7 +1939,7 @@ void SetMultiuseSpriteTemplateToTrainerFront(u16 trainerPicId, u8 battlerPositio gMultiuseSpriteTemplate = gBattlerSpriteTemplates[battlerPosition]; gMultiuseSpriteTemplate.paletteTag = trainerPicId; - gMultiuseSpriteTemplate.anims = gTrainerSprites[trainerPicId].animation; + gMultiuseSpriteTemplate.anims = sAnims_Trainer; } static void EncryptBoxMon(struct BoxPokemon *boxMon) diff --git a/src/trainer_pokemon_sprites.c b/src/trainer_pokemon_sprites.c index cfa013620a..06b21d05cf 100644 --- a/src/trainer_pokemon_sprites.c +++ b/src/trainer_pokemon_sprites.c @@ -116,7 +116,7 @@ static void AssignSpriteAnimsTable(bool8 isTrainer) if (!isTrainer) sCreatingSpriteTemplate.anims = gAnims_MonPic; else - sCreatingSpriteTemplate.anims = gTrainerSprites[0].animation; + sCreatingSpriteTemplate.anims = sAnims_Trainer; } static u16 CreatePicSprite(u16 species, bool8 isShiny, u32 personality, bool8 isFrontPic, s16 x, s16 y, u8 paletteSlot, u16 paletteTag, bool8 isTrainer)