diff --git a/.all-contributorsrc b/.all-contributorsrc index a441c1abc7..b80a18d4c5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -581,10 +581,10 @@ ] }, { - "login": "izrofid", - "name": "Kildemal", + "login": "miriamlefae", + "name": "Miriam", "avatar_url": "https://avatars.githubusercontent.com/u/206095739?v=4", - "profile": "https://github.com/izrofid", + "profile": "https://github.com/miriamlefae", "contributions": [ "code" ] @@ -715,6 +715,15 @@ "contributions": [ "code" ] + }, + { + "login": "Gastly92", + "name": "Gastly92", + "avatar_url": "https://avatars.githubusercontent.com/u/262681076?v=4", + "profile": "https://github.com/Gastly92", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 42a31171b7..dc13c04856 100644 --- a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml +++ b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml @@ -43,9 +43,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.16.0 (Latest release) + - 1.16.1 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.16.0 - 1.15.3 - 1.15.2 - 1.15.1 diff --git a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml index 28943effda..48f3793e6d 100644 --- a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml +++ b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml @@ -43,9 +43,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.16.0 (Latest release) + - 1.16.1 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.16.0 - 1.15.3 - 1.15.2 - 1.15.1 diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index cda4d6dc2f..3c7bd9cf70 100644 --- a/.github/ISSUE_TEMPLATE/04_other_errors.yaml +++ b/.github/ISSUE_TEMPLATE/04_other_errors.yaml @@ -43,9 +43,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using? options: - - 1.16.0 (Latest release) + - 1.16.1 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.16.0 - 1.15.3 - 1.15.2 - 1.15.1 diff --git a/CREDITS.md b/CREDITS.md index ac6209db3b..f761d3f086 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -1,6 +1,6 @@ ## Credits ✨ -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/en/reference/emoji-key/)): @@ -102,6 +102,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d blusunrize
blusunrize

🐛 💻 jtebbe
jtebbe

💻 Liam
Liam

💻 + Gastly92
Gastly92

💻 @@ -119,7 +120,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +This project follows the [all-contributors](https://github.com/all-contributors/allcontributors.org) specification. Contributions of any kind welcome! ## Other Credits ### Mega Evolution Overworld Sprite Credits: diff --git a/Makefile b/Makefile index d4c75585b4..37249891fa 100644 --- a/Makefile +++ b/Makefile @@ -105,8 +105,8 @@ ASSETS_DIR_NAME := $(BUILD_DIR)/assets ELF_NAME := $(ROM_NAME:.gba=.elf) MAP_NAME := $(ROM_NAME:.gba=.map) -TESTELF = $(ROM_NAME:.gba=-test.elf) -HEADLESSELF = $(ROM_NAME:.gba=-test-headless.elf) +TESTELF := $(ROM_NAME:.gba=-test.elf) +HEADLESSELF := $(ROM_NAME:.gba=-test-headless.elf) # Pick our active variables ROM := $(ROM_NAME) diff --git a/README.md b/README.md index c768a6f5d8..0c4eac3dc1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you use **`pokeemerald-expansion`**, please credit **RHH (Rom Hacking Hideout)**. Optionally, include the version number for clarity. ``` -Based off RHH's pokeemerald-expansion 1.16.0 https://github.com/rh-hideout/pokeemerald-expansion/ +Based off RHH's pokeemerald-expansion 1.16.1 https://github.com/rh-hideout/pokeemerald-expansion/ ``` Please consider [crediting all contributors](CREDITS.md) involved in the project! diff --git a/charmap.txt b/charmap.txt index 24fbba0d17..348f00cfb2 100644 --- a/charmap.txt +++ b/charmap.txt @@ -432,7 +432,7 @@ B_EFF_TEAM2 = FD 47 NAME_END = FC 00 @ special 0xF7 character -DYNAMIC = F7 +DYNAMIC = F7 @ more text functions diff --git a/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc b/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc index 6cd428c8ed..920f912a9e 100644 --- a/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc +++ b/data/maps/BattleFrontier_BattleTowerMultiPartnerRoom/scripts.inc @@ -126,7 +126,7 @@ BattleFrontier_BattleTowerMultiPartnerRoom_EventScript_MoveToElevatorEast: @ Unused BattleFrontier_BattleTowerMultiPartnerRoom_EventScript_MoveToElevatorWest: applymovement LOCALID_TOWER_PARTNER_ROOM_ATTENDANT, BattleFrontier_BattleTowerMultiPartnerRoom_Movement_AttendantEnterElevator - applymovement LOCALID_PLAYER, BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEneterElevatorWest + applymovement LOCALID_PLAYER, BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEnterElevatorWest waitmovement 0 return @@ -144,7 +144,7 @@ BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEnterElevatorEast: step_end @ Functionally unused -BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEneterElevatorWest: +BattleFrontier_BattleTowerMultiPartnerRoom_Movement_PlayerEnterElevatorWest: walk_left walk_up set_invisible diff --git a/data/maps/MtChimney/scripts.inc b/data/maps/MtChimney/scripts.inc index cdff230d77..cf0fde9738 100644 --- a/data/maps/MtChimney/scripts.inc +++ b/data/maps/MtChimney/scripts.inc @@ -471,7 +471,7 @@ MtChimney_EventScript_MachineOff:: end MtChimney_EventScript_MachineOn:: - msgbox MtChimney_Text_MetoriteFittedOnMachine, MSGBOX_DEFAULT + msgbox MtChimney_Text_MeteoriteFittedOnMachine, MSGBOX_DEFAULT releaseall end @@ -726,7 +726,7 @@ MtChimney_Text_YouveNotGotTheMoney: MtChimney_Text_OhFineThen: .string "Oh, fine then.$" -MtChimney_Text_MetoriteFittedOnMachine: +MtChimney_Text_MeteoriteFittedOnMachine: .string "A METEORITE is fitted on a mysterious\n" .string "machine…\p" .string "The machine seems to be storing\n" diff --git a/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc b/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc index b100438f55..cd5c6c6806 100644 --- a/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc +++ b/data/maps/Route124_DivingTreasureHuntersHouse/scripts.inc @@ -328,11 +328,11 @@ Route124_DivingTreasureHuntersHouse_Text_ComeBackIfYouChangeMind: .string "Well, if you change your mind, come back.$" Route124_DivingTreasureHuntersHouse_Text_ShardTradeBoard: - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x0f}RED SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x7b}FIRE STONE{CLEAR_TO 0xc8}\p" - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x06}YELLOW SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x73}THUNDERSTONE{CLEAR_TO 0xc8}\p" - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x0c}BLUE SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x79}WATER STONE{CLEAR_TO 0xc8}\p" - .string "{CLEAR_TO 0x0a}Wanted item{CLEAR_TO 0x7c}Trade item\n" - .string "{CLEAR_TO 0x08}GREEN SHARD{CLEAR_TO 0x59}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 0x7b}LEAF STONE$" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 15}RED SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 123}FIRE STONE{CLEAR_TO 200}\p" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 6}YELLOW SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 115}THUNDERSTONE{CLEAR_TO 200}\p" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 12}BLUE SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 121}WATER STONE{CLEAR_TO 200}\p" + .string "{CLEAR_TO 10}Wanted item{CLEAR_TO 124}Trade item\n" + .string "{CLEAR_TO 8}GREEN SHARD{CLEAR_TO 89}{LEFT_ARROW}{RIGHT_ARROW}{CLEAR_TO 123}LEAF STONE$" diff --git a/data/scripts/cable_club_frlg.inc b/data/scripts/cable_club_frlg.inc index bd2f91a412..bba62dda1d 100644 --- a/data/scripts/cable_club_frlg.inc +++ b/data/scripts/cable_club_frlg.inc @@ -298,7 +298,7 @@ CableClub_EventScript_EnterColosseum_Frlg:: release goto_if_eq VAR_0x8004, USING_MULTI_BATTLE, CableClub_EventScript_WarpTo4PColosseum_Frlg special SetCableClubWarp - warp MAP_BATTLE_COLOSSEUM_2P, 6, 8 + warp MAP_BATTLE_COLOSSEUM_2P_FRLG, 6, 8 special DoCableClubWarp end @@ -310,7 +310,7 @@ CableClub_EventScript_PlayerApproachLinkRoomRight_Frlg:: CableClub_EventScript_WarpTo4PColosseum_Frlg:: special SetCableClubWarp - warp MAP_BATTLE_COLOSSEUM_4P, 5, 8 + warp MAP_BATTLE_COLOSSEUM_4P_FRLG, 5, 8 special DoCableClubWarp end diff --git a/data/scripts/mart_clerk.inc b/data/scripts/mart_clerk.inc index 2b9f872e85..a947ce1711 100644 --- a/data/scripts/mart_clerk.inc +++ b/data/scripts/mart_clerk.inc @@ -6,7 +6,7 @@ gText_PleaseComeAgain:: .string "Please come again!$" gText_PlayerWhatCanIDoForYou:: - .string "{PLAYER}{STRING 5}, welcome!\p" + .string "{PLAYER}{KUN}, welcome!\p" .string "What can I do for you?$" Pokemart_DefaultItemList:: diff --git a/data/scripts/std_msgbox.inc b/data/scripts/std_msgbox.inc index 541ec384d1..cb95b5ebf7 100644 --- a/data/scripts/std_msgbox.inc +++ b/data/scripts/std_msgbox.inc @@ -33,7 +33,7 @@ Std_ReceivedItem:: textcolor NPC_TEXT_COLOR_NEUTRAL call_if_eq VAR_0x8002, MUS_LEVEL_UP, EventScript_ReceivedItemFanfare1 call_if_eq VAR_0x8002, MUS_RG_OBTAIN_KEY_ITEM, EventScript_ReceivedItemFanfare2 - message 0x0 + message NULL waitmessage waitfanfare call_if_eq VAR_0x8002, MUS_LEVEL_UP, EventScript_ReceivedItemWaitFanfare diff --git a/data/text/lottery_corner.inc b/data/text/lottery_corner.inc index 44571ef562..e86cdff59c 100644 --- a/data/text/lottery_corner.inc +++ b/data/text/lottery_corner.inc @@ -16,7 +16,7 @@ LilycoveCity_DepartmentStore_1F_Text_PleaseVisitAgain: LilycoveCity_DepartmentStore_1F_Text_PleasePickTicket: .string "Please pick a LOTO TICKET.\n" - .string "…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}…{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}{PAUSE 0x0F}$" + .string "…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}…{PAUSE 15}{PAUSE 15}{PAUSE 15}{PAUSE 15}$" LilycoveCity_DepartmentStore_1F_Text_TicketNumberIsXPleaseWait: .string "The LOTO TICKET number is {STR_VAR_1}.\p" diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 807404bff7..5deb27670e 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -58,6 +58,7 @@ - [How to use dynamic trainer battle scripts](tutorials/how_to_dynamic_trainer_script.md) - [Changelog](./CHANGELOG.md) - [1.16.x]() + - [Version 1.16.1](changelogs/1.16.x/1.16.1.md) - [Version 1.16.0](changelogs/1.16.x/1.16.0.md) - [1.15.x]() - [Version 1.15.3](changelogs/1.15.x/1.15.3.md) diff --git a/docs/changelogs/1.16.x/1.16.1.md b/docs/changelogs/1.16.x/1.16.1.md new file mode 100644 index 0000000000..4ab9c54104 --- /dev/null +++ b/docs/changelogs/1.16.x/1.16.1.md @@ -0,0 +1,90 @@ +```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.16.1 +`. +``` + + +## 🧬 General 🧬 +### Added +* Add `if_comptime` by @mrgriffin in [#10130](https://github.com/rh-hideout/pokeemerald-expansion/pull/10130) + +### Changed +* Cleanup 'message 0x0' by @mrgriffin in [#10110](https://github.com/rh-hideout/pokeemerald-expansion/pull/10110) +* Fix Trainer Party Pool documentation by @RubyRaven6 in [#10122](https://github.com/rh-hideout/pokeemerald-expansion/pull/10122) +* Remove deprecated ``HQ_RANDOM`` config by @Bassoonian in [#10131](https://github.com/rh-hideout/pokeemerald-expansion/pull/10131) + +### Fixed +* chore(credits): change kildemal to miriam in credits by @miriamlefae in [#10123](https://github.com/rh-hideout/pokeemerald-expansion/pull/10123) +* Misc Fixes/Cleanups by @mrgriffin in [#9892](https://github.com/rh-hideout/pokeemerald-expansion/pull/9892) +* Fix HGSS Dex Form Strings by @HashtagMarky in [#10147](https://github.com/rh-hideout/pokeemerald-expansion/pull/10147) + +## 🗺️ Overworld 🗺️ +### Changed +* assertf for NULL goto/call by @mrgriffin in [#10111](https://github.com/rh-hideout/pokeemerald-expansion/pull/10111) + +### Fixed +* Fix colosseum warps frlg by @Viperio19 in [#10100](https://github.com/rh-hideout/pokeemerald-expansion/pull/10100) + +## 🐉 Pokémon 🐉 +### Changed +* Fix missing incgfx for Mega Garchomp Z by @hedara90 in [#10116](https://github.com/rh-hideout/pokeemerald-expansion/pull/10116) + +## ⚔️ Battle General ⚔️ +### Changed +* feat (battle): improve gimmick triggers' graphics by @mudskipper13 in [#10129](https://github.com/rh-hideout/pokeemerald-expansion/pull/10129) + +### Fixed +* Fixes stat change queue having erroneous stats stored by @AlexOn1ine in [#10088](https://github.com/rh-hideout/pokeemerald-expansion/pull/10088) +* Fixes Acupressure timeout in doubles by @AlexOn1ine in [#10091](https://github.com/rh-hideout/pokeemerald-expansion/pull/10091) +* Fixes Random Move from disobedience by @AlexOn1ine in [#10093](https://github.com/rh-hideout/pokeemerald-expansion/pull/10093) +* Fix link singles and doubles using incorrect parties by @Viperio19 in [#10102](https://github.com/rh-hideout/pokeemerald-expansion/pull/10102) +* Fix player's hp display showing 0 max hp for p2 in link battles after taking damage by @Viperio19 in [#10105](https://github.com/rh-hideout/pokeemerald-expansion/pull/10105) +* Fix generic ability ineffective battle message misuse by @Cle-bit in [#10149](https://github.com/rh-hideout/pokeemerald-expansion/pull/10149) + +## 🧶 Items 🧶 +### Changed +* Add missing item sort types by @Cle-bit in [#10104](https://github.com/rh-hideout/pokeemerald-expansion/pull/10104) +* SanitizeBagItemId, TryTakeMonItemResult by @mrgriffin in [#10109](https://github.com/rh-hideout/pokeemerald-expansion/pull/10109) + +### Fixed +* Use values from `enum PokeBall` for Poké Balls by @PCG06 in [#10106](https://github.com/rh-hideout/pokeemerald-expansion/pull/10106) + +## 🤖 Battle AI 🤖 +### Fixed +* Prevent AI illegally targeting itself in doubles by @grintoul1 in [#10139](https://github.com/rh-hideout/pokeemerald-expansion/pull/10139) + +## 🧹 Other Cleanup 🧹 +* Add missing item sort types by @Cle-bit in [#10104](https://github.com/rh-hideout/pokeemerald-expansion/pull/10104) +* Cleanup 'message 0x0' by @mrgriffin in [#10110](https://github.com/rh-hideout/pokeemerald-expansion/pull/10110) +* SanitizeBagItemId, TryTakeMonItemResult by @mrgriffin in [#10109](https://github.com/rh-hideout/pokeemerald-expansion/pull/10109) +* feat (battle): improve gimmick triggers' graphics by @mudskipper13 in [#10129](https://github.com/rh-hideout/pokeemerald-expansion/pull/10129) +* assertf for NULL goto/call by @mrgriffin in [#10111](https://github.com/rh-hideout/pokeemerald-expansion/pull/10111) +* Remove deprecated ``HQ_RANDOM`` config by @Bassoonian in [#10131](https://github.com/rh-hideout/pokeemerald-expansion/pull/10131) +* Fix Beat Up typeless damage test effectiveness check by @Cle-bit in [#10103](https://github.com/rh-hideout/pokeemerald-expansion/pull/10103) + +## 🧪 Test Runner 🧪 +### Changed +* Fix Beat Up typeless damage test effectiveness check by @Cle-bit in [#10103](https://github.com/rh-hideout/pokeemerald-expansion/pull/10103) + +### Fixed +* Prevent AI illegally targeting itself in doubles by @grintoul1 in [#10139](https://github.com/rh-hideout/pokeemerald-expansion/pull/10139) + +## 📚 Documentation 📚 +* Fix Trainer Party Pool documentation by @RubyRaven6 in [#10122](https://github.com/rh-hideout/pokeemerald-expansion/pull/10122) +* Fix broken/old links in CREDITS.md by @ThePeeps191 in [#10120](https://github.com/rh-hideout/pokeemerald-expansion/pull/10120) + +## 📦 Branch Synchronisation 📦 +### pret +* 1st of June, 2026 in [#10113](https://github.com/rh-hideout/pokeemerald-expansion/pull/10113) + * Implicit waitstate for special/specialvars by @mrgriffin in [pret#2200](https://github.com/pret/pokeemerald/pull/2200) + +## New Contributors +* @Viperio19 made their first contribution in [#10100](https://github.com/rh-hideout/pokeemerald-expansion/pull/10100) + +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.16.0...expansion/1.16.1 + + + + diff --git a/docs/tutorials/how_to_trainer_party_pool.md b/docs/tutorials/how_to_trainer_party_pool.md index e111ba957e..b0045249c8 100644 --- a/docs/tutorials/how_to_trainer_party_pool.md +++ b/docs/tutorials/how_to_trainer_party_pool.md @@ -3,7 +3,7 @@ Trainer Party Pools (TPP) is a way to introduce a bit of unpredictability to tra The maximum number of mons that can be in a single trainer's pool is 255. -## Turning on TPP with `trainer.sparty` +## Turning on TPP with `trainers.party` To use TPP with `trainers.party`, all that's needed is to define a `Party Size` that's smaller than than the number of defined mons for the trainer. ## Turning on TPP with `trainers.h` @@ -69,7 +69,7 @@ Double Battle: Yes AI: Check Bad Move Party Size: 4 Pool Rules: Weather Doubles -Pool Pick Index: Default +Pool Pick Functions: Default Zigzagoon Level: 4 diff --git a/graphics/battle_interface/burst_trigger.png b/graphics/battle_interface/burst_trigger.png index bbd16ac555..f9b1f13707 100644 Binary files a/graphics/battle_interface/burst_trigger.png and b/graphics/battle_interface/burst_trigger.png differ diff --git a/graphics/battle_interface/dynamax_trigger.png b/graphics/battle_interface/dynamax_trigger.png index 18f3a84cff..954de81e7c 100644 Binary files a/graphics/battle_interface/dynamax_trigger.png and b/graphics/battle_interface/dynamax_trigger.png differ diff --git a/graphics/battle_interface/mega_trigger.pal b/graphics/battle_interface/mega_trigger.pal deleted file mode 100644 index 2672d1f10a..0000000000 --- a/graphics/battle_interface/mega_trigger.pal +++ /dev/null @@ -1,19 +0,0 @@ -JASC-PAL -0100 -16 -185 207 163 -77 105 97 -199 159 199 -221 177 207 -57 151 117 -139 221 253 -247 161 133 -255 255 255 -153 87 67 -233 233 125 -129 255 223 -149 147 247 -195 207 201 -123 151 135 -0 0 0 -0 0 0 diff --git a/graphics/battle_interface/mega_trigger.png b/graphics/battle_interface/mega_trigger.png index a269ee738c..bdb3e8e957 100644 Binary files a/graphics/battle_interface/mega_trigger.png and b/graphics/battle_interface/mega_trigger.png differ diff --git a/graphics/battle_interface/tera_trigger.png b/graphics/battle_interface/tera_trigger.png index 5498ea8806..660880acf9 100644 Binary files a/graphics/battle_interface/tera_trigger.png and b/graphics/battle_interface/tera_trigger.png differ diff --git a/graphics/battle_interface/z_move_trigger.png b/graphics/battle_interface/z_move_trigger.png index 7d5fbaba0f..907a4cf20c 100644 Binary files a/graphics/battle_interface/z_move_trigger.png and b/graphics/battle_interface/z_move_trigger.png differ diff --git a/graphics/pokemon/bounsweet/anim_front.png b/graphics/pokemon/bounsweet/anim_front.png new file mode 100644 index 0000000000..d9a30f545d Binary files /dev/null and b/graphics/pokemon/bounsweet/anim_front.png differ diff --git a/graphics/pokemon/bounsweet/front.png b/graphics/pokemon/bounsweet/front.png deleted file mode 100644 index 9e09d6d728..0000000000 Binary files a/graphics/pokemon/bounsweet/front.png and /dev/null differ diff --git a/graphics/pokemon/bruxish/anim_front.png b/graphics/pokemon/bruxish/anim_front.png new file mode 100644 index 0000000000..b9485d270b Binary files /dev/null and b/graphics/pokemon/bruxish/anim_front.png differ diff --git a/graphics/pokemon/bruxish/front.png b/graphics/pokemon/bruxish/front.png deleted file mode 100644 index ce29eb8d5f..0000000000 Binary files a/graphics/pokemon/bruxish/front.png and /dev/null differ diff --git a/graphics/pokemon/comfey/anim_front.png b/graphics/pokemon/comfey/anim_front.png new file mode 100644 index 0000000000..a76dd3b51e Binary files /dev/null and b/graphics/pokemon/comfey/anim_front.png differ diff --git a/graphics/pokemon/comfey/front.png b/graphics/pokemon/comfey/front.png deleted file mode 100644 index d2e8709651..0000000000 Binary files a/graphics/pokemon/comfey/front.png and /dev/null differ diff --git a/graphics/pokemon/cosmog/anim_front.png b/graphics/pokemon/cosmog/anim_front.png new file mode 100644 index 0000000000..a348e884e9 Binary files /dev/null and b/graphics/pokemon/cosmog/anim_front.png differ diff --git a/graphics/pokemon/cosmog/front.png b/graphics/pokemon/cosmog/front.png deleted file mode 100644 index c1c2cba84f..0000000000 Binary files a/graphics/pokemon/cosmog/front.png and /dev/null differ diff --git a/graphics/pokemon/dhelmise/anim_front.png b/graphics/pokemon/dhelmise/anim_front.png new file mode 100644 index 0000000000..06d1ebed11 Binary files /dev/null and b/graphics/pokemon/dhelmise/anim_front.png differ diff --git a/graphics/pokemon/dhelmise/front.png b/graphics/pokemon/dhelmise/front.png deleted file mode 100644 index 1181df89b9..0000000000 Binary files a/graphics/pokemon/dhelmise/front.png and /dev/null differ diff --git a/graphics/pokemon/fomantis/anim_front.png b/graphics/pokemon/fomantis/anim_front.png new file mode 100644 index 0000000000..97448d37a6 Binary files /dev/null and b/graphics/pokemon/fomantis/anim_front.png differ diff --git a/graphics/pokemon/fomantis/front.png b/graphics/pokemon/fomantis/front.png deleted file mode 100644 index 116850706e..0000000000 Binary files a/graphics/pokemon/fomantis/front.png and /dev/null differ diff --git a/graphics/pokemon/komala/anim_front.png b/graphics/pokemon/komala/anim_front.png new file mode 100644 index 0000000000..58fa1eba70 Binary files /dev/null and b/graphics/pokemon/komala/anim_front.png differ diff --git a/graphics/pokemon/komala/front.png b/graphics/pokemon/komala/front.png deleted file mode 100644 index 8b8c6cb687..0000000000 Binary files a/graphics/pokemon/komala/front.png and /dev/null differ diff --git a/graphics/pokemon/morelull/anim_front.png b/graphics/pokemon/morelull/anim_front.png new file mode 100644 index 0000000000..1f9a8e915d Binary files /dev/null and b/graphics/pokemon/morelull/anim_front.png differ diff --git a/graphics/pokemon/morelull/front.png b/graphics/pokemon/morelull/front.png deleted file mode 100644 index 73c2c96425..0000000000 Binary files a/graphics/pokemon/morelull/front.png and /dev/null differ diff --git a/graphics/pokemon/palossand/anim_front.png b/graphics/pokemon/palossand/anim_front.png new file mode 100644 index 0000000000..0cb8750303 Binary files /dev/null and b/graphics/pokemon/palossand/anim_front.png differ diff --git a/graphics/pokemon/palossand/front.png b/graphics/pokemon/palossand/front.png deleted file mode 100644 index d22845d345..0000000000 Binary files a/graphics/pokemon/palossand/front.png and /dev/null differ diff --git a/graphics/pokemon/sandygast/anim_front.png b/graphics/pokemon/sandygast/anim_front.png new file mode 100644 index 0000000000..bd8e8ed0b6 Binary files /dev/null and b/graphics/pokemon/sandygast/anim_front.png differ diff --git a/graphics/pokemon/sandygast/front.png b/graphics/pokemon/sandygast/front.png deleted file mode 100644 index 5e80875bb0..0000000000 Binary files a/graphics/pokemon/sandygast/front.png and /dev/null differ diff --git a/graphics/pokemon/shiinotic/anim_front.png b/graphics/pokemon/shiinotic/anim_front.png new file mode 100644 index 0000000000..a9cee08c39 Binary files /dev/null and b/graphics/pokemon/shiinotic/anim_front.png differ diff --git a/graphics/pokemon/shiinotic/front.png b/graphics/pokemon/shiinotic/front.png deleted file mode 100644 index 0f63c92c7d..0000000000 Binary files a/graphics/pokemon/shiinotic/front.png and /dev/null differ diff --git a/graphics/pokemon/steenee/anim_front.png b/graphics/pokemon/steenee/anim_front.png new file mode 100644 index 0000000000..fdcf044c51 Binary files /dev/null and b/graphics/pokemon/steenee/anim_front.png differ diff --git a/graphics/pokemon/steenee/front.png b/graphics/pokemon/steenee/front.png deleted file mode 100644 index 77ae6e0f22..0000000000 Binary files a/graphics/pokemon/steenee/front.png and /dev/null differ diff --git a/graphics/pokemon/tsareena/anim_front.png b/graphics/pokemon/tsareena/anim_front.png new file mode 100644 index 0000000000..a3503731e1 Binary files /dev/null and b/graphics/pokemon/tsareena/anim_front.png differ diff --git a/graphics/pokemon/tsareena/front.png b/graphics/pokemon/tsareena/front.png deleted file mode 100644 index 9072ce8651..0000000000 Binary files a/graphics/pokemon/tsareena/front.png and /dev/null differ diff --git a/include/battle_anim.h b/include/battle_anim.h index b3cfc97d60..ead7730e6e 100644 --- a/include/battle_anim.h +++ b/include/battle_anim.h @@ -270,8 +270,8 @@ extern const union AffineAnimCmd *const gAffineAnims_SpinningBone[]; // battle_anim_throw.c void TryShinyAnimation(enum BattlerId battler, struct Pokemon *mon); -u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, u8 ballId); -u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, u8 ballId); +u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, enum PokeBall ballId); +u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, enum PokeBall ballId); bool32 IsCriticalCapture(void); // battle_anim_utility_funcs.c void InitStatsChangeAnimation(u8 taskId); diff --git a/include/battle_controllers.h b/include/battle_controllers.h index e5218e8733..fa1b50de76 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -93,46 +93,55 @@ enum BattleController static inline void MarkBattleControllerActiveOnLocal(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags |= (1u << battler); } static inline void MarkBattleControllerIdleOnLocal(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags &= ~(1u << battler); } static inline bool32 IsBattleControllerActiveOnLocal(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & (1u << battler); } static inline void MarkBattleControllerMessageOutboundOverLink(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags |= ((1u << battler) << (32 - MAX_BATTLERS_COUNT)); } static inline void MarkBattleControllerMessageSynchronizedOverLink(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags &= ~((1 << 28) << (battler)); } static inline bool32 IsBattleControllerMessageSynchronizedOverLink(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & (1u << (battler + 28)); } static inline void MarkBattleControllerActiveForPlayer(enum BattlerId battler, u32 playerId) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags |= ((1u << battler) << ((playerId) << 2)); } static inline void MarkBattleControllerIdleForPlayer(enum BattlerId battler, u32 playerId) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); gBattleControllerExecFlags &= ~((1u << battler) << ((playerId) * 4)); } static inline bool32 IsBattleControllerActiveForPlayer(enum BattlerId battler, u32 playerId) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & ((1u << battler) << ((playerId) * 4)); } @@ -141,6 +150,7 @@ static inline bool32 IsBattleControllerActiveForPlayer(enum BattlerId battler, u // can only be so specific before it just gets ridiculous. static inline bool32 IsBattleControllerActiveOrPendingSyncAnywhere(enum BattlerId battler) { + assertf(battler < MAX_BATTLERS_COUNT, "illegal battle controller: %d", battler); return gBattleControllerExecFlags & ( (1u << battler) | (0xF << 28) diff --git a/include/battle_stat_change.h b/include/battle_stat_change.h index d1f4b93bf7..920cc0321d 100644 --- a/include/battle_stat_change.h +++ b/include/battle_stat_change.h @@ -39,6 +39,7 @@ void SetStatChange(enum BattlerId battler, enum Stat stat, s32 stage); void SetStatChange2(enum BattlerId battler, enum Stat stat, s32 stage); void ClearStatChangeValues(void); void ClearOtherStatChangeValues(enum BattlerId battler); +void ClearBothStatChangeQueues(void); enum StatChangeResult TrySingleStatChange(struct BattleCalcValues *cv, struct StatChange *st); u32 GetStatStage(enum Stat stat, const struct AdditionalEffect *additionalEffect); diff --git a/include/bg.h b/include/bg.h index 89ffc8d8eb..9715dfb5b4 100644 --- a/include/bg.h +++ b/include/bg.h @@ -58,6 +58,7 @@ u8 LoadBgVram(u32 bg, const void *src, u16 size, u16 destOffset, u32 mode); void SetTextModeAndHideBgs(void); bool32 IsInvalidBg(u32 bg); int BgTileAllocOp(int bg, int offset, int count, int mode); +int BgTileAllocOpUnchecked(int bg, int offset, int count, int mode); void ResetBgsAndClearDma3BusyFlags(u32 leftoverFireRedLeafGreenVariable); void InitBgsFromTemplates(u32 bgMode, const struct BgTemplate *templates, u8 numTemplates); void InitBgFromTemplate(const struct BgTemplate *template); diff --git a/include/config/general.h b/include/config/general.h index 729a28ed0b..e156efbbcc 100644 --- a/include/config/general.h +++ b/include/config/general.h @@ -75,7 +75,6 @@ // General settings #define EXPANSION_INTRO TRUE // If TRUE, a custom RHH intro will play after the vanilla copyright screen. -#define HQ_RANDOM TRUE // If TRUE, replaces the default RNG with an implementation of SFC32 RNG. May break code that relies on RNG. #define PHONEMES_SHARED FALSE // If TRUE, bard phonemes all reference the same sound (sound/direct_sound_samples/phonemes/shared.bin) to save ROM space. // Measurement system constants to be used for UNITS diff --git a/include/constants/expansion.h b/include/constants/expansion.h index 22f5af54e8..7532cde428 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -1,7 +1,7 @@ #ifndef GUARD_CONSTANTS_EXPANSION_H #define GUARD_CONSTANTS_EXPANSION_H -// Last version: 1.16.0 +// Last version: 1.16.1 #define EXPANSION_VERSION_MAJOR 1 #define EXPANSION_VERSION_MINOR 17 #define EXPANSION_VERSION_PATCH 0 diff --git a/include/malloc.h b/include/malloc.h index 10481dc398..d1bd330270 100644 --- a/include/malloc.h +++ b/include/malloc.h @@ -3,10 +3,10 @@ #define FREE_AND_SET_NULL(ptr) \ -{ \ +do { \ Free(ptr); \ ptr = NULL; \ -} +} while (0) #define TRY_FREE_AND_SET_NULL(ptr) if (ptr != NULL) FREE_AND_SET_NULL(ptr) @@ -47,19 +47,27 @@ extern u8 gHeap[HEAP_SIZE]; #if TESTING || !defined(NDEBUG) #define Alloc(size) Alloc_(size, __FILE__ ":" STR(__LINE__)) +#define AllocUnchecked(size) AllocUnchecked_(size, __FILE__ ":" STR(__LINE__)) + #define AllocZeroed(size) AllocZeroed_(size, __FILE__ ":" STR(__LINE__)) +#define AllocZeroedUnchecked(size) AllocZeroedUnchecked_(size, __FILE__ ":" STR(__LINE__)) #else #define Alloc(size) Alloc_(size, NULL) +#define AllocUnchecked(size) AllocUnchecked_(size, NULL) #define AllocZeroed(size) AllocZeroed_(size, NULL) +#define AllocZeroedUnchecked(size) AllocZeroedUnchecked_(size, NULL) #endif void *Alloc_(u32 size, const char *location); +void *AllocUnchecked_(u32 size, const char *location); void *AllocZeroed_(u32 size, const char *location); +void *AllocZeroedUnchecked_(u32 size, const char *location); void Free(void *pointer); void InitHeap(void *heapStart, u32 heapSize); +void PrintHeap(void); const struct MemBlock *HeapHead(void); const char *MemBlockLocation(const struct MemBlock *block); diff --git a/include/metaprogram.h b/include/metaprogram.h index ec0b6ef0bf..d29c42571c 100644 --- a/include/metaprogram.h +++ b/include/metaprogram.h @@ -207,4 +207,14 @@ Input must be of the form (upper << lower) where upper can be up to 7, lower up /* Useful for counting arguments */ #define PLUS_ONE(...) + 1 +/* Expands to 'if (true)' if 'cond' can be evaluated at compile-time and + * evaluates to non-zero; expands to 'if (false)' otherwise. + * + * GCC will not generate code for an 'if (false) { ... }', so this can + * be used to write compile-time optimizations without a run-time cost. + * + * Because 'cond' must be known at compile-time, this is rarely useful + * outside macros. */ +#define if_comptime(cond) if (__builtin_constant_p((cond) ? 0 : *(int *)0)) + #endif diff --git a/include/pokeball.h b/include/pokeball.h index 036cff9275..09a3184b25 100644 --- a/include/pokeball.h +++ b/include/pokeball.h @@ -30,8 +30,8 @@ void CreatePokeballSpriteToReleaseMon(u8 monSpriteId, u8 monPalNum, u8 x, u8 y, u8 CreateTradePokeballSprite(u8 monSpriteId, u8 monPalNum, u8 x, u8 y, u8 oamPriority, u8 subPriority, u8 delay, u32 fadePalettes); void StartHealthboxSlideIn(enum BattlerId battler); void DoHitAnimHealthboxEffect(enum BattlerId battler); -void LoadBallGfx(u8 ballId); -void FreeBallGfx(u8 ballId); +void LoadBallGfx(enum PokeBall ballId); +void FreeBallGfx(enum PokeBall ballId); enum PokeBall ItemIdToBallId(u32 ballItem); #endif // GUARD_POKEBALL_H diff --git a/include/pokedex.h b/include/pokedex.h index d19d340095..2b955974f8 100644 --- a/include/pokedex.h +++ b/include/pokedex.h @@ -256,11 +256,11 @@ extern const struct SpriteTemplate sNationalDexSeenOwnNumberSpriteTemplate; extern const struct SpriteTemplate sDexListStartMenuCursorSpriteTemplate; extern const struct BgTemplate sSearchMenu_BgTemplate[NUM_SEARCH_MENU_BG_TEMPLATES]; -extern const struct WindowTemplate sSearchMenu_WindowTemplate[]; +extern const struct WindowTemplate sSearchMenu_WindowTemplate[2]; extern const u8 sScrollMonIncrements[]; extern const u8 sScrollTimers[]; extern const struct BgTemplate sPokedex_BgTemplate[NUM_POKEDEX_BG_TEMPLATES]; -extern const struct WindowTemplate sPokemonList_WindowTemplate[]; +extern const struct WindowTemplate sPokemonList_WindowTemplate[2]; extern const struct BgTemplate sInfoScreen_BgTemplate[NUM_INFO_SCREEN_BG_TEMPLATES]; extern const struct BgTemplate sNewEntryInfoScreen_BgTemplate[NUM_NEW_ENTRY_INFO_BG_TEMPLATES]; diff --git a/include/random.h b/include/random.h index d1c0ddd4f1..9783fda016 100644 --- a/include/random.h +++ b/include/random.h @@ -275,7 +275,11 @@ enum RandomTag #define RandomPercentage(tag, t) \ ({ \ u32 r; \ - if (t <= 0) \ + if_comptime (t == 50) \ + { \ + r = RandomUniform(tag, FALSE, TRUE); \ + } \ + else if (t <= 0) \ { \ r = FALSE; \ } \ diff --git a/include/test/battle.h b/include/test/battle.h index e65ba005d1..9879db8618 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -461,7 +461,7 @@ * MESSAGE("Wobbuffet used Dream Eater!"); * MESSAGE("It doesn't affect the opposing Wobbuffet…"); * - * STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis:, badPoison:) + * STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis: | badPoison: | frostbite:) * Causes the test to fail if the battler's status is not changed to the * specified status. * STATUS_ICON(player, badPoison: TRUE); @@ -767,8 +767,6 @@ struct BattleTrialData u8 targetTieCount; }; -extern struct BattleTrialData gBattleTrialData; - struct BattleTestData { u8 stack[BATTLE_TEST_STACK_SIZE]; diff --git a/include/test/test.h b/include/test/test.h index 9e95d837fa..df0a97a4f4 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -57,8 +57,8 @@ struct TestRunnerState const struct Test *test; u32 processCosts[MAX_PROCESSES]; - u8 result; - u8 expectedResult; + enum TestResult result:8; + enum TestResult expectedResult:8; bool8 expectLeaks:1; bool8 inBenchmark:1; bool8 tearDown:1; diff --git a/include/text.h b/include/text.h index 7d2ecdb4ce..f0bda0351b 100644 --- a/include/text.h +++ b/include/text.h @@ -186,7 +186,7 @@ extern struct TextGlyph gCurGlyph; void DeactivateAllTextPrinters(void); void DeactivateSingleTextPrinter(u32 id, enum TextPrinterType type); u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); -u16 AddSpriteTextPrinterParametrerized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); +u16 AddSpriteTextPrinterParameterized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)); void AddSpriteTextPrinterParameterized3(u8 spriteId, u8 fontId, u8 left, u8 top, const u8 *color, s8 speed, const u8 *str); void AddSpriteTextPrinterParameterized4(u8 spriteId, u8 fontId, u8 left, u8 top, u8 letterSpacing, u8 lineSpacing, const u8 *color, s8 speed, const u8 *str); void AddSpriteTextPrinterParameterized6(u8 spriteId, u8 fontId, u8 left, u8 top, u8 letterSpacing, u8 lineSpacing, const union TextColor color, s8 speed, const u8 *str); diff --git a/include/window.h b/include/window.h index fc35f724d9..5af7979be4 100644 --- a/include/window.h +++ b/include/window.h @@ -48,7 +48,10 @@ struct Window ALIGNED(4) u8 *tileData; }; -bool32 InitWindows(const struct WindowTemplate *templates); +bool32 InitWindowsUnchecked(const struct WindowTemplate *templates); +bool32 InitWindowsChecked(const struct WindowTemplate *templates, s32 staticSize); +#define InitWindows(templates) InitWindowsChecked(templates, (__builtin_types_compatible_p(typeof(templates), const struct WindowTemplate *)) ? -1 : (s32)sizeof(templates)) + u32 AddWindow(const struct WindowTemplate *template); int AddWindowWithoutTileMap(const struct WindowTemplate *template); void RemoveWindow(u32 windowId); diff --git a/ld_script_modern.ld b/ld_script_modern.ld index 6141d84701..005ca633ff 100644 --- a/ld_script_modern.ld +++ b/ld_script_modern.ld @@ -70,7 +70,7 @@ SECTIONS { script_data : ALIGN(4) { - data/*.o(script_data); + data/*.o(script_data); } > ROM =0 .rodata.compound_string : diff --git a/map_data_rules.mk b/map_data_rules.mk index 57752c94d3..9935171306 100755 --- a/map_data_rules.mk +++ b/map_data_rules.mk @@ -21,9 +21,9 @@ MAP_HEADERS := $(patsubst $(MAPS_DIR)/%/,$(MAPS_DIR)/%/header.inc,$(MAP_DIRS)) MAP_JSONS := $(patsubst $(MAPS_DIR)/%/,$(MAPS_DIR)/%/map.json,$(MAP_DIRS)) $(DATA_ASM_BUILDDIR)/maps.o: $(DATA_ASM_SUBDIR)/maps.s $(LAYOUTS_DIR)/layouts.inc $(LAYOUTS_DIR)/layouts_table.inc $(MAPS_DIR)/headers.inc $(MAPS_DIR)/groups.inc $(MAPS_DIR)/connections.inc $(MAP_CONNECTIONS) $(MAP_HEADERS) - $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) -s $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(DATA_ASM_BUILDDIR)/map_events.o: $(DATA_ASM_SUBDIR)/map_events.s $(MAPS_DIR)/events.inc $(MAP_EVENTS) - $(PREPROC) $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ + $(PREPROC) -s $< charmap.txt | $(CPP) $(CPPFLAGS) -I include - | $(PREPROC) -ie $< charmap.txt | $(AS) $(ASFLAGS) -o $@ $(MAPS_OUTDIR)/%/header.inc $(MAPS_OUTDIR)/%/events.inc $(MAPS_OUTDIR)/%/connections.inc: $(MAPS_DIR)/%/map.json $(INCLUDECONSTS_OUTDIR)/map_groups.h $(MAPJSON) map emerald $< $(LAYOUTS_DIR)/layouts.json $(@D) diff --git a/src/assertf.c b/src/assertf.c index f7ecd0fd82..bf2252a377 100644 --- a/src/assertf.c +++ b/src/assertf.c @@ -145,9 +145,9 @@ static bool32 Putp(u32 *x, u32 *y, const void *p) return TRUE; } -static bool32 Puts(u32 *x, u32 *y, const char *s) +static bool32 Puts(u32 *x, u32 *y, s32 n, const char *s) { - while (*s != '\0') + while (*s != '\0' && n-- > 0) { if (!Putc(x, y, *s++)) return FALSE; @@ -155,9 +155,9 @@ static bool32 Puts(u32 *x, u32 *y, const char *s) return TRUE; } -static bool32 PutS(u32 *x, u32 *y, const u8 *s) +static bool32 PutS(u32 *x, u32 *y, s32 n, const u8 *s) { - while (*s != EOS) + while (*s != EOS && n-- > 0) { char c; if (CHAR_a <= *s && *s <= CHAR_z) @@ -215,6 +215,7 @@ static bool32 Putx(u32 *x, u32 *y, unsigned u) static void Vprintf(const void *return1, const void *return0, const char *fmt, va_list va) { u32 x, y; + s32 n; x = 3; y = 19; @@ -226,6 +227,16 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v y = 0; while (TRUE) { + if (fmt[0] == '.' && fmt[1] == '*') + { + fmt += 2; + n = va_arg(va, int); + } + else + { + n = INT_MAX; + } + char c = *fmt++; if (c == '\0') { @@ -236,6 +247,10 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v char f = *fmt++; switch (f) { + case '%': + if (!Putc(&x, &y, '%')) + return; + break; case 'd': if (!Puti(&x, &y, va_arg(va, int))) return; @@ -245,11 +260,11 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v return; break; case 's': - if (!Puts(&x, &y, va_arg(va, const char *))) + if (!Puts(&x, &y, n, va_arg(va, const char *))) return; break; case 'S': - if (!PutS(&x, &y, va_arg(va, const u8 *))) + if (!PutS(&x, &y, n, va_arg(va, const u8 *))) return; break; case 'x': @@ -265,11 +280,11 @@ static void Vprintf(const void *return1, const void *return0, const char *fmt, v } } - if (!Puts(&x, &y, "\n in: ")) + if (!Puts(&x, &y, INT_MAX, "\n in: ")) return; if (!Putp(&x, &y, return1)) return; - if (!Puts(&x, &y, "\n in: ")) + if (!Puts(&x, &y, INT_MAX, "\n in: ")) return; if (!Putp(&x, &y, return0)) return; @@ -305,7 +320,7 @@ void AssertfCrashScreen(const void *return1, const char *fmt, ...) // Allocate on heap if possible. if (!backup) { - backup = Alloc(sizeof(*backup)); + backup = AllocUnchecked(sizeof(*backup)); if (backup) backup->onHeap = TRUE; } diff --git a/src/battle_anim.c b/src/battle_anim.c index 4dcaba3e3c..3bec8939ad 100644 --- a/src/battle_anim.c +++ b/src/battle_anim.c @@ -341,16 +341,37 @@ void LaunchBattleAnimation(u32 animType, u32 animId) if (gTestRunnerEnabled) { TestRunner_Battle_RecordAnimation(animType, animId); - // Play Transform and Ally Switch even in Headless as these move animations also change mon data. - if (gTestRunnerHeadless - #if TESTING // Because gBattleTestRunnerState is not seen outside of test env. - && !gBattleTestRunnerState->forceMoveAnim - #endif // TESTING - && !(animType == ANIM_TYPE_MOVE && (animId == MOVE_TRANSFORM || animId == MOVE_ALLY_SWITCH))) + + bool32 forceMoveAnim = FALSE; + #if TESTING // Because gBattleTestRunnerState is not seen outside of test env. + forceMoveAnim = gBattleTestRunnerState->forceMoveAnim; + #endif + if (!forceMoveAnim) { - gAnimScriptCallback = Nop; - gAnimScriptActive = FALSE; - return; + enum { DEFAULT, PLAY, SKIP } mode = DEFAULT; + if (animType == ANIM_TYPE_MOVE) + { + switch (animId) + { + // Play Transform and Ally Switch even in headless + // because the animations also change mon data. + case MOVE_TRANSFORM: + case MOVE_ALLY_SWITCH: + mode = PLAY; + break; + // Skip Celebrate even in non-headless because it's + // very noisy. + case MOVE_CELEBRATE: + mode = SKIP; + break; + } + } + if ((mode == DEFAULT && gTestRunnerHeadless) || mode == SKIP) + { + gAnimScriptCallback = Nop; + gAnimScriptActive = FALSE; + return; + } } } diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index dd4cc2fbdf..1b065c3eba 100644 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -71,7 +71,7 @@ static void SpriteCB_Ball_Capture_Step(struct Sprite *); static void MakeCaptureStars(struct Sprite *); static void SpriteCB_Ball_FadeOut(struct Sprite *); static void DestroySpriteAfterOneFrame(struct Sprite *); -static void LoadBallParticleGfx(u8); +static void LoadBallParticleGfx(enum PokeBall); static void SpriteCB_CaptureStar_Flicker(struct Sprite *); static void SpriteCB_Ball_Release_Wait(struct Sprite *); static void SpriteCB_Ball_Block_Step(struct Sprite *); @@ -1600,7 +1600,7 @@ static void SpriteCB_Ball_Block_Step(struct Sprite *sprite) #undef sFrame -static void LoadBallParticleGfx(u8 ballId) +static void LoadBallParticleGfx(enum PokeBall ballId) { if (GetSpriteTileStartByTag(sBallParticles[ballId].pic.tag) == 0xFFFF) { @@ -1609,7 +1609,7 @@ static void LoadBallParticleGfx(u8 ballId) } } -u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, u8 ballId) +u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, enum PokeBall ballId) { u8 taskId; @@ -1636,7 +1636,7 @@ static void PokeBallOpenParticleAnimation(u8 taskId) u8 spriteId; u8 x, y; u8 priority, subpriority; - u8 ballId; + enum PokeBall ballId; u8 var0; ballId = gTasks[taskId].data[15]; @@ -2065,7 +2065,7 @@ static void DestroyBallOpenAnimationParticle(struct Sprite *sprite) #define tPaletteHi data[11] #define tBallId data[15] -u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, u8 ballId) +u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalettes, enum PokeBall ballId) { u8 taskId; @@ -2094,7 +2094,7 @@ u8 LaunchBallFadeMonTask(bool8 unfadeLater, u8 spritePalNum, u32 selectedPalette static void Task_FadeMon_ToBallColor(u8 taskId) { - u8 ballId = gTasks[taskId].tBallId; + enum PokeBall ballId = gTasks[taskId].tBallId; if (gTasks[taskId].tTimer <= 16) { @@ -2122,7 +2122,7 @@ static void Task_FadeMon_ToNormal(u8 taskId) static void Task_FadeMon_ToNormal_Step(u8 taskId) { - u8 ballId = gTasks[taskId].tBallId; + enum PokeBall ballId = gTasks[taskId].tBallId; if (gTasks[taskId].tTimer <= 16) { diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 5f5c5d7402..645236d349 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -195,12 +195,13 @@ static void CompleteOnBattlerSpritePosX_0(enum BattlerId battler) BtlController_Complete(battler); } -static u16 GetPrevBall(u16 ballId) +static enum Item GetPrevBall(enum Item ballId) { s32 i; - s32 index = ItemIdToBallId(ballId); - u32 newBall = 0; - for (i = 0; i < POKEBALL_COUNT; i++) + enum PokeBall index = ItemIdToBallId(ballId); + enum Item newBall = ITEM_NONE; + + for (i = 0; i < POKEBALL_COUNT; i++) { index--; if (index == -1) @@ -212,11 +213,12 @@ static u16 GetPrevBall(u16 ballId) return ballId; } -static u32 GetNextBall(u32 ballId) +static enum Item GetNextBall(enum Item ballId) { s32 i; s32 index = ItemIdToBallId(ballId); - u32 newBall = 0; + enum Item newBall = ITEM_NONE; + for (i = 0; i < POKEBALL_COUNT; i++) { index++; @@ -1783,9 +1785,9 @@ static void MoveSelectionDisplayMoveDescription(enum BattlerId battler) u8 cat_desc[7] = _("CAT: "); u8 pwr_desc[7] = _("PWR: "); u8 acc_desc[7] = _("ACC: "); - u8 cat_start[] = _("{CLEAR_TO 0x03}"); - u8 pwr_start[] = _("{CLEAR_TO 0x38}"); - u8 acc_start[] = _("{CLEAR_TO 0x6C}"); + u8 cat_start[] = _("{CLEAR_TO 3}"); + u8 pwr_start[] = _("{CLEAR_TO 56}"); + u8 acc_start[] = _("{CLEAR_TO 108}"); LoadMessageBoxAndBorderGfx(); DrawStdWindowFrame(B_WIN_MOVE_DESCRIPTION, FALSE); if (pwr < 2) diff --git a/src/battle_controllers.c b/src/battle_controllers.c index 4349200cb4..97dcf98552 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -2166,11 +2166,13 @@ static void Controller_HandleTrainerSlideBack(enum BattlerId battler) void Controller_WaitForHealthBar(enum BattlerId battler) { s16 hpValue = MoveBattleBar(battler, gHealthboxSpriteIds[battler], HEALTH_BAR, 0); + struct Pokemon *mon = GetBattlerMon(battler); + s32 maxHP = GetMonData(mon, MON_DATA_MAX_HP); SetHealthboxSpriteVisible(gHealthboxSpriteIds[battler]); if (hpValue != -1) { - UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, hpValue, gBattleMons[battler].maxHP); + UpdateHpTextInHealthbox(gHealthboxSpriteIds[battler], HP_CURRENT, hpValue, maxHP); } else { @@ -2644,7 +2646,7 @@ void BtlController_HandlePrintString(enum BattlerId battler) if (gTestRunnerEnabled) { TestRunner_Battle_RecordMessage(gDisplayedStringBattle); - if (gTestRunnerHeadless) + if (gTestRunnerHeadless || *stringId == STRINGID_CELEBRATEMESSAGE) { BtlController_Complete(battler); return; @@ -3297,7 +3299,7 @@ void FreeShinyStars(void) enum BattleTrainer GetBattlerTrainer(enum BattlerId battler) { - if (gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleTypeFlags & BATTLE_TYPE_MULTI) + if (gBattleTypeFlags & BATTLE_TYPE_LINK) { switch (gBattlerBattleController[battler]) { @@ -3310,7 +3312,9 @@ enum BattleTrainer GetBattlerTrainer(enum BattlerId battler) case BATTLE_CONTROLLER_LINK_OPPONENT: case BATTLE_CONTROLLER_RECORDED_OPPONENT: case BATTLE_CONTROLLER_OPPONENT: - return (battler & BIT_FLANK) ? B_TRAINER_OPPONENT_B : B_TRAINER_OPPONENT_A; + if (gBattleTypeFlags & BATTLE_TYPE_MULTI) + return (battler & BIT_FLANK) ? B_TRAINER_OPPONENT_B : B_TRAINER_OPPONENT_A; + return B_TRAINER_OPPONENT_A; default: break; } diff --git a/src/battle_frontier.c b/src/battle_frontier.c index b07b7f1e31..e7cea741a4 100644 --- a/src/battle_frontier.c +++ b/src/battle_frontier.c @@ -307,7 +307,7 @@ static void FillTrainerParty(u16 trainerId, enum BattleTrainer trainer, u8 monCo void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 otID, u32 flags, struct Pokemon *dst) { - u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; + enum PokeBall ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball; enum Move move; u32 personality = 0, ability, friendship, j; diff --git a/src/battle_gimmick.c b/src/battle_gimmick.c index aa209ca510..af96bed651 100644 --- a/src/battle_gimmick.c +++ b/src/battle_gimmick.c @@ -109,12 +109,12 @@ void SetGimmickAsActivated(enum BattlerId battler, enum Gimmick gimmick) #define SINGLES_GIMMICK_TRIGGER_POS_X_OPTIMAL (30) #define SINGLES_GIMMICK_TRIGGER_POS_X_PRIORITY (31) #define SINGLES_GIMMICK_TRIGGER_POS_X_SLIDE (15) -#define SINGLES_GIMMICK_TRIGGER_POS_Y_DIFF (-11) +#define SINGLES_GIMMICK_TRIGGER_POS_Y_DIFF (-5) #define DOUBLES_GIMMICK_TRIGGER_POS_X_OPTIMAL (30) #define DOUBLES_GIMMICK_TRIGGER_POS_X_PRIORITY (31) #define DOUBLES_GIMMICK_TRIGGER_POS_X_SLIDE (15) -#define DOUBLES_GIMMICK_TRIGGER_POS_Y_DIFF (-4) +#define DOUBLES_GIMMICK_TRIGGER_POS_Y_DIFF (-2) #define tBattler data[0] #define tHide data[1] diff --git a/src/battle_interface.c b/src/battle_interface.c index fd5392bb21..5cccf61194 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -63,7 +63,7 @@ enum HEALTHBOX_GFX_20, //exp bar [8 pixels] HEALTHBOX_GFX_STATUS_PSN_BATTLER0, //status psn "(P" HEALTHBOX_GFX_22, //status psn "SN" - HEALTHBOX_GFX_23, //status psn "|)"" + HEALTHBOX_GFX_23, //status psn "|)" HEALTHBOX_GFX_STATUS_PRZ_BATTLER0, //status prz HEALTHBOX_GFX_25, HEALTHBOX_GFX_26, diff --git a/src/battle_main.c b/src/battle_main.c index 0e563e1d9e..b99844aa0a 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1986,7 +1986,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer if (B_TRAINER_CLASS_POKE_BALLS >= GEN_7 && ball == -1) { - ball = gTrainerClasses[trainer->trainerClass].ball ?: ITEM_POKE_BALL; + ball = gTrainerClasses[trainer->trainerClass].ball ?: BALL_POKE; SetMonData(&party[i], MON_DATA_POKEBALL, &ball); } } @@ -5560,8 +5560,7 @@ static void HandleEndTurn_FinishBattle(void) } else { - if (gBattleControllerExecFlags == 0) - gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + RunBattleScriptCommands(); } } @@ -5708,8 +5707,7 @@ void RunBattleScriptCommands_PopCallbacksStack(void) } else { - if (gBattleControllerExecFlags == 0) - gBattleScriptingCommandsTable[gBattlescriptCurrInstr[0]](); + RunBattleScriptCommands(); } } diff --git a/src/battle_message.c b/src/battle_message.c index 76f2d2dfe2..f171bcc21b 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -496,7 +496,7 @@ const u8 *const gBattleStringsTable[STRINGID_COUNT] = [STRINGID_PKMNSITEMNORMALIZEDSTATUS] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_LAST_ITEM} normalized its status!"), // Not in Gen 5+ [STRINGID_TRAINER1USEDITEM] = COMPOUND_STRING("{B_ATK_TRAINER_NAME_WITH_CLASS} used {B_LAST_ITEM}!"), [STRINGID_BOXISFULL] = COMPOUND_STRING("The Box is full! You can't catch any more!\p"), - [STRINGID_PKMNSXMADEITINEFFECTIVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s item cannot be removed!"), + [STRINGID_PKMNSXMADEITINEFFECTIVE] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX} made it ineffective!"), [STRINGID_PKMNSXPREVENTSFLINCHING] = COMPOUND_STRING("{B_EFF_NAME_WITH_PREFIX}'s {B_EFF_ABILITY} prevents flinching!"), //not in gen 5+, ability popup [STRINGID_PKMNALREADYHASBURN] = COMPOUND_STRING("{B_DEF_NAME_WITH_PREFIX} is already burned!"), [STRINGID_PKMNSXBLOCKSY] = COMPOUND_STRING("{B_SCR_NAME_WITH_PREFIX}'s {B_SCR_ABILITY} blocks {B_CURRENT_MOVE}!"), //not in gen 5+, ability popup @@ -1354,7 +1354,7 @@ const u16 gItemSwapStringIds[] = const u16 gFlashFireStringIds[] = { [B_MSG_FLASH_FIRE_BOOST] = STRINGID_PKMNRAISEDFIREPOWERWITH, - [B_MSG_FLASH_FIRE_NO_BOOST] = STRINGID_PKMNSXMADEYINEFFECTIVE + [B_MSG_FLASH_FIRE_NO_BOOST] = STRINGID_PKMNSXMADEITINEFFECTIVE }; const u16 gCaughtMonStringIds[] = diff --git a/src/battle_move_resolution.c b/src/battle_move_resolution.c index 15b292ef5b..5c031d392c 100644 --- a/src/battle_move_resolution.c +++ b/src/battle_move_resolution.c @@ -231,6 +231,7 @@ static enum CancelerResult CancelerObedience(struct BattleCalcValues *cv) return CANCELER_RESULT_FAILURE; case DISOBEYS_RANDOM_MOVE: gCurrentMove = gCalledMove = gBattleMons[cv->battlerAtk].moves[gCurrMovePos]; + gBattlescriptCurrInstr = GetMoveBattleScript(gCalledMove); BattleScriptCall(BattleScript_IgnoresAndUsesRandomMove); gBattlerTarget = GetBattleMoveTarget(gCalledMove, TARGET_NONE); return CANCELER_RESULT_RUN_SCRIPT_AND_INCREMENT; @@ -722,13 +723,11 @@ static bool32 IsTargetingSelfOrAlly(enum BattlerId battlerAtk, enum BattlerId ba if (battlerDef == battlerAtk) return skipFailure; - if (battlerDef != BATTLE_PARTNER(battlerAtk)) - { - gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_DOESNT_AFFECT_FOE; - return skipFailure; - } + if (battlerDef == gBattlerTarget) + return checkFailure; - return checkFailure; + gBattleStruct->moveResultFlags[battlerDef] = MOVE_RESULT_DOESNT_AFFECT_FOE; + return skipFailure; } static bool32 IsTargetingFoesAndAlly(enum BattlerId battlerAtk, enum BattlerId battlerDef) @@ -4495,10 +4494,43 @@ static enum MoveResult StatChangeSubstitute(struct BattleCalcValues *cv) return MOVE_RESULT_CONTINUE; } +static void TryAcupressureStatChange(struct BattleCalcValues *cv) +{ + u32 bits = 0; + + if (ShouldSkipStatChangeOnBattler(cv->battlerAtk, cv->battlerDef)) + return; + + for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) + { + if (CompareStat(cv->battlerDef, stat, MAX_STAT_STAGE, CMP_LESS_THAN, cv->abilities[cv->battlerDef])) + bits |= 1u << stat; + } + + if (bits) + { + enum Stat statId; + do + { + statId = (Random() % (NUM_BATTLE_STATS - 1)) + 1; + } while (!(bits & (1u << statId))); + + SetStatChange(cv->battlerDef, statId, 2); + gBattleStruct->moveResultFlags[cv->battlerDef] = MOVE_RESULT_ATTEMPT_STAT_CHANGE; + } + else + { + gBattleStruct->moveResultFlags[cv->battlerDef] = MOVE_RESULT_DOESNT_AFFECT_FOE; + } +} + static enum MoveResult StatChangeCanAnyChange(struct BattleCalcValues *cv) { if (GetMoveEffect(cv->move) == EFFECT_ACUPRESSURE) + { + TryAcupressureStatChange(cv); return MOVE_RESULT_CONTINUE; + } struct StatChange st = { .onlyChecking = TRUE, @@ -4586,34 +4618,6 @@ static enum MoveResult StatChangeBeforeChange(struct BattleCalcValues *cv) return MOVE_RESULT_RUN_SCRIPT_INCREMENT; } break; - case EFFECT_ACUPRESSURE: - { - u32 bits = 0; - for (enum Stat stat = STAT_ATK; stat < NUM_BATTLE_STATS; stat++) - { - if (CompareStat(cv->battlerDef, stat, MAX_STAT_STAGE, CMP_LESS_THAN, cv->abilities[cv->battlerDef])) - bits |= 1u << stat; - } - if (bits) - { - enum Stat statId; - do - { - statId = (Random() % (NUM_BATTLE_STATS - 1)) + 1; - } while (!(bits & (1u << statId))); - - gBattleStruct->moveResultFlags[cv->battlerDef] = MOVE_RESULT_ATTEMPT_STAT_CHANGE; - SetStatChange(cv->battlerDef, statId, 2); - BattleScriptCall(BattleScript_PlayMoveAnim); - return MOVE_RESULT_RUN_SCRIPT_INCREMENT; - } - else - { - gBattlescriptCurrInstr = BattleScript_StatChangeFailed; - return MOVE_RESULT_FAILURE; - } - break; - } case EFFECT_STUFF_CHEEKS: // Back up current queue for later use memcpy( diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 299d998bb3..150169f7f5 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -8659,6 +8659,7 @@ static void Cmd_recoverbasedonsunlight(void) s32 recoverAmount = 0; u32 weather = GetWeather(); u32 attackerWeather = GetAttackerWeather(GetBattlerHoldEffect(gBattlerAttacker), GetBattlerAbility(gBattlerAttacker), weather); + u32 healingWeather = attackerWeather & ~B_WEATHER_STRONG_WINDS; if (GetMoveEffect(gCurrentMove) == EFFECT_SHORE_UP) { if (attackerWeather & B_WEATHER_SANDSTORM) @@ -8670,7 +8671,7 @@ static void Cmd_recoverbasedonsunlight(void) { if (attackerWeather & B_WEATHER_SUN) recoverAmount = 20 * GetNonDynamaxMaxHP(gBattlerAttacker) / 30; - else if (!(GetWeather() & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) + else if (!(healingWeather & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 2; else // not sunny weather recoverAmount = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; @@ -8701,7 +8702,7 @@ static void Cmd_recoverbasedonsunlight(void) } if (attackerWeather & B_WEATHER_SUN) recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 2; - else if (!(attackerWeather & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) + else if (!(healingWeather & B_WEATHER_ANY) || GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_UTILITY_UMBRELLA) recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 4; else // not sunny weather recoverAmount = healingModifier * GetNonDynamaxMaxHP(gBattlerAttacker) / 8; @@ -9691,7 +9692,7 @@ u8 GetCatchingBattler(void) static void FinalizeCapture(void) { - u32 ballId = ItemIdToBallId(gLastThrownBall); + enum PokeBall ballId = ItemIdToBallId(gLastThrownBall); enum NationalDexOrder natDexNo = SpeciesToNationalPokedexNum(gBattleMons[gBattlerTarget].species); if ((GetConfig(B_CRITICAL_CAPTURE_IF_OWNED) >= GEN_9 && GetSetPokedexFlag(natDexNo, FLAG_GET_CAUGHT)) || IsCriticalCapture()) @@ -9739,7 +9740,7 @@ struct BallData static void ComputeBallData(u32 wildMonBattler, u32 playerBattler, struct BallData *ball) { u32 i; - u32 ballId = ItemIdToBallId(gLastUsedItem); + enum PokeBall ballId = ItemIdToBallId(gLastUsedItem); struct BattlePokemon *battleMon = &gBattleMons[wildMonBattler]; ball->multiplier = 100; @@ -9921,6 +9922,8 @@ static void ComputeBallData(u32 wildMonBattler, u32 playerBattler, struct BallDa ball->multiplier = 410; ball->divider = 4096; break; + default: + break; } } diff --git a/src/battle_stat_change.c b/src/battle_stat_change.c index d7da7d93f4..26e98045e4 100644 --- a/src/battle_stat_change.c +++ b/src/battle_stat_change.c @@ -925,6 +925,20 @@ void ClearOtherStatChangeValues(enum BattlerId battler) gBattleStruct->positiveAnimPlayed = 0; } +void ClearBothStatChangeQueues(void) +{ + for (enum BattlerId battler = 0; battler < gBattlersCount; battler++) + { + memset(gSpecialStatuses[battler].statStageQueue2, 0, sizeof(gSpecialStatuses[battler].statStageQueue2)); + gSpecialStatuses[battler].statStageAmount2 = 0; + memset(gSpecialStatuses[battler].statStageQueue, 0, sizeof(gSpecialStatuses[battler].statStageQueue)); + gSpecialStatuses[battler].statStageAmount = 0; + } + gBattleStruct->negativeAnimPlayed = 0; + gBattleStruct->positiveAnimPlayed = 0; + gBattleStruct->statChangeBattler = 0; +} + bool32 CompareStat(enum BattlerId battler, enum Stat statId, u32 cmpTo, u32 cmpKind, enum Ability ability) { bool32 ret = FALSE; diff --git a/src/battle_util.c b/src/battle_util.c index dc3105fc60..58955eb8f4 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -66,7 +66,7 @@ static void ResetParadoxTerrainStat(enum BattlerId battler); static bool32 CanBattlerFormChange(enum BattlerId battler, enum FormChanges method); static bool32 IsPowderMoveBlocked(struct DamageContext *ctx); const u8 *AbsorbedByDrainHpAbility(enum BattlerId battlerDef); -const u8 *AbsorbedByStatIncreaseAbility(enum BattlerId battlerDef, enum Ability abilityDef, enum Stat statId, u32 statAmount); +const u8 *AbsorbedByStatIncreaseAbility(struct DamageContext *ctx, enum Stat statId, u32 statAmount); const u8 *AbsorbedByFlashFire(enum BattlerId battlerDef); static bool32 IsCriticalHit(struct DamageContext *ctx); @@ -448,6 +448,7 @@ void HandleAction_UseMove(void) gBattleStruct->eventState.atkCanceler = 0; ClearDamageCalcResults(); + ClearBothStatChangeQueues(); gMultiHitCounter = 0; gBattleCommunication[MISS_TYPE] = 0; gBattlerTarget = gBattleStruct->moveTarget[gBattlerAttacker]; @@ -1240,13 +1241,19 @@ void UpdateSentPokesToOpponentValue(enum BattlerId battler) void BattleScriptPush(const u8 *bsPtr) { - assertf(gBattleResources->battleScriptsStack->size < UINT8_MAX, "attempted to push a battle script, but battleScriptsStack is full!"); + assertf(gBattleResources->battleScriptsStack->size < ARRAY_COUNT(gBattleResources->battleScriptsStack->ptr), "attempted to push a battle script, but battleScriptsStack is full!") + { + return; + } gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = bsPtr; } void BattleScriptPushCursor(void) { - assertf(gBattleResources->battleScriptsStack->size < UINT8_MAX, "attempted to push cursor, but battleScriptsStack is full!"); + assertf(gBattleResources->battleScriptsStack->size < ARRAY_COUNT(gBattleResources->battleScriptsStack->ptr), "attempted to push cursor, but battleScriptsStack is full!") + { + return; + } gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = gBattlescriptCurrInstr; } @@ -2255,27 +2262,27 @@ bool32 CanAbilityAbsorbMove(struct DamageContext *ctx) break; case ABILITY_MOTOR_DRIVE: if (ctx->moveType == TYPE_ELECTRIC) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_SPEED, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_SPEED, 1); break; case ABILITY_LIGHTNING_ROD: if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && ctx->moveType == TYPE_ELECTRIC) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_SPATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_SPATK, 1); break; case ABILITY_STORM_DRAIN: if (GetConfig(B_REDIRECT_ABILITY_IMMUNITY) >= GEN_5 && ctx->moveType == TYPE_WATER) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_SPATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_SPATK, 1); break; case ABILITY_SAP_SIPPER: if (ctx->moveType == TYPE_GRASS) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_ATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_ATK, 1); break; case ABILITY_WELL_BAKED_BODY: if (ctx->moveType == TYPE_FIRE) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_DEF, 2); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_DEF, 2); break; case ABILITY_WIND_RIDER: if (IsWindMove(ctx->move)) - battleScript = AbsorbedByStatIncreaseAbility(ctx->battlerDef, ctx->abilities[ctx->battlerDef], STAT_ATK, 1); + battleScript = AbsorbedByStatIncreaseAbility(ctx, STAT_ATK, 1); break; case ABILITY_FLASH_FIRE: if (ctx->moveType == TYPE_FIRE && (B_FLASH_FIRE_FROZEN >= GEN_5 || !(gBattleMons[ctx->battlerDef].status1 & STATUS1_FREEZE))) @@ -2327,15 +2334,16 @@ const u8 *AbsorbedByDrainHpAbility(enum BattlerId battlerDef) } } -const u8 *AbsorbedByStatIncreaseAbility(enum BattlerId battlerDef, enum Ability abilityDef, enum Stat statId, u32 statAmount) +const u8 *AbsorbedByStatIncreaseAbility(struct DamageContext *ctx, enum Stat statId, u32 statAmount) { - if (!CompareStat(battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, abilityDef)) + if (!CompareStat(ctx->battlerDef, statId, MAX_STAT_STAGE, CMP_LESS_THAN, ctx->abilities[ctx->battlerDef])) { return BattleScript_AbilityProtectedTarget; } else { - SetStatChange(battlerDef, statId, statAmount); + if (ctx->runScript) + SetStatChange(ctx->battlerDef, statId, statAmount); return BattleScript_MoveStatDrain; } } @@ -5487,10 +5495,9 @@ void ClearVariousBattlerFlags(enum BattlerId battler) gBattleMons[battler].volatiles.grudge = FALSE; } -void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands +void HandleAction_RunBattleScript(void) { - if (gBattleControllerExecFlags == 0) - gBattleScriptingCommandsTable[*gBattlescriptCurrInstr](); + RunBattleScriptCommands(); } u32 SetRandomTarget(enum BattlerId battlerAtk) @@ -6175,7 +6182,7 @@ static inline u32 CalcMoveBasePower(struct DamageContext *ctx) basePower *= 2; break; case EFFECT_WEATHER_BALL: - if (GetAttackerWeather(ctx->holdEffects[ctx->battlerAtk], ctx->abilities[ctx->battlerAtk], ctx->weather) & B_WEATHER_ANY) + if (GetAttackerWeather(ctx->holdEffects[ctx->battlerAtk], ctx->abilities[ctx->battlerAtk], ctx->weather) & (B_WEATHER_ANY & ~B_WEATHER_STRONG_WINDS)) basePower *= 2; break; case EFFECT_PURSUIT: diff --git a/src/bg.c b/src/bg.c index 0ffa35f35f..45397984e8 100644 --- a/src/bg.c +++ b/src/bg.c @@ -289,8 +289,15 @@ bool32 IsInvalidBg(u32 bg) return FALSE; } -// From FRLG. Dummied out. int BgTileAllocOp(int bg, int offset, int count, int mode) +{ + int result = BgTileAllocOpUnchecked(bg, offset, count, mode); + assertf(result > 0); + return result; +} + +// From FRLG. Dummied out. +int BgTileAllocOpUnchecked(int bg, int offset, int count, int mode) { #if IS_FRLG int start, end; diff --git a/src/config_changes.c b/src/config_changes.c index 06e5b6ab6a..6b4bcb65be 100644 --- a/src/config_changes.c +++ b/src/config_changes.c @@ -118,12 +118,13 @@ void SetConfig(enum ConfigTag _config, u32 _value) #if TESTING void TestInitConfigData(void) { + Free(gConfigChangesTestOverride); gConfigChangesTestOverride = Alloc(sizeof(sConfigChanges)); memcpy(gConfigChangesTestOverride, &sConfigChanges, sizeof(sConfigChanges)); } void TestFreeConfigData(void) { - TRY_FREE_AND_SET_NULL(gConfigChangesTestOverride) + FREE_AND_SET_NULL(gConfigChangesTestOverride); } #endif diff --git a/src/credits_frlg.c b/src/credits_frlg.c index 3f6145bc0c..e15e9b7a32 100644 --- a/src/credits_frlg.c +++ b/src/credits_frlg.c @@ -421,9 +421,9 @@ ALIGNED(4) const u8 gCreditsString_Teruki_Murakawa_Souichi_Yamamoto_Kimiko_Nakam ALIGNED(4) const u8 gCreditsString_NOA_Product_Testing[] = _("NOA Product Testing\n\n\n\n\n\n"); ALIGNED(4) const u8 gCreditsString_Thomas_Hertzog_Kathy_Huguenard_Mika_Kurosawa[] = _("\nThomas Hertzog\nKathy Huguenard\nMika Kurosawa\n\n\n"); ALIGNED(4) const u8 gCreditsString_Braille_Code_Check_2[] = _("Braille Code Check\n\n\n\n\n\n"); -ALIGNED(4) const u8 gCreditsString_National_Federation_of_the_Blind_Patricia_A_Maurer_Japan_Braille_Library_European_Blind_Union[] = _("\nNational Federation\n{CLEAR_TO 0x13}of the Blind\nPatricia A. Maurer\nJapan Braille Library\nEuropean Blind Union\n"); +ALIGNED(4) const u8 gCreditsString_National_Federation_of_the_Blind_Patricia_A_Maurer_Japan_Braille_Library_European_Blind_Union[] = _("\nNational Federation\n{CLEAR_TO 19}of the Blind\nPatricia A. Maurer\nJapan Braille Library\nEuropean Blind Union\n"); ALIGNED(4) const u8 gCreditsString_Braille_Code_Check_3[] = _("\nBraille Code Check\n\n\n\n\n"); -ALIGNED(4) const u8 gCreditsString_National_Information_Library_Service_Margaret_Campion[] = _("\n\nNational Information Library\n{CLEAR_TO 0x2D}Service\nMargaret Campion\n\n"); +ALIGNED(4) const u8 gCreditsString_National_Information_Library_Service_Margaret_Campion[] = _("\n\nNational Information Library\n{CLEAR_TO 45}Service\nMargaret Campion\n\n"); ALIGNED(4) const u8 gCreditsString_Special_Thanks_4[] = _("Special Thanks\n\n\n\n\n\n"); ALIGNED(4) const u8 gCreditsString_Takehiro_Izushi_Motoyasu_Tojima_Hitoshi_Yamagami_Hiroyuki_Uesugi[] = _("\nTakehiro Izushi\nMotoyasu Tojima\nHitoshi Yamagami\nHiroyuki Uesugi\n\n"); ALIGNED(4) const u8 gCreditsString_Special_Thanks_5[] = _("Special Thanks\n\n\n\n\n\n"); diff --git a/src/data/graphics/gimmicks.h b/src/data/graphics/gimmicks.h index c7ba9a620d..509d95ec14 100644 --- a/src/data/graphics/gimmicks.h +++ b/src/data/graphics/gimmicks.h @@ -5,7 +5,7 @@ static const u8 ALIGNED(4) sBurstTriggerGfx[] = INCGFX_U8("graphics/battle_inter static const u8 ALIGNED(4) sDynamaxTriggerGfx[] = INCGFX_U8("graphics/battle_interface/dynamax_trigger.png", ".4bpp"); static const u8 ALIGNED(4) sTeraTriggerGfx[] = INCGFX_U8("graphics/battle_interface/tera_trigger.png", ".4bpp"); -static const u16 sMegaTriggerPal[] = INCGFX_U16("graphics/battle_interface/mega_trigger.pal", ".gbapal"); +static const u16 sMegaTriggerPal[] = INCGFX_U16("graphics/battle_interface/mega_trigger.png", ".gbapal"); static const u16 sZMoveTriggerPal[] = INCGFX_U16("graphics/battle_interface/z_move_trigger.png", ".gbapal"); static const u16 sBurstTriggerPal[] = INCGFX_U16("graphics/battle_interface/burst_trigger.png", ".gbapal"); static const u16 sDynamaxTriggerPal[] = INCGFX_U16("graphics/battle_interface/dynamax_trigger.png", ".gbapal"); diff --git a/src/data/graphics/pokemon.h b/src/data/graphics/pokemon.h index 503ca34556..5d354b3ee9 100644 --- a/src/data/graphics/pokemon.h +++ b/src/data/graphics/pokemon.h @@ -15314,9 +15314,9 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_MEGA_EVOLUTIONS #if P_GEN_9_MEGA_EVOLUTIONS - const u32 gMonFrontPic_GarchompMegaZ[] = INCBIN_U32("graphics/pokemon/garchomp/mega_z/front.4bpp.smol"); + const u32 gMonFrontPic_GarchompMegaZ[] = INCGFX_U32("graphics/pokemon/garchomp/mega_z/front.png", ".4bpp.smol"); const u16 gMonPalette_GarchompMegaZ[] = INCGFX_U16("graphics/pokemon/garchomp/mega_z/normal.pal", ".gbapal"); - const u32 gMonBackPic_GarchompMegaZ[] = INCBIN_U32("graphics/pokemon/garchomp/mega_z/back.4bpp.smol"); + const u32 gMonBackPic_GarchompMegaZ[] = INCGFX_U32("graphics/pokemon/garchomp/mega_z/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_GarchompMegaZ[] = INCGFX_U16("graphics/pokemon/garchomp/mega_z/shiny.pal", ".gbapal"); const u8 gMonIcon_GarchompMegaZ[] = INCGFX_U8("graphics/pokemon/garchomp/mega_z/icon.png", ".4bpp"); #if OW_POKEMON_OBJECT_EVENTS && OW_BATTLE_ONLY_FORMS @@ -22017,7 +22017,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_DEWPIDER #if P_FAMILY_FOMANTIS - const u32 gMonFrontPic_Fomantis[] = INCGFX_U32("graphics/pokemon/fomantis/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Fomantis[] = INCGFX_U32("graphics/pokemon/fomantis/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Fomantis[] = INCGFX_U16("graphics/pokemon/fomantis/normal.pal", ".gbapal"); const u32 gMonBackPic_Fomantis[] = INCGFX_U32("graphics/pokemon/fomantis/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Fomantis[] = INCGFX_U16("graphics/pokemon/fomantis/shiny.pal", ".gbapal"); @@ -22051,7 +22051,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_FOMANTIS #if P_FAMILY_MORELULL - const u32 gMonFrontPic_Morelull[] = INCGFX_U32("graphics/pokemon/morelull/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Morelull[] = INCGFX_U32("graphics/pokemon/morelull/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Morelull[] = INCGFX_U16("graphics/pokemon/morelull/normal.pal", ".gbapal"); const u32 gMonBackPic_Morelull[] = INCGFX_U32("graphics/pokemon/morelull/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Morelull[] = INCGFX_U16("graphics/pokemon/morelull/shiny.pal", ".gbapal"); @@ -22067,7 +22067,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Shiinotic[] = INCGFX_U32("graphics/pokemon/shiinotic/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Shiinotic[] = INCGFX_U32("graphics/pokemon/shiinotic/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Shiinotic[] = INCGFX_U16("graphics/pokemon/shiinotic/normal.pal", ".gbapal"); const u32 gMonBackPic_Shiinotic[] = INCGFX_U32("graphics/pokemon/shiinotic/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Shiinotic[] = INCGFX_U16("graphics/pokemon/shiinotic/shiny.pal", ".gbapal"); @@ -22153,7 +22153,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_STUFFUL #if P_FAMILY_BOUNSWEET - const u32 gMonFrontPic_Bounsweet[] = INCGFX_U32("graphics/pokemon/bounsweet/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Bounsweet[] = INCGFX_U32("graphics/pokemon/bounsweet/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Bounsweet[] = INCGFX_U16("graphics/pokemon/bounsweet/normal.pal", ".gbapal"); const u32 gMonBackPic_Bounsweet[] = INCGFX_U32("graphics/pokemon/bounsweet/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Bounsweet[] = INCGFX_U16("graphics/pokemon/bounsweet/shiny.pal", ".gbapal"); @@ -22169,7 +22169,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Steenee[] = INCGFX_U32("graphics/pokemon/steenee/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Steenee[] = INCGFX_U32("graphics/pokemon/steenee/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Steenee[] = INCGFX_U16("graphics/pokemon/steenee/normal.pal", ".gbapal"); const u32 gMonBackPic_Steenee[] = INCGFX_U32("graphics/pokemon/steenee/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Steenee[] = INCGFX_U16("graphics/pokemon/steenee/shiny.pal", ".gbapal"); @@ -22185,7 +22185,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Tsareena[] = INCGFX_U32("graphics/pokemon/tsareena/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Tsareena[] = INCGFX_U32("graphics/pokemon/tsareena/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Tsareena[] = INCGFX_U16("graphics/pokemon/tsareena/normal.pal", ".gbapal"); const u32 gMonBackPic_Tsareena[] = INCGFX_U32("graphics/pokemon/tsareena/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Tsareena[] = INCGFX_U16("graphics/pokemon/tsareena/shiny.pal", ".gbapal"); @@ -22203,7 +22203,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_BOUNSWEET #if P_FAMILY_COMFEY - const u32 gMonFrontPic_Comfey[] = INCGFX_U32("graphics/pokemon/comfey/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Comfey[] = INCGFX_U32("graphics/pokemon/comfey/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Comfey[] = INCGFX_U16("graphics/pokemon/comfey/normal.pal", ".gbapal"); const u32 gMonBackPic_Comfey[] = INCGFX_U32("graphics/pokemon/comfey/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Comfey[] = INCGFX_U16("graphics/pokemon/comfey/shiny.pal", ".gbapal"); @@ -22306,7 +22306,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_WIMPOD #if P_FAMILY_SANDYGAST - const u32 gMonFrontPic_Sandygast[] = INCGFX_U32("graphics/pokemon/sandygast/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Sandygast[] = INCGFX_U32("graphics/pokemon/sandygast/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Sandygast[] = INCGFX_U16("graphics/pokemon/sandygast/normal.pal", ".gbapal"); const u32 gMonBackPic_Sandygast[] = INCGFX_U32("graphics/pokemon/sandygast/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Sandygast[] = INCGFX_U16("graphics/pokemon/sandygast/shiny.pal", ".gbapal"); @@ -22322,7 +22322,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //OW_PKMN_OBJECTS_SHARE_PALETTES #endif //OW_POKEMON_OBJECT_EVENTS - const u32 gMonFrontPic_Palossand[] = INCGFX_U32("graphics/pokemon/palossand/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Palossand[] = INCGFX_U32("graphics/pokemon/palossand/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Palossand[] = INCGFX_U16("graphics/pokemon/palossand/normal.pal", ".gbapal"); const u32 gMonBackPic_Palossand[] = INCGFX_U32("graphics/pokemon/palossand/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Palossand[] = INCGFX_U16("graphics/pokemon/palossand/shiny.pal", ".gbapal"); @@ -22488,7 +22488,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_MINIOR #if P_FAMILY_KOMALA - const u32 gMonFrontPic_Komala[] = INCGFX_U32("graphics/pokemon/komala/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Komala[] = INCGFX_U32("graphics/pokemon/komala/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Komala[] = INCGFX_U16("graphics/pokemon/komala/normal.pal", ".gbapal"); const u32 gMonBackPic_Komala[] = INCGFX_U32("graphics/pokemon/komala/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Komala[] = INCGFX_U16("graphics/pokemon/komala/shiny.pal", ".gbapal"); @@ -22573,7 +22573,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_MIMIKYU #if P_FAMILY_BRUXISH - const u32 gMonFrontPic_Bruxish[] = INCGFX_U32("graphics/pokemon/bruxish/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Bruxish[] = INCGFX_U32("graphics/pokemon/bruxish/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Bruxish[] = INCGFX_U16("graphics/pokemon/bruxish/normal.pal", ".gbapal"); const u32 gMonBackPic_Bruxish[] = INCGFX_U32("graphics/pokemon/bruxish/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Bruxish[] = INCGFX_U16("graphics/pokemon/bruxish/shiny.pal", ".gbapal"); @@ -22624,7 +22624,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_DRAMPA #if P_FAMILY_DHELMISE - const u32 gMonFrontPic_Dhelmise[] = INCGFX_U32("graphics/pokemon/dhelmise/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Dhelmise[] = INCGFX_U32("graphics/pokemon/dhelmise/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Dhelmise[] = INCGFX_U16("graphics/pokemon/dhelmise/normal.pal", ".gbapal"); const u32 gMonBackPic_Dhelmise[] = INCGFX_U32("graphics/pokemon/dhelmise/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Dhelmise[] = INCGFX_U16("graphics/pokemon/dhelmise/shiny.pal", ".gbapal"); @@ -22764,7 +22764,7 @@ const u32 gObjectEventPic_Substitute[] = INCGFX_COMP("graphics/pokemon/question_ #endif //P_FAMILY_TAPU_FINI #if P_FAMILY_COSMOG - const u32 gMonFrontPic_Cosmog[] = INCGFX_U32("graphics/pokemon/cosmog/front.png", ".4bpp.smol"); + const u32 gMonFrontPic_Cosmog[] = INCGFX_U32("graphics/pokemon/cosmog/anim_front.png", ".4bpp.smol"); const u16 gMonPalette_Cosmog[] = INCGFX_U16("graphics/pokemon/cosmog/normal.pal", ".gbapal"); const u32 gMonBackPic_Cosmog[] = INCGFX_U32("graphics/pokemon/cosmog/back.png", ".4bpp.smol"); const u16 gMonShinyPalette_Cosmog[] = INCGFX_U16("graphics/pokemon/cosmog/shiny.pal", ".gbapal"); diff --git a/src/data/items.h b/src/data/items.h index e0e4de468e..8f3662ec97 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -14669,6 +14669,7 @@ const struct ItemInfo gItemsInfo[] = "prevented for this\n" "items's holder."), .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_HELD_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, .flingPower = 30, @@ -15779,6 +15780,7 @@ const struct ItemInfo gItemsInfo[] = .price = 1200, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_AUX_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, //.effect = currently missing @@ -15792,6 +15794,7 @@ const struct ItemInfo gItemsInfo[] = .price = 1200, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_AUX_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, //.effect = currently missing @@ -15806,6 +15809,7 @@ const struct ItemInfo gItemsInfo[] = .price = 1600, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, + .sortType = ITEM_TYPE_AUX_ITEM, .type = ITEM_USE_BAG_MENU, .fieldUseFunc = ItemUseOutOfBattle_CannotUse, //.effect = currently missing diff --git a/src/data/pokemon/species_info/gen_7_families.h b/src/data/pokemon/species_info/gen_7_families.h index 1558e80f80..5ff7bdb6ac 100644 --- a/src/data/pokemon/species_info/gen_7_families.h +++ b/src/data/pokemon/species_info/gen_7_families.h @@ -3029,8 +3029,15 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Fomantis, .frontPicSize = MON_COORDS_SIZE(40, 48), .frontPicYOffset = 11, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE_SLOW, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 15), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 25), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_TIP_MOVE_FORWARD, .backPic = gMonBackPic_Fomantis, .backPicSize = MON_COORDS_SIZE(40, 56), .backPicYOffset = 5, @@ -3227,8 +3234,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Morelull, .frontPicSize = MON_COORDS_SIZE(24, 48), .frontPicYOffset = 10, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_SHAKE_FLASH_YELLOW, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 55), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_GLOW_YELLOW, .backPic = gMonBackPic_Morelull, .backPicSize = MON_COORDS_SIZE(40, 48), .backPicYOffset = 9, @@ -3294,7 +3304,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Shiinotic, .frontPicSize = MON_COORDS_SIZE(56, 56), .frontPicYOffset = 4, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 55), + ANIMCMD_FRAME(1, 55), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_SHAKE_GLOW_WHITE_SLOW, .backPic = gMonBackPic_Shiinotic, .backPicSize = MON_COORDS_SIZE(64, 48), @@ -3695,7 +3709,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Bounsweet, .frontPicSize = MON_COORDS_SIZE(32, 40), .frontPicYOffset = 16, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, .backPic = gMonBackPic_Bounsweet, .backPicSize = MON_COORDS_SIZE(48, 40), @@ -3762,8 +3779,13 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Steenee, .frontPicSize = MON_COORDS_SIZE(48, 56), .frontPicYOffset = 7, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_V_SQUISH_AND_BOUNCE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 15), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_V_JUMPS_BIG, .backPic = gMonBackPic_Steenee, .backPicSize = MON_COORDS_SIZE(56, 56), .backPicYOffset = 8, @@ -3828,8 +3850,13 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Tsareena, .frontPicSize = MON_COORDS_SIZE(56, 64), .frontPicYOffset = 1, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_SHRINK_GROW, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 40), + ANIMCMD_FRAME(1, 15), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_V_STRETCH, .backPic = gMonBackPic_Tsareena, .backPicSize = MON_COORDS_SIZE(56, 56), .backPicYOffset = 6, @@ -3895,8 +3922,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Comfey, .frontPicSize = MON_COORDS_SIZE(48, 48), .frontPicYOffset = 9, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_H_SLIDE_WOBBLE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_CIRCULAR_STRETCH_TWICE, .enemyMonElevation = 8, .backPic = gMonBackPic_Comfey, .backPicSize = MON_COORDS_SIZE(64, 56), @@ -4300,8 +4330,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Sandygast, .frontPicSize = MON_COORDS_SIZE(48, 48), .frontPicYOffset = 11, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_CIRCULAR_STRETCH_TWICE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 50), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_H_SHAKE, .backPic = gMonBackPic_Sandygast, .backPicSize = MON_COORDS_SIZE(40, 48), .backPicYOffset = 11, @@ -4367,8 +4400,11 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Palossand, .frontPicSize = MON_COORDS_SIZE(64, 64), .frontPicYOffset = 0, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_H_VIBRATE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 50), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_GROW_VIBRATE, .backPic = gMonBackPic_Palossand, .backPicSize = MON_COORDS_SIZE(64, 64), .backPicYOffset = 2, @@ -4780,7 +4816,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Komala, .frontPicSize = MON_COORDS_SIZE(48, 40), .frontPicYOffset = 12, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 60), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_H_DIP, .backPic = gMonBackPic_Komala, .backPicSize = MON_COORDS_SIZE(64, 48), @@ -5286,8 +5325,13 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Bruxish, .frontPicSize = MON_COORDS_SIZE(56, 40), .frontPicYOffset = 15, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, - .frontAnimId = ANIM_RISING_WOBBLE, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 20), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 1), + ), + .frontAnimId = ANIM_H_SPRING, .backPic = gMonBackPic_Bruxish, .backPicSize = MON_COORDS_SIZE(64, 48), .backPicYOffset = 14, @@ -5486,7 +5530,16 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Dhelmise, .frontPicSize = MON_COORDS_SIZE(48, 64), .frontPicYOffset = 1, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 10), + ANIMCMD_FRAME(1, 10), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_SWING_CONVEX, .enemyMonElevation = 2, .backPic = gMonBackPic_Dhelmise, @@ -6117,7 +6170,10 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPic = gMonFrontPic_Cosmog, .frontPicSize = MON_COORDS_SIZE(56, 48), .frontPicYOffset = 10, - .frontAnimFrames = sAnims_SingleFramePlaceHolder, + .frontAnimFrames = ANIM_FRAMES( + ANIMCMD_FRAME(1, 30), + ANIMCMD_FRAME(0, 1), + ), .frontAnimId = ANIM_H_JUMPS_V_STRETCH, .enemyMonElevation = 7, .backPic = gMonBackPic_Cosmog, diff --git a/src/data/script_menu.h b/src/data/script_menu.h index 843a6a10cf..a4260e72c5 100644 --- a/src/data/script_menu.h +++ b/src/data/script_menu.h @@ -216,9 +216,9 @@ static const struct MenuAction MultichoiceList_Mechadoll5_Q3[] = static const struct MenuAction MultichoiceList_VendingMachine[] = { - {COMPOUND_STRING("FRESH WATER{CLEAR_TO 0x48}¥200")}, - {COMPOUND_STRING("SODA POP{CLEAR_TO 0x48}¥300")}, - {COMPOUND_STRING("LEMONADE{CLEAR_TO 0x48}¥350")}, + {COMPOUND_STRING("FRESH WATER{CLEAR_TO 72}¥200")}, + {COMPOUND_STRING("SODA POP{CLEAR_TO 72}¥300")}, + {COMPOUND_STRING("LEMONADE{CLEAR_TO 72}¥350")}, {gText_Exit}, }; @@ -273,11 +273,11 @@ static const struct MenuAction MultichoiceList_GameCornerDolls[] = static const struct MenuAction MultichoiceList_GameCornerTMs[] = { - {COMPOUND_STRING("TM32{CLEAR_TO 0x48}1,500 COINS")}, - {COMPOUND_STRING("TM29{CLEAR_TO 0x48}3,500 COINS")}, - {COMPOUND_STRING("TM35{CLEAR_TO 0x48}4,000 COINS")}, - {COMPOUND_STRING("TM24{CLEAR_TO 0x48}4,000 COINS")}, - {COMPOUND_STRING("TM13{CLEAR_TO 0x48}4,000 COINS")}, + {COMPOUND_STRING("TM32{CLEAR_TO 72}1,500 COINS")}, + {COMPOUND_STRING("TM29{CLEAR_TO 72}3,500 COINS")}, + {COMPOUND_STRING("TM35{CLEAR_TO 72}4,000 COINS")}, + {COMPOUND_STRING("TM24{CLEAR_TO 72}4,000 COINS")}, + {COMPOUND_STRING("TM13{CLEAR_TO 72}4,000 COINS")}, {gText_Exit}, }; @@ -817,7 +817,7 @@ static const struct MenuAction MultichoiceList_BerryPlot[] = }; static const struct MenuAction sMultichoiceList_BikeShop[] = { - {COMPOUND_STRING("BICYCLE{CLEAR_TO 0x49}{FONT_SMALL}¥1,000,000")}, + {COMPOUND_STRING("BICYCLE{CLEAR_TO 73}{FONT_SMALL}¥1,000,000")}, {COMPOUND_STRING("NO THANKS")} }; @@ -909,36 +909,36 @@ const u8 sText_NoThanks[] = _("NO THANKS"); static const struct MenuAction sMultichoiceList_GameCornerPokemonPrizes[] = { #if defined(FIRERED) - {COMPOUND_STRING("ABRA{CLEAR_TO 0x55}{FONT_SMALL} 180 COINS")}, - {COMPOUND_STRING("CLEFAIRY{CLEAR_TO 0x55}{FONT_SMALL} 500 COINS")}, - {COMPOUND_STRING("DRATINI{CLEAR_TO 0x4B}{FONT_SMALL} 2,800 COINS")}, - {COMPOUND_STRING("SCYTHER{CLEAR_TO 0x4B}{FONT_SMALL} 5,500 COINS")}, - {COMPOUND_STRING("PORYGON{CLEAR_TO 0x4B}{FONT_SMALL} 9,999 COINS")}, + {COMPOUND_STRING("ABRA{CLEAR_TO 85}{FONT_SMALL} 180 COINS")}, + {COMPOUND_STRING("CLEFAIRY{CLEAR_TO 85}{FONT_SMALL} 500 COINS")}, + {COMPOUND_STRING("DRATINI{CLEAR_TO 75}{FONT_SMALL} 2,800 COINS")}, + {COMPOUND_STRING("SCYTHER{CLEAR_TO 75}{FONT_SMALL} 5,500 COINS")}, + {COMPOUND_STRING("PORYGON{CLEAR_TO 75}{FONT_SMALL} 9,999 COINS")}, #else - {COMPOUND_STRING("ABRA{CLEAR_TO 0x55}{FONT_SMALL} 120 COINS")}, - {COMPOUND_STRING("CLEFAIRY{CLEAR_TO 0x55}{FONT_SMALL} 750 COINS")}, - {COMPOUND_STRING("PINSIR{CLEAR_TO 0x4B}{FONT_SMALL} 2,500 COINS")}, - {COMPOUND_STRING("DRATINI{CLEAR_TO 0x4B}{FONT_SMALL} 4,600 COINS")}, - {COMPOUND_STRING("PORYGON{CLEAR_TO 0x4B}{FONT_SMALL} 6,500 COINS")}, + {COMPOUND_STRING("ABRA{CLEAR_TO 85}{FONT_SMALL} 120 COINS")}, + {COMPOUND_STRING("CLEFAIRY{CLEAR_TO 85}{FONT_SMALL} 750 COINS")}, + {COMPOUND_STRING("PINSIR{CLEAR_TO 75}{FONT_SMALL} 2,500 COINS")}, + {COMPOUND_STRING("DRATINI{CLEAR_TO 75}{FONT_SMALL} 4,600 COINS")}, + {COMPOUND_STRING("PORYGON{CLEAR_TO 75}{FONT_SMALL} 6,500 COINS")}, #endif {sText_NoThanks} }; static const struct MenuAction sMultichoiceList_GameCornerTMPrizes[] = { - {COMPOUND_STRING("TM13{CLEAR_TO 0x48}{FONT_SMALL}4,000 COINS")}, - {COMPOUND_STRING("TM23{CLEAR_TO 0x48}{FONT_SMALL}3,500 COINS")}, - {COMPOUND_STRING("TM24{CLEAR_TO 0x48}{FONT_SMALL}4,000 COINS")}, - {COMPOUND_STRING("TM30{CLEAR_TO 0x48}{FONT_SMALL}4,500 COINS")}, - {COMPOUND_STRING("TM35{CLEAR_TO 0x48}{FONT_SMALL}4,000 COINS")}, + {COMPOUND_STRING("TM13{CLEAR_TO 72}{FONT_SMALL}4,000 COINS")}, + {COMPOUND_STRING("TM23{CLEAR_TO 72}{FONT_SMALL}3,500 COINS")}, + {COMPOUND_STRING("TM24{CLEAR_TO 72}{FONT_SMALL}4,000 COINS")}, + {COMPOUND_STRING("TM30{CLEAR_TO 72}{FONT_SMALL}4,500 COINS")}, + {COMPOUND_STRING("TM35{CLEAR_TO 72}{FONT_SMALL}4,000 COINS")}, {sText_NoThanks} }; static const struct MenuAction sMultichoiceList_GameCornerBattleItemPrizes[] = { - {COMPOUND_STRING("SMOKE BALL{CLEAR_TO 0x5A}{FONT_SMALL}800 COINS")}, - {COMPOUND_STRING("MIRACLE SEED{CLEAR_TO 0x50}{FONT_SMALL}1,000 COINS")}, - {COMPOUND_STRING("CHARCOAL{CLEAR_TO 0x50}{FONT_SMALL}1,000 COINS")}, - {COMPOUND_STRING("MYSTIC WATER{CLEAR_TO 0x50}{FONT_SMALL}1,000 COINS")}, - {COMPOUND_STRING("YELLOW FLUTE{CLEAR_TO 0x50}{FONT_SMALL}1,600 COINS")}, + {COMPOUND_STRING("SMOKE BALL{CLEAR_TO 90}{FONT_SMALL}800 COINS")}, + {COMPOUND_STRING("MIRACLE SEED{CLEAR_TO 80}{FONT_SMALL}1,000 COINS")}, + {COMPOUND_STRING("CHARCOAL{CLEAR_TO 80}{FONT_SMALL}1,000 COINS")}, + {COMPOUND_STRING("MYSTIC WATER{CLEAR_TO 80}{FONT_SMALL}1,000 COINS")}, + {COMPOUND_STRING("YELLOW FLUTE{CLEAR_TO 80}{FONT_SMALL}1,600 COINS")}, {sText_NoThanks} }; @@ -952,8 +952,8 @@ static const struct MenuAction sMultichoiceList_DeptStoreElevator[] = { }; static const struct MenuAction sMultichoiceList_GameCornerCoinPurchaseCounter[] = { - {COMPOUND_STRING("{FONT_SMALL} 50 COINS{CLEAR_TO 0x45}¥1,000")}, - {COMPOUND_STRING("{FONT_SMALL}500 COINS{CLEAR_TO 0x40}¥10,000")}, + {COMPOUND_STRING("{FONT_SMALL} 50 COINS{CLEAR_TO 69}¥1,000")}, + {COMPOUND_STRING("{FONT_SMALL}500 COINS{CLEAR_TO 64}¥10,000")}, {gText_Exit} }; @@ -965,9 +965,9 @@ static const struct MenuAction sMultichoiceList_LinkedDirectUnion[] = { }; static const struct MenuAction sMultichoiceList_CeladonVendingMachine[] = { - {COMPOUND_STRING("FRESH WATER{CLEAR_TO 0x57}{FONT_SMALL}¥200")}, - {COMPOUND_STRING("SODA POP{CLEAR_TO 0x57}{FONT_SMALL}¥300")}, - {COMPOUND_STRING("LEMONADE{CLEAR_TO 0x57}{FONT_SMALL}¥350")}, + {COMPOUND_STRING("FRESH WATER{CLEAR_TO 87}{FONT_SMALL}¥200")}, + {COMPOUND_STRING("SODA POP{CLEAR_TO 87}{FONT_SMALL}¥300")}, + {COMPOUND_STRING("LEMONADE{CLEAR_TO 87}{FONT_SMALL}¥350")}, {gText_Exit} }; diff --git a/src/field_specials.c b/src/field_specials.c index 9cf4137653..e2cbe8b7f9 100644 --- a/src/field_specials.c +++ b/src/field_specials.c @@ -2543,48 +2543,48 @@ static const u8 *const sScrollableMultichoiceOptions[][MAX_SCROLL_MULTI_LENGTH] }, [SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_1] = { - COMPOUND_STRING("KISS POSTER{CLEAR_TO 0x5E}16BP"), - COMPOUND_STRING("KISS CUSHION{CLEAR_TO 0x5E}32BP"), - COMPOUND_STRING("SMOOCHUM DOLL{CLEAR_TO 0x5E}32BP"), - COMPOUND_STRING("TOGEPI DOLL{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("MEOWTH DOLL{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("CLEFAIRY DOLL{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("DITTO DOLL{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("CYNDAQUIL DOLL{CLEAR_TO 0x5E}80BP"), - COMPOUND_STRING("CHIKORITA DOLL{CLEAR_TO 0x5E}80BP"), - COMPOUND_STRING("TOTODILE DOLL{CLEAR_TO 0x5E}80BP"), + COMPOUND_STRING("KISS POSTER{CLEAR_TO 94}16BP"), + COMPOUND_STRING("KISS CUSHION{CLEAR_TO 94}32BP"), + COMPOUND_STRING("SMOOCHUM DOLL{CLEAR_TO 94}32BP"), + COMPOUND_STRING("TOGEPI DOLL{CLEAR_TO 94}48BP"), + COMPOUND_STRING("MEOWTH DOLL{CLEAR_TO 94}48BP"), + COMPOUND_STRING("CLEFAIRY DOLL{CLEAR_TO 94}48BP"), + COMPOUND_STRING("DITTO DOLL{CLEAR_TO 94}48BP"), + COMPOUND_STRING("CYNDAQUIL DOLL{CLEAR_TO 94}80BP"), + COMPOUND_STRING("CHIKORITA DOLL{CLEAR_TO 94}80BP"), + COMPOUND_STRING("TOTODILE DOLL{CLEAR_TO 94}80BP"), gText_Exit }, [SCROLL_MULTI_BF_EXCHANGE_CORNER_DECOR_VENDOR_2] = { - COMPOUND_STRING("LAPRAS DOLL{CLEAR_TO 0x58}128BP"), - COMPOUND_STRING("SNORLAX DOLL{CLEAR_TO 0x58}128BP"), - COMPOUND_STRING("VENUSAUR DOLL{CLEAR_TO 0x58}256BP"), - COMPOUND_STRING("CHARIZARD DOLL{CLEAR_TO 0x58}256BP"), - COMPOUND_STRING("BLASTOISE DOLL{CLEAR_TO 0x58}256BP"), + COMPOUND_STRING("LAPRAS DOLL{CLEAR_TO 88}128BP"), + COMPOUND_STRING("SNORLAX DOLL{CLEAR_TO 88}128BP"), + COMPOUND_STRING("VENUSAUR DOLL{CLEAR_TO 88}256BP"), + COMPOUND_STRING("CHARIZARD DOLL{CLEAR_TO 88}256BP"), + COMPOUND_STRING("BLASTOISE DOLL{CLEAR_TO 88}256BP"), gText_Exit }, [SCROLL_MULTI_BF_EXCHANGE_CORNER_VITAMIN_VENDOR] = { - COMPOUND_STRING("PROTEIN{CLEAR_TO 0x64}1BP"), - COMPOUND_STRING("CALCIUM{CLEAR_TO 0x64}1BP"), - COMPOUND_STRING("IRON{CLEAR_TO 0x64}1BP"), - COMPOUND_STRING("ZINC{CLEAR_TO 0x64}1BP"), - COMPOUND_STRING("CARBOS{CLEAR_TO 0x64}1BP"), - COMPOUND_STRING("HP UP{CLEAR_TO 0x64}1BP"), + COMPOUND_STRING("PROTEIN{CLEAR_TO 100}1BP"), + COMPOUND_STRING("CALCIUM{CLEAR_TO 100}1BP"), + COMPOUND_STRING("IRON{CLEAR_TO 100}1BP"), + COMPOUND_STRING("ZINC{CLEAR_TO 100}1BP"), + COMPOUND_STRING("CARBOS{CLEAR_TO 100}1BP"), + COMPOUND_STRING("HP UP{CLEAR_TO 100}1BP"), gText_Exit }, [SCROLL_MULTI_BF_EXCHANGE_CORNER_HOLD_ITEM_VENDOR] = { - COMPOUND_STRING("LEFTOVERS{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("WHITE HERB{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("QUICK CLAW{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("MENTAL HERB{CLEAR_TO 0x5E}48BP"), - COMPOUND_STRING("BRIGHTPOWDER{CLEAR_TO 0x5E}64BP"), - COMPOUND_STRING("CHOICE BAND{CLEAR_TO 0x5E}64BP"), - COMPOUND_STRING("KING'S ROCK{CLEAR_TO 0x5E}64BP"), - COMPOUND_STRING("FOCUS BAND{CLEAR_TO 0x5E}64BP"), - COMPOUND_STRING("SCOPE LENS{CLEAR_TO 0x5E}64BP"), + COMPOUND_STRING("LEFTOVERS{CLEAR_TO 94}48BP"), + COMPOUND_STRING("WHITE HERB{CLEAR_TO 94}48BP"), + COMPOUND_STRING("QUICK CLAW{CLEAR_TO 94}48BP"), + COMPOUND_STRING("MENTAL HERB{CLEAR_TO 94}48BP"), + COMPOUND_STRING("BRIGHTPOWDER{CLEAR_TO 94}64BP"), + COMPOUND_STRING("CHOICE BAND{CLEAR_TO 94}64BP"), + COMPOUND_STRING("KING'S ROCK{CLEAR_TO 94}64BP"), + COMPOUND_STRING("FOCUS BAND{CLEAR_TO 94}64BP"), + COMPOUND_STRING("SCOPE LENS{CLEAR_TO 94}64BP"), gText_Exit }, [SCROLL_MULTI_BERRY_POWDER_VENDOR] = @@ -2617,30 +2617,30 @@ static const u8 *const sScrollableMultichoiceOptions[][MAX_SCROLL_MULTI_LENGTH] }, [SCROLL_MULTI_BF_MOVE_TUTOR_1] = { - COMPOUND_STRING("SOFTBOILED{CLEAR_TO 0x4E}16BP"), - COMPOUND_STRING("SEISMIC TOSS{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("DREAM EATER{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("MEGA PUNCH{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("MEGA KICK{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("BODY SLAM{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("ROCK SLIDE{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("COUNTER{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("THUNDER WAVE{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("SWORDS DANCE{CLEAR_TO 0x4E}48BP"), + COMPOUND_STRING("SOFTBOILED{CLEAR_TO 78}16BP"), + COMPOUND_STRING("SEISMIC TOSS{CLEAR_TO 78}24BP"), + COMPOUND_STRING("DREAM EATER{CLEAR_TO 78}24BP"), + COMPOUND_STRING("MEGA PUNCH{CLEAR_TO 78}24BP"), + COMPOUND_STRING("MEGA KICK{CLEAR_TO 78}48BP"), + COMPOUND_STRING("BODY SLAM{CLEAR_TO 78}48BP"), + COMPOUND_STRING("ROCK SLIDE{CLEAR_TO 78}48BP"), + COMPOUND_STRING("COUNTER{CLEAR_TO 78}48BP"), + COMPOUND_STRING("THUNDER WAVE{CLEAR_TO 78}48BP"), + COMPOUND_STRING("SWORDS DANCE{CLEAR_TO 78}48BP"), gText_Exit }, [SCROLL_MULTI_BF_MOVE_TUTOR_2] = { - COMPOUND_STRING("DEFENSE CURL{CLEAR_TO 0x4E}16BP"), - COMPOUND_STRING("SNORE{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("MUD-SLAP{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("SWIFT{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("ICY WIND{CLEAR_TO 0x4E}24BP"), - COMPOUND_STRING("ENDURE{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("PSYCH UP{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("ICE PUNCH{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("THUNDERPUNCH{CLEAR_TO 0x4E}48BP"), - COMPOUND_STRING("FIRE PUNCH{CLEAR_TO 0x4E}48BP"), + COMPOUND_STRING("DEFENSE CURL{CLEAR_TO 78}16BP"), + COMPOUND_STRING("SNORE{CLEAR_TO 78}24BP"), + COMPOUND_STRING("MUD-SLAP{CLEAR_TO 78}24BP"), + COMPOUND_STRING("SWIFT{CLEAR_TO 78}24BP"), + COMPOUND_STRING("ICY WIND{CLEAR_TO 78}24BP"), + COMPOUND_STRING("ENDURE{CLEAR_TO 78}48BP"), + COMPOUND_STRING("PSYCH UP{CLEAR_TO 78}48BP"), + COMPOUND_STRING("ICE PUNCH{CLEAR_TO 78}48BP"), + COMPOUND_STRING("THUNDERPUNCH{CLEAR_TO 78}48BP"), + COMPOUND_STRING("FIRE PUNCH{CLEAR_TO 78}48BP"), gText_Exit }, [SCROLL_MULTI_SS_TIDAL_DESTINATION] = diff --git a/src/item.c b/src/item.c index cec77d7dfb..e060343c30 100644 --- a/src/item.c +++ b/src/item.c @@ -34,6 +34,8 @@ static bool32 CheckPyramidBagHasSpace(enum Item itemId, u16 count); static const u8 *GetItemPluralName(enum Item); static bool32 DoesItemHavePluralName(enum Item); static void NONNULL BagPocket_CompactItems(struct BagPocket *pocket); +static u16 SanitizeItemId(enum Item itemId); +static u16 SanitizeBagItemId(enum Item itemId); EWRAM_DATA struct BagPocket gBagPockets[POCKETS_COUNT] = {0}; @@ -347,7 +349,8 @@ static bool32 NONNULL BagPocket_AddItem(struct BagPocket *pocket, enum Item item bool32 AddBagItem(enum Item itemId, u16 count) { - if (GetItemPocket(itemId) >= POCKETS_COUNT) + itemId = SanitizeBagItemId(itemId); + if (itemId == ITEM_NONE) return FALSE; // check Battle Pyramid Bag @@ -403,7 +406,8 @@ static bool32 NONNULL BagPocket_RemoveItem(struct BagPocket *pocket, enum Item i bool32 RemoveBagItem(enum Item itemId, u16 count) { - if (GetItemPocket(itemId) >= POCKETS_COUNT || itemId == ITEM_NONE) + itemId = SanitizeBagItemId(itemId); + if (itemId == ITEM_NONE) return FALSE; // check Battle Pyramid Bag @@ -789,6 +793,23 @@ static u16 SanitizeItemId(enum Item itemId) return itemId; } +static u16 SanitizeBagItemId(enum Item itemId) +{ + itemId = SanitizeItemId(itemId); + + assertf(itemId != ITEM_NONE, "invalid bag item: ITEM_NONE") + { + return ITEM_NONE; + } + + assertf(GetItemPocket(itemId) < POCKETS_COUNT, "invalid bag item pocket: %S", gItemsInfo[itemId].name) + { + return ITEM_NONE; + } + + return itemId; +} + const u8 *GetItemName(enum Item itemId) { const u8 *name = gItemsInfo[SanitizeItemId(itemId)].name; diff --git a/src/malloc.c b/src/malloc.c index f31c4e024e..2f457bfddd 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -27,7 +27,7 @@ void PutFirstMemBlockHeader(void *block, u32 size) PutMemBlockHeader(block, (struct MemBlock *)block, (struct MemBlock *)block, size - sizeof(struct MemBlock)); } -void *AllocInternal(void *heapStart, u32 size, const char *location) +static void *AllocInternal(void *heapStart, u32 size, const char *location) { struct MemBlock *pos = (struct MemBlock *)heapStart; struct MemBlock *head = pos; @@ -81,36 +81,14 @@ void *AllocInternal(void *heapStart, u32 size, const char *location) } } -#if TESTING if (pos->next == head) - { - const struct MemBlock *head = HeapHead(); - const struct MemBlock *block = head; - do - { - if (block->allocated) - { - const char *location = MemBlockLocation(block); - if (location) - Test_MgbaPrintf("%s: %d bytes allocated", location, block->size); - else - Test_MgbaPrintf(": %d bytes allocated", block->size); - } - block = block->next; - } - while (block != head); - } -#endif - assertf(pos->next != head, "%s: out of memory trying to allocate %d bytes", location, size) - { return NULL; - } pos = pos->next; } } -void FreeInternal(void *heapStart, void *pointer) +static void FreeInternal(void *heapStart, void *pointer) { if (pointer) { @@ -154,7 +132,7 @@ void FreeInternal(void *heapStart, void *pointer) } } -void *AllocZeroedInternal(void *heapStart, u32 size, const char *location) +static void *AllocZeroedInternal(void *heapStart, u32 size, const char *location) { void *mem = AllocInternal(heapStart, size, location); @@ -169,7 +147,7 @@ void *AllocZeroedInternal(void *heapStart, u32 size, const char *location) return mem; } -bool32 CheckMemBlockInternal(void *heapStart, void *pointer) +static bool32 CheckMemBlockInternal(void *heapStart, void *pointer) { struct MemBlock *head = (struct MemBlock *)heapStart; struct MemBlock *block = (struct MemBlock *)((u8 *)pointer - sizeof(struct MemBlock)); @@ -202,12 +180,55 @@ void InitHeap(void *heapStart, u32 heapSize) PutFirstMemBlockHeader(heapStart, heapSize); } +void PrintHeap(void) +{ + const struct MemBlock *head = HeapHead(); + const struct MemBlock *block = head; + do + { + if (block->allocated) + { + const char *location = MemBlockLocation(block); + if (location) + DebugPrintf("%s: %d bytes allocated", location, block->size); + else + DebugPrintf(": %d bytes allocated", block->size); + } + block = block->next; + } + while (block != head); +} + void *Alloc_(u32 size, const char *location) +{ + void *p = AllocInternal(sHeapStart, size, location); + if (!p) + { + if (TESTING) + PrintHeap(); + errorf("%s: out of memory trying to allocate %d bytes", location, size); + } + return p; +} + +void *AllocUnchecked_(u32 size, const char *location) { return AllocInternal(sHeapStart, size, location); } void *AllocZeroed_(u32 size, const char *location) +{ + void *p = AllocZeroedInternal(sHeapStart, size, location); + if (!p) + { + if (TESTING) + PrintHeap(); + errorf("%s: out of memory trying to allocate %d bytes", location, size); + } + return p; +} + +void *AllocZeroedUnchecked_(u32 size, const char *location) { return AllocZeroedInternal(sHeapStart, size, location); } diff --git a/src/mini_printf.c b/src/mini_printf.c index 31d72dcd17..74ceb5bad5 100644 --- a/src/mini_printf.c +++ b/src/mini_printf.c @@ -47,7 +47,7 @@ struct mini_buff u32 buffer_len; }; -static inline char mini_pchar_decode(char encoded) +char mini_pchar_decode(char encoded) { char ret = '?'; if (encoded >= CHAR_a && encoded <= CHAR_z) diff --git a/src/party_menu.c b/src/party_menu.c index e72ce71737..aa70440700 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -2119,19 +2119,27 @@ static void GiveItemToMon(struct Pokemon *mon, enum Item item) TryItemHoldFormChange(&gParties[B_TRAINER_PLAYER][gPartyMenu.slotId], gPartyMenu.slotId, B_TRAINER_PLAYER); } -static u8 TryTakeMonItem(struct Pokemon *mon) +enum TryTakeMonItemResult +{ + TAKE_NO_ITEM, + TAKE_NO_BAG_SPACE, + TAKE_OK, +}; + +static enum TryTakeMonItemResult TryTakeMonItem(struct Pokemon *mon) { enum Item item = GetMonData(mon, MON_DATA_HELD_ITEM); if (item == ITEM_NONE) - return 0; - if (AddBagItem(item, 1) == FALSE) - return 1; + return TAKE_NO_ITEM; + + if (!AddBagItem(item, 1)) + return TAKE_NO_BAG_SPACE; item = ITEM_NONE; SetMonData(mon, MON_DATA_HELD_ITEM, &item); TryItemHoldFormChange(&gParties[B_TRAINER_PLAYER][gPartyMenu.slotId], gPartyMenu.slotId, B_TRAINER_PLAYER); - return 2; + return TAKE_OK; } static void BufferBagFullCantTakeItemMessage(u16 itemUnused) @@ -3652,16 +3660,16 @@ static void CursorCb_TakeItem(u8 taskId) PartyMenuRemoveWindow(&sPartyMenuInternal->windowId[1]); switch (TryTakeMonItem(mon)) { - case 0: // Not holding item + case TAKE_NO_ITEM: GetMonNickname(mon, gStringVar1); StringExpandPlaceholders(gStringVar4, gText_PkmnNotHolding); DisplayPartyMenuMessage(gStringVar4, TRUE); break; - case 1: // No room to take item + case TAKE_NO_BAG_SPACE: BufferBagFullCantTakeItemMessage(item); DisplayPartyMenuMessage(gStringVar4, TRUE); break; - default: // Took item + case TAKE_OK: DisplayTookHeldItemMessage(mon, item, TRUE); break; } diff --git a/src/pokeball.c b/src/pokeball.c index c8d9f5e4a7..1bca450a35 100644 --- a/src/pokeball.c +++ b/src/pokeball.c @@ -45,7 +45,7 @@ static void SpriteCB_TradePokeballEnd(struct Sprite *sprite); static void SpriteCB_HealthboxSlideInDelayed(struct Sprite *sprite); static void SpriteCB_HealthboxSlideIn(struct Sprite *sprite); static void SpriteCB_HitAnimHealthoxEffect(struct Sprite *sprite); -static u16 GetBattlerPokeballItemId(enum BattlerId battler); +static enum PokeBall GetBattlerPokeballItemId(enum BattlerId battler); // rom const data @@ -400,7 +400,8 @@ u8 DoPokeballSendOutAnimation(enum BattlerId battler, s16 pan, u8 kindOfThrow) static void Task_DoPokeballSendOutAnim(u8 taskId) { - u32 throwCaseId, ballId, ballSpriteId; + u32 throwCaseId, ballSpriteId; + enum PokeBall ballId; enum BattlerId battler; bool32 notSendOut = FALSE; u32 throwXoffset = (B_ENEMY_THROW_BALLS >= GEN_6 && !gTestRunnerHeadless) ? 24 : 0; @@ -491,7 +492,7 @@ static void SpriteCB_BallThrow(struct Sprite *sprite) { if (TranslateAnimHorizontalArc(sprite)) { - u16 ballId; + enum PokeBall ballId; u8 taskId = sprite->oam.affineParam; u8 opponentBattler = gTasks[taskId].tOpponentBattler; u8 noOfShakes = gTasks[taskId].tThrowId; @@ -816,7 +817,7 @@ static void Task_PlayCryWhenReleasedFromBall(u8 taskId) static void SpriteCB_ReleaseMonFromBall(struct Sprite *sprite) { enum BattlerId battler = sprite->sBattler; - u32 ballId; + enum PokeBall ballId; StartSpriteAnim(sprite, 1); ballId = GetBattlerPokeballItemId(battler); @@ -1395,7 +1396,7 @@ static void SpriteCB_HitAnimHealthoxEffect(struct Sprite *sprite) } } -void LoadBallGfx(u8 ballId) +void LoadBallGfx(enum PokeBall ballId) { u16 var; @@ -1414,16 +1415,18 @@ void LoadBallGfx(u8 ballId) var = GetSpriteTileStartByTag(gPokeBalls[ballId].pic.tag); DecompressDataWithHeaderVram(gOpenPokeballGfx, (void *)(OBJ_VRAM0 + 0x100 + var * 32)); break; + default: + break; } } -void FreeBallGfx(u8 ballId) +void FreeBallGfx(enum PokeBall ballId) { FreeSpriteTilesByTag(gPokeBalls[ballId].pic.tag); FreeSpritePaletteByTag(gPokeBalls[ballId].palette.tag); } -static u16 GetBattlerPokeballItemId(enum BattlerId battler) +static enum PokeBall GetBattlerPokeballItemId(enum BattlerId battler) { struct Pokemon *illusionMon; struct Pokemon *mon = GetBattlerMon(battler); diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 108bb569d1..f469694de3 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -149,9 +149,9 @@ static const u8 sText_EVO_DEFEAT_THREE_WITH_ITEM[] = _("{LV}{UP_ARROW} defeating static const u8 sText_EVO_NONE[] = _("{STR_VAR_1} has no evolution."); static const u8 sText_FORMS_Buttons_PE[] = _("{A_BUTTON}FORM MODE {START_BUTTON}EVOs"); -static const u8 sText_FORMS_Buttons_Decapped_PE[] = _("{START_BUTTON}Evos"); +static const u8 sText_FORMS_Buttons_Decapped_PE[] = _("{A_BUTTON}Form Mode {START_BUTTON}Evos"); static const u8 sText_FORMS_Buttons_Submenu_PE[] = _("{DPAD_NONE}FORMs {A_BUTTON}CHECK {START_BUTTON}EVOs"); -static const u8 sText_FORMS_Buttons_Submenu_Decapped_PE[] = _("{START_BUTTON}Evos"); +static const u8 sText_FORMS_Buttons_Submenu_Decapped_PE[] = _("{DPAD_NONE}Forms {A_BUTTON}Check {START_BUTTON}Evos"); static const u8 sText_FORMS_NONE[] = _("{STR_VAR_1} has no alternate forms."); static const u8 sText_PlusSymbol[] = _("+"); diff --git a/src/pokemon.c b/src/pokemon.c index f8f66967a7..36a6a97716 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -1006,7 +1006,7 @@ void CreateBoxMon(struct BoxPokemon *boxMon, enum Species species, u8 level, u32 SetBoxMonData(boxMon, MON_DATA_MET_LOCATION, &value); SetBoxMonData(boxMon, MON_DATA_MET_LEVEL, &level); SetBoxMonData(boxMon, MON_DATA_MET_GAME, &gGameVersion); - value = ITEM_POKE_BALL; + value = BALL_POKE; SetBoxMonData(boxMon, MON_DATA_POKEBALL, &value); SetBoxMonData(boxMon, MON_DATA_OT_GENDER, &gSaveBlock2Ptr->playerGender); @@ -5050,7 +5050,7 @@ s32 CalculateFriendshipBonuses(struct Pokemon *mon, s32 modifier, enum HoldEffec if (modifier == 0) return bonus; - if (GetMonData(mon, MON_DATA_POKEBALL) == ITEM_LUXURY_BALL) + if (GetMonData(mon, MON_DATA_POKEBALL) == BALL_LUXURY) bonus += ITEM_FRIENDSHIP_LUXURY_BONUS; if (GetMonData(mon, MON_DATA_MET_LOCATION) == GetCurrentRegionMapSectionId()) @@ -6524,7 +6524,12 @@ bool32 TryBoxMonFormChange(struct BoxPokemon *boxMon, enum FormChanges method) enum Species SanitizeSpeciesId(enum Species species) { - assertf(species <= NUM_SPECIES && (species == SPECIES_NONE || IsSpeciesEnabled(species)), "invalid species: %d", species) + assertf(species <= NUM_SPECIES, "invalid species: %d", species) + { + return SPECIES_NONE; + } + + assertf(species == SPECIES_NONE || IsSpeciesEnabled(species), "disabled species: %d", species) { return SPECIES_NONE; } diff --git a/src/pokenav_ribbons_summary.c b/src/pokenav_ribbons_summary.c index 4e862a6534..7bc67d1eb3 100644 --- a/src/pokenav_ribbons_summary.c +++ b/src/pokenav_ribbons_summary.c @@ -871,9 +871,9 @@ static void AddRibbonSummaryMonNameWindow(struct Pokenav_RibbonsSummaryMenu *men PrintRibbbonsSummaryMonInfo(menu); } -static const u8 sMaleIconString[] = _("{TEXT_COLORS LIGHT_RED GREEN WHITE}{BACKGROUND WHITE}♂{TEXT_COLORS DARK_GRAY LIGHT_GRAY WHITE}{BACKGROUND WHITE}"); -static const u8 sFemaleIconString[] = _("{TEXT_COLORS LIGHT_GREEN BLUE WHITE}{BACKGROUND WHITE}♀{TEXT_COLORS DARK_GRAY LIGHT_GRAY WHITE}{BACKGROUND WHITE}"); -static const u8 sGenderlessIconString[] = _("{UNK_SPACER}"); +static const u8 sText_MaleSymbol[] = _("{TEXT_COLORS LIGHT_RED GREEN WHITE}{BACKGROUND WHITE}♂{TEXT_COLORS DARK_GRAY LIGHT_GRAY WHITE}{BACKGROUND WHITE}"); +static const u8 sText_FemaleSymbol[] = _("{TEXT_COLORS LIGHT_GREEN BLUE WHITE}{BACKGROUND WHITE}♀{TEXT_COLORS DARK_GRAY LIGHT_GRAY WHITE}{BACKGROUND WHITE}"); +static const u8 sText_NoGenderSymbol[] = _("{UNK_SPACER}"); static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) { @@ -887,13 +887,13 @@ static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) switch (gender) { case MON_MALE: - genderTxt = sMaleIconString; + genderTxt = sText_MaleSymbol; break; case MON_FEMALE: - genderTxt = sFemaleIconString; + genderTxt = sText_FemaleSymbol; break; default: - genderTxt = sGenderlessIconString; + genderTxt = sText_NoGenderSymbol; break; } AddTextPrinterParameterized(windowId, GetFontIdToFit(gStringVar3, FONT_NORMAL, 0, 60), gStringVar3, 0, 1, TEXT_SKIP_DRAW, NULL); diff --git a/src/save_failed_screen.c b/src/save_failed_screen.c index c2d16b0dc6..2075ae96ef 100644 --- a/src/save_failed_screen.c +++ b/src/save_failed_screen.c @@ -424,7 +424,8 @@ void CB2_FlashNotDetectedScreen(void) .height = 16, .paletteNum = 15, .baseBlock = 1, - } + }, + DUMMY_WIN_TEMPLATE }; if (gMain.state) diff --git a/src/scrcmd.c b/src/scrcmd.c index 3d16267598..ad8479f2c2 100644 --- a/src/scrcmd.c +++ b/src/scrcmd.c @@ -88,10 +88,6 @@ extern const u8 *gStdScripts_End[]; static void CloseBrailleWindow(void); static void DynamicMultichoiceSortList(struct ListMenuItem *items, u32 count); -// This is defined in here so the optimizer can't see its value when compiling -// script.c. -void *const gNullScriptPtr = NULL; - static const u8 sScriptConditionTable[6][3] = { // < = > diff --git a/src/script.c b/src/script.c index 3f40103954..ff1e43375a 100644 --- a/src/script.c +++ b/src/script.c @@ -40,7 +40,6 @@ EWRAM_DATA u8 gMsgBoxIsCancelable = FALSE; extern ScrCmdFunc gScriptCmdTable[]; extern ScrCmdFunc gScriptCmdTableEnd[]; -extern void *const gNullScriptPtr; void InitScriptStack(struct ScriptStack *stk) { @@ -90,9 +89,6 @@ void StopScript(struct ScriptContext *ctx) bool8 RunScriptCommand(struct ScriptContext *ctx) { - if (ctx->mode == SCRIPT_MODE_STOPPED) - return FALSE; - switch (ctx->mode) { case SCRIPT_MODE_STOPPED: @@ -114,18 +110,12 @@ bool8 RunScriptCommand(struct ScriptContext *ctx) u8 cmdCode; ScrCmdFunc *func; - if (!ctx->scriptPtr) + if (ctx->scriptPtr == NULL) { ctx->mode = SCRIPT_MODE_STOPPED; return FALSE; } - if (ctx->scriptPtr == gNullScriptPtr) - { - while (1) - asm("svc 2"); // HALT - } - cmdCode = *(ctx->scriptPtr); ctx->scriptPtr++; func = &ctx->cmdTable[cmdCode]; @@ -192,16 +182,26 @@ const u8 *ScriptPop(struct ScriptContext *ctx) void ScriptJump(struct ScriptContext *ctx, const u8 *ptr) { + assertf(ptr != NULL, "goto to NULL"); ctx->scriptPtr = ptr; } void ScriptCall(struct ScriptContext *ctx, const u8 *ptr) { - assertf(!ScriptPush(ctx, ctx->scriptPtr), - "Failed to push %p to %p", ptr, ctx) + assertf(ptr != NULL, "call to NULL") + { + // HINT: Returning without having pushed the current location is + // equivalent to branching to a script that just contains + // 'return'. + return; + } + + bool32 failed = ScriptPush(ctx, ctx->scriptPtr); + assertf(!failed, "could not push %p to %p", ptr, ctx) { return; } + ctx->scriptPtr = ptr; } diff --git a/src/sprite.c b/src/sprite.c index 80051f576f..c4e1851589 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -15,8 +15,8 @@ #define SET_SPRITE_TILE_RANGE(index, start, count) \ { \ - sSpriteTileRanges[index * 2] = start; \ - (sSpriteTileRanges + 1)[index * 2] = count; \ + sSpriteTileRanges[index][0] = start; \ + sSpriteTileRanges[index][1] = count; \ } #define ALLOC_SPRITE_TILE(n) \ @@ -250,7 +250,7 @@ const struct OamDimensions gOamDimensions[3][4] = // iwram bss static u16 sSpriteTileRangeTags[MAX_SPRITES]; -static u16 sSpriteTileRanges[MAX_SPRITES * 2]; +static u16 sSpriteTileRanges[MAX_SPRITES][2]; static struct AffineAnimState sAffineAnimStates[OAM_MATRIX_COUNT]; static u16 sSpritePaletteTags[16]; @@ -1563,14 +1563,10 @@ void FreeSpriteTilesByTag(u16 tag) gSpriteAllocs--; #endif u16 i; - u16 *rangeStarts; - u16 *rangeCounts; u16 start; u16 count; - rangeStarts = sSpriteTileRanges; - start = rangeStarts[index * 2]; - rangeCounts = sSpriteTileRanges + 1; - count = rangeCounts[index * 2]; + start = sSpriteTileRanges[index][0]; + count = sSpriteTileRanges[index][1]; for (i = start; i < start + count; i++) FREE_SPRITE_TILE(i); @@ -1595,7 +1591,7 @@ u16 GetSpriteTileStartByTag(u16 tag) u8 index = IndexOfSpriteTileTag(tag); if (index == 0xFF) return 0xFFFF; - return sSpriteTileRanges[index * 2]; + return sSpriteTileRanges[index][0]; } u8 IndexOfSpriteTileTag(u16 tag) @@ -1615,7 +1611,7 @@ u16 GetSpriteTileTagByTileStart(u16 start) for (i = 0; i < MAX_SPRITES; i++) { - if (sSpriteTileRangeTags[i] != TAG_NONE && sSpriteTileRanges[i * 2] == start) + if (sSpriteTileRangeTags[i] != TAG_NONE && sSpriteTileRanges[i][0] == start) return sSpriteTileRangeTags[i]; } diff --git a/src/strings.c b/src/strings.c index 3c94e0917e..863fb14280 100644 --- a/src/strings.c +++ b/src/strings.c @@ -45,12 +45,12 @@ const u8 gText_Boy[] = _("BOY"); const u8 gText_Girl[] = _("GIRL"); const u8 gText_ThisIsAPokemon[] = _("This is what we call a “POKéMON.”{PAUSE 96}\p"); const u8 gText_5MarksPokemon[] = _("????? POKéMON"); -const u8 gText_UnkHeight[] = _("{CLEAR_TO 0x0C}??'??”"); +const u8 gText_UnkHeight[] = _("{CLEAR_TO 12}??'??”"); const u8 gText_UnkHeightMetric[] = _("???.? m"); const u8 gText_UnkWeight[] = _("????.? lbs."); const u8 gText_UnkWeightMetric[] = _("???.? kg."); const u8 gText_EmptyPkmnCategory[] = _(" POKéMON"); // Unused -const u8 gText_EmptyHeight[] = _("{CLEAR_TO 0x0C} ' ”"); // Unused +const u8 gText_EmptyHeight[] = _("{CLEAR_TO 12} ' ”"); // Unused const u8 gText_EmptyWeight[] = _(" . lbs."); // Unused const u8 gText_EmptyPokedexInfo1[] = _(""); // Unused const u8 gText_CryOf[] = _("CRY OF"); @@ -143,7 +143,7 @@ const u8 gText_ThreeDashes[] = _("---"); const u8 gText_MaleSymbol[] = _("♂"); const u8 gText_FemaleSymbol[] = _("♀"); const u8 gText_LevelSymbol[] = _("{LV}"); -const u8 gText_NumberClear01[] = _("{NO}{CLEAR 0x01}"); +const u8 gText_NumberClear01[] = _("{NO}{CLEAR 1}"); const u8 gText_RightArrow[] = _("{RIGHT_ARROW}"); // Unused const u8 gText_IDNumber2[] = _("{ID}{NO}"); const u8 gText_Space[] = _(" "); @@ -210,8 +210,8 @@ const u8 *const gPocketNamesStringsTable[] = [POCKET_KEY_ITEMS] = COMPOUND_STRING("KEY ITEMS") }; -const u8 gText_NumberItem_TMBerry[] = _("{NO}{STR_VAR_1}{CLEAR 0x03}{STR_VAR_2}"); -const u8 gText_NumberItem_HM[] = _("{CLEAR_TO 0x11}{STR_VAR_1}{CLEAR 0x05}{STR_VAR_2}"); +const u8 gText_NumberItem_TMBerry[] = _("{NO}{STR_VAR_1}{CLEAR 3}{STR_VAR_2}"); +const u8 gText_NumberItem_HM[] = _("{CLEAR_TO 17}{STR_VAR_1}{CLEAR 5}{STR_VAR_2}"); const u8 gText_ShopBuy[] = _("BUY"); const u8 gText_ShopSell[] = _("SELL"); @@ -820,7 +820,7 @@ const u8 gText_BerriesPicked[] = _("BERRIES picked:"); const u8 gText_BestScore[] = _("Best score:"); const u8 gText_BerriesInRowFivePlayers[] = _("BERRIES picked in a row with\nfive players:"); const u8 gText_BerryPickingResults[] = _("Announcing BERRY-PICKING results!"); -const u8 gText_10P30P50P50P[] = _("{CLEAR_TO 0x03}10P{CLEAR_TO 0x2B}30P{CLEAR_TO 0x53}50P{CLEAR_TO 0x77}{EMOJI_MINUS}50P"); +const u8 gText_10P30P50P50P[] = _("{CLEAR_TO 3}10P{CLEAR_TO 43}30P{CLEAR_TO 83}50P{CLEAR_TO 119}{EMOJI_MINUS}50P"); const u8 gText_AnnouncingRankings[] = _("Announcing rankings!"); const u8 gText_AnnouncingPrizes[] = _("Announcing prizes!"); const u8 gText_1Colon[] = _("1:"); @@ -895,7 +895,7 @@ const u8 gText_Total[] = _("Total"); const u8 gText_ClearStreak[] = _("Clear streak: {STR_VAR_1}"); const u8 gText_Championships[] = _("Championships: {STR_VAR_1}"); const u8 gText_RoomsCleared[] = _("Rooms cleared: {STR_VAR_1}"); -const u8 gText_TimesCleared[] = _("Times cleared:{CLEAR 0x05}{STR_VAR_1}"); +const u8 gText_TimesCleared[] = _("Times cleared:{CLEAR 5}{STR_VAR_1}"); const u8 gText_KOsInARow[] = _("KOs in a row: {STR_VAR_1}"); const u8 gText_TimesVar1[] = _("Times: {STR_VAR_1}"); const u8 gText_FloorsCleared[] = _("Floors cleared: {STR_VAR_1}"); @@ -965,7 +965,7 @@ const u8 gJPText_Player[] = _("プレイヤー"); // Unused const u8 gJPText_Sama[] = _("さま"); // Unused const u8 gText_DexHoenn[] = _("HOENN"); const u8 gText_DexNational[] = _("NATIONAL"); -const u8 gText_PokedexDiploma[] = _("PLAYER: {CLEAR 0x10}{COLOR RED}{SHADOW LIGHT_RED}{PLAYER}{COLOR DARK_GRAY}{SHADOW LIGHT_GRAY}\n\nThis document certifies\nthat you have successfully\ncompleted your\n{STR_VAR_1} POKéDEX.\n\n{CLEAR_TO 0x42}{COLOR RED}{SHADOW LIGHT_RED}GAME FREAK"); +const u8 gText_PokedexDiploma[] = _("PLAYER: {CLEAR 16}{COLOR RED}{SHADOW LIGHT_RED}{PLAYER}{COLOR DARK_GRAY}{SHADOW LIGHT_GRAY}\n\nThis document certifies\nthat you have successfully\ncompleted your\n{STR_VAR_1} POKéDEX.\n\n{CLEAR_TO 66}{COLOR RED}{SHADOW LIGHT_RED}GAME FREAK"); const u8 gJPText_GameFreak[] = _("{COLOR RED}{SHADOW LIGHT_RED}ゲ-ムフリ-ク"); // Unused const u8 gText_DiplomaEmpty[] = _("{COLOR RED}{SHADOW LIGHT_RED}"); // Unused const u8 gText_Hoenn[] = _("HOENN"); @@ -1098,7 +1098,7 @@ ALIGNED(4) const u8 gText_PickOKExit[] = _("{DPAD_UPDOWN}PICK {A_BUTTON}OK {B_BU ALIGNED(4) const u8 gText_PickOKCancel[] = _("{DPAD_UPDOWN}PICK {A_BUTTON}OK {B_BUTTON}CANCEL"); const u8 gText_PlayersBattleResults[] = _("{PLAYER}'s BATTLE RESULTS"); const u8 gText_TotalRecordWLD[] = _("TOTAL RECORD W:{STR_VAR_1} L:{STR_VAR_2} D:{STR_VAR_3}"); -const u8 gText_WinLoseDraw[] = _("{CLEAR_TO 0x53}WIN{CLEAR_TO 0x80}LOSE{CLEAR_TO 0xB0}DRAW"); +const u8 gText_WinLoseDraw[] = _("{CLEAR_TO 83}WIN{CLEAR_TO 128}LOSE{CLEAR_TO 176}DRAW"); const u8 gText_CommunicationStandby5[] = _("Communication standby…"); const u8 gDaycareText_GetAlongVeryWell[] = _("The two seem to get along\nvery well."); const u8 gDaycareText_GetAlong[] = _("The two seem to get along."); diff --git a/src/text.c b/src/text.c index 2fd9c9f84d..132490f415 100644 --- a/src/text.c +++ b/src/text.c @@ -385,7 +385,7 @@ u16 AddTextPrinterParameterized(u8 windowId, u8 fontId, const u8 *str, u8 x, u8 return AddTextPrinter(&printerTemplate, speed, callback); } -u16 AddSpriteTextPrinterParametrerized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) +u16 AddSpriteTextPrinterParameterized(u8 spriteId, u8 fontId, const u8 *str, u8 x, u8 y, u8 speed, void (*callback)(struct TextPrinterTemplate *, u16)) { struct TextPrinterTemplate printerTemplate; diff --git a/src/window.c b/src/window.c index 51b473e89c..885e802ec0 100644 --- a/src/window.c +++ b/src/window.c @@ -20,7 +20,42 @@ static void DummyWindowBgTilemap(void) } -bool32 InitWindows(const struct WindowTemplate *templates) +bool32 InitWindowsChecked(const struct WindowTemplate *templates, s32 staticSize) +{ + bool32 terminated; + + if (staticSize >= 0) + { + terminated = templates[(staticSize / sizeof(*templates)) - 1].bg == 0xFF; + } + else + { + terminated = FALSE; + for (u32 i = 0; i < WINDOWS_MAX; i++) + { + if (templates[i].bg == 0xFF) + { + terminated = TRUE; + break; + } + else if (0x04 <= templates[i].bg && templates[i].bg < 0xFF) + { + break; + } + } + } + + assertf(terminated, "%p is missing DUMMY_WIN_TEMPLATE terminator", templates) + { + return FALSE; + } + + bool32 initialized = InitWindowsUnchecked(templates); + assertf(initialized, "Could not initialize windows"); + return initialized; +} + +bool32 InitWindowsUnchecked(const struct WindowTemplate *templates) { int i; void *bgTilemapBuffer; @@ -49,7 +84,7 @@ bool32 InitWindows(const struct WindowTemplate *templates) { if (gWindowTileAutoAllocEnabled == TRUE) { - allocatedBaseBlock = BgTileAllocOp(bgLayer, 0, templates[i].width * templates[i].height, 0); + allocatedBaseBlock = BgTileAllocOpUnchecked(bgLayer, 0, templates[i].width * templates[i].height, 0); if (allocatedBaseBlock == -1) return FALSE; } @@ -60,7 +95,7 @@ bool32 InitWindows(const struct WindowTemplate *templates) if (attrib != 0xFFFF) { - allocatedTilemapBuffer = AllocZeroed(attrib); + allocatedTilemapBuffer = AllocZeroedUnchecked(attrib); if (allocatedTilemapBuffer == NULL) { @@ -76,7 +111,7 @@ bool32 InitWindows(const struct WindowTemplate *templates) } } - allocatedTilemapBuffer = AllocZeroed((u16)(32 * (templates[i].width * templates[i].height))); + allocatedTilemapBuffer = AllocZeroedUnchecked((u16)(32 * (templates[i].width * templates[i].height))); if (allocatedTilemapBuffer == NULL) { @@ -125,7 +160,7 @@ u32 AddWindow(const struct WindowTemplate *template) if (gWindowTileAutoAllocEnabled == TRUE) { - allocatedBaseBlock = BgTileAllocOp(bgLayer, 0, template->width * template->height, 0); + allocatedBaseBlock = BgTileAllocOpUnchecked(bgLayer, 0, template->width * template->height, 0); if (allocatedBaseBlock == -1) return WINDOW_NONE; diff --git a/test/battle/ability/delta_stream.c b/test/battle/ability/delta_stream.c index 0ea7429ff4..816317459a 100644 --- a/test/battle/ability/delta_stream.c +++ b/test/battle/ability/delta_stream.c @@ -8,18 +8,18 @@ DOUBLE_BATTLE_TEST("Delta Stream doesn't activate if there's already strong winds") { GIVEN { + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { - TURN { SWITCH(playerLeft, 2); } + TURN { + MOVE(opponentLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + } } SCENE { ABILITY_POPUP(opponentLeft, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); - SWITCH_OUT_MESSAGE("Wobbuffet"); - SEND_IN_MESSAGE("Rayquaza"); NONE_OF { ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); @@ -30,18 +30,21 @@ DOUBLE_BATTLE_TEST("Delta Stream doesn't activate if there's already strong wind DOUBLE_BATTLE_TEST("Strong winds continue as long as there's a Pokémon with Delta Stream on the field") { GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); HP(1); } - PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } - OPPONENT(SPECIES_WOBBUFFET); + PLAYER(SPECIES_RAYQUAZA) { HP(1); Speed(5); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + PLAYER(SPECIES_WOBBUFFET) { Speed(4); } + PLAYER(SPECIES_WOBBUFFET) { Speed(3); } + OPPONENT(SPECIES_RAYQUAZA) { Speed(2); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_SCRATCH); } + OPPONENT(SPECIES_WOBBUFFET) { Speed(1); } } WHEN { + TURN { + MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + MOVE(opponentLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); + } TURN { MOVE(opponentLeft, MOVE_SCRATCH, target: playerLeft); SEND_OUT(playerLeft, 2); } } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, opponentLeft); - HP_BAR(playerLeft, hp: 0); - MESSAGE("Rayquaza fainted!"); - SEND_IN_MESSAGE("Wobbuffet"); + HP_BAR(playerLeft); NOT MESSAGE("The mysterious strong winds have dissipated!"); } THEN { EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); diff --git a/test/battle/ability/desolate_land.c b/test/battle/ability/desolate_land.c index e45197aea4..6a35847b1a 100644 --- a/test/battle/ability/desolate_land.c +++ b/test/battle/ability/desolate_land.c @@ -128,7 +128,8 @@ SINGLE_BATTLE_TEST("Desolate Land blocks weather-setting moves") SINGLE_BATTLE_TEST("Desolate Land prevents other weather abilities") { - enum Ability ability; u16 species; + enum Ability ability; + enum Species species; PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } @@ -151,10 +152,9 @@ SINGLE_BATTLE_TEST("Desolate Land can be replaced by Delta Stream") { GIVEN { PLAYER(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } } WHEN { - TURN { SWITCH(opponent, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } } SCENE { ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); diff --git a/test/battle/ability/flash_fire.c b/test/battle/ability/flash_fire.c index 4cdcec9973..3b7d7bbb0b 100644 --- a/test/battle/ability/flash_fire.c +++ b/test/battle/ability/flash_fire.c @@ -16,9 +16,11 @@ SINGLE_BATTLE_TEST("Flash Fire boosts fire type moves by 50% but no subsequent i ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &damage[0]); ABILITY_POPUP(player, ABILITY_FLASH_FIRE); + MESSAGE("The power of Heatran's Fire-type moves rose!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &damage[1]); ABILITY_POPUP(player, ABILITY_FLASH_FIRE); + MESSAGE("Heatran made it ineffective!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_EMBER, player); HP_BAR(opponent, captureDamage: &damage[2]); } THEN { diff --git a/test/battle/ability/insomnia.c b/test/battle/ability/insomnia.c index c95b294907..f012c90ec1 100644 --- a/test/battle/ability/insomnia.c +++ b/test/battle/ability/insomnia.c @@ -12,6 +12,7 @@ SINGLE_BATTLE_TEST("Insomnia prevents sleep") TURN { MOVE(opponent, MOVE_SPORE); } } SCENE { ABILITY_POPUP(player, ABILITY_INSOMNIA); + MESSAGE("Drowzee made it ineffective!"); NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, player); diff --git a/test/battle/ability/primordial_sea.c b/test/battle/ability/primordial_sea.c index b6000718cc..9cd37096dc 100644 --- a/test/battle/ability/primordial_sea.c +++ b/test/battle/ability/primordial_sea.c @@ -94,7 +94,8 @@ SINGLE_BATTLE_TEST("Primordial Sea blocks weather-setting moves") SINGLE_BATTLE_TEST("Primordial Sea prevents other weather abilities") { - enum Ability ability; u16 species; + enum Ability ability; + enum Species species; PARAMETRIZE { ability = ABILITY_DROUGHT; species = SPECIES_NINETALES; } PARAMETRIZE { ability = ABILITY_DRIZZLE; species = SPECIES_POLITOED; } PARAMETRIZE { ability = ABILITY_SAND_STREAM; species = SPECIES_HIPPOWDON; } @@ -117,10 +118,9 @@ SINGLE_BATTLE_TEST("Primordial Sea can be replaced by Delta Stream") { GIVEN { PLAYER(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } } WHEN { - TURN { SWITCH(opponent, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } } SCENE { ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); MESSAGE("Mysterious strong winds are protecting Flying-type Pokémon!"); diff --git a/test/battle/ability/shadow_tag.c b/test/battle/ability/shadow_tag.c index f00696d8b7..93b930ecb3 100644 --- a/test/battle/ability/shadow_tag.c +++ b/test/battle/ability/shadow_tag.c @@ -2,3 +2,18 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Shadow Tag (Ability) test titles") + +WILD_BATTLE_TEST("Shadow Tag prevents wild Pokemon from fleeing with Teleport") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_TELEPORT) == EFFECT_TELEPORT); + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_SHADOW_TAG); } + OPPONENT(SPECIES_ABRA); + } WHEN { + TURN { MOVE(opponent, MOVE_TELEPORT); } + } SCENE { + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEPORT, opponent); + ABILITY_POPUP(player, ABILITY_SHADOW_TAG); + MESSAGE("Wobbuffet made it ineffective!"); + } +} diff --git a/test/battle/ability/vital_spirit.c b/test/battle/ability/vital_spirit.c index 2539df2334..85fcbff613 100644 --- a/test/battle/ability/vital_spirit.c +++ b/test/battle/ability/vital_spirit.c @@ -2,3 +2,23 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Vital Spirit (Ability) test titles") + +SINGLE_BATTLE_TEST("Vital Spirit prevents sleep") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS); + ASSUME(GetMoveNonVolatileStatus(MOVE_SPORE) == MOVE_EFFECT_SLEEP); + PLAYER(SPECIES_MANKEY) { Ability(ABILITY_VITAL_SPIRIT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SPORE); } + } SCENE { + ABILITY_POPUP(player, ABILITY_VITAL_SPIRIT); + MESSAGE("Mankey made it ineffective!"); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, player); + STATUS_ICON(player, sleep: TRUE); + } + } +} diff --git a/test/battle/ai/ai.c b/test/battle/ai/ai.c index c9437b99b9..8b783b2985 100644 --- a/test/battle/ai/ai.c +++ b/test/battle/ai/ai.c @@ -1355,3 +1355,93 @@ AI_DOUBLE_BATTLE_TEST("Bolt Beak damage will be correctly seen by AI (doubles)") } } } + +AI_MULTI_BATTLE_TEST("AI does not target itself with selected moves in doubles (TARGET_SELECTED)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SCORE_TIE_DOUBLES_TARGET); + + GIVEN { + ASSUME(GetMoveTarget(MOVE_FLAMETHROWER) == TARGET_SELECTED); + AI_FLAGS(0); + TIE_BREAK_TARGET(TARGET_TIE_CHOSEN, i % 3); + PLAYER(SPECIES_TURTONATOR) { Speed(4); } + PARTNER(SPECIES_TURTONATOR) { Speed(2); Moves(MOVE_FLAMETHROWER); } + OPPONENT_A(SPECIES_TURTONATOR) { Speed(3); Moves(MOVE_FLAMETHROWER); } + OPPONENT_B(SPECIES_TURTONATOR) { Speed(1); Moves(MOVE_FLAMETHROWER); } + } WHEN { + TURN { + EXPECT_MOVE(opponentLeft, MOVE_FLAMETHROWER); + EXPECT_MOVE(playerRight, MOVE_FLAMETHROWER); + EXPECT_MOVE(opponentRight, MOVE_FLAMETHROWER); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAMETHROWER, opponentLeft); + NOT HP_BAR(opponentLeft); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAMETHROWER, playerRight); + NOT HP_BAR(playerRight); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_FLAMETHROWER, opponentRight); + NOT HP_BAR(opponentRight); + } +} + +AI_MULTI_BATTLE_TEST("AI does not target itself with selected moves in doubles (TARGET_FOES_AND_ALLY)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SCORE_TIE_DOUBLES_TARGET); + + GIVEN { + ASSUME(GetMoveTarget(MOVE_LAVA_PLUME) == TARGET_FOES_AND_ALLY); + AI_FLAGS(0); + TIE_BREAK_TARGET(TARGET_TIE_CHOSEN, i % 3); + PLAYER(SPECIES_TURTONATOR) { Speed(4); } + PARTNER(SPECIES_TURTONATOR) { Speed(2); Moves(MOVE_LAVA_PLUME); } + OPPONENT_A(SPECIES_TURTONATOR) { Speed(3); Moves(MOVE_LAVA_PLUME); } + OPPONENT_B(SPECIES_TURTONATOR) { Speed(1); Moves(MOVE_LAVA_PLUME); } + } WHEN { + TURN { + EXPECT_MOVE(opponentLeft, MOVE_LAVA_PLUME); + EXPECT_MOVE(playerRight, MOVE_LAVA_PLUME); + EXPECT_MOVE(opponentRight, MOVE_LAVA_PLUME); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_LAVA_PLUME, opponentLeft); + NOT HP_BAR(opponentLeft); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_LAVA_PLUME, playerRight); + NOT HP_BAR(playerRight); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_LAVA_PLUME, opponentRight); + NOT HP_BAR(opponentRight); + } +} + +AI_MULTI_BATTLE_TEST("AI does not target itself with selected moves in doubles (TARGET_BOTH)") +{ + PASSES_RANDOMLY(100, 100, RNG_AI_SCORE_TIE_DOUBLES_TARGET); + + GIVEN { + ASSUME(GetMoveTarget(MOVE_HEAT_WAVE) == TARGET_BOTH); + AI_FLAGS(0); + TIE_BREAK_TARGET(TARGET_TIE_CHOSEN, i % 3); + PLAYER(SPECIES_TURTONATOR) { Speed(4); } + PARTNER(SPECIES_TURTONATOR) { Speed(2); Moves(MOVE_HEAT_WAVE); } + OPPONENT_A(SPECIES_TURTONATOR) { Speed(3); Moves(MOVE_HEAT_WAVE); } + OPPONENT_B(SPECIES_TURTONATOR) { Speed(1); Moves(MOVE_HEAT_WAVE); } + } WHEN { + TURN { + EXPECT_MOVE(opponentLeft, MOVE_HEAT_WAVE); + EXPECT_MOVE(playerRight, MOVE_HEAT_WAVE); + EXPECT_MOVE(opponentRight, MOVE_HEAT_WAVE); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAT_WAVE, opponentLeft); + NOT HP_BAR(opponentLeft); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAT_WAVE, playerRight); + NOT HP_BAR(playerRight); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEAT_WAVE, opponentRight); + NOT HP_BAR(opponentRight); + } +} diff --git a/test/battle/move_effect/acupressure.c b/test/battle/move_effect/acupressure.c index 6eaade94ae..b0d7b61e19 100644 --- a/test/battle/move_effect/acupressure.c +++ b/test/battle/move_effect/acupressure.c @@ -1,13 +1,6 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Acupressure increases one of its stats by 2 stages at random"); -TO_DO_BATTLE_TEST("Acupressure doesn't try to increase a stat that has been maximized"); -TO_DO_BATTLE_TEST("Acupressure fails on the user if all of its stats are maximized"); -TO_DO_BATTLE_TEST("Acupressure fails on the ally if all of its stats are maximized"); -TO_DO_BATTLE_TEST("Acupressure works on the user if it's behind a Substitute (Gen5+)"); -TO_DO_BATTLE_TEST("Acupressure fails on its ally if it's behind a Substitute"); - DOUBLE_BATTLE_TEST("Acupressure fails on the user if it targeted its ally but switched positions via Ally Switch") { GIVEN { @@ -50,8 +43,112 @@ DOUBLE_BATTLE_TEST("Acupressure works on the ally if it targeted itself but swit } } -TO_DO_BATTLE_TEST("Acupressure works on the user if its side is protected by Crafty Shield"); -TO_DO_BATTLE_TEST("Acupressure fails on the ally if its side is protected by Crafty Shield"); +DOUBLE_BATTLE_TEST("Acupressure will not try to raise partners stat if it already increased its own") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentLeft); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } + } +} + +DOUBLE_BATTLE_TEST("Acupressure works on the user if its side is protected by Crafty Shield") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_CRAFTY_SHIELD) == EFFECT_PROTECT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); + MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentRight); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + } +} + +DOUBLE_BATTLE_TEST("Acupressure works on the ally if its side is protected by Crafty Shield") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_PROTECT) == EFFECT_PROTECT); + ASSUME(GetMoveEffect(MOVE_CRAFTY_SHIELD) == EFFECT_PROTECT); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_CRAFTY_SHIELD); + MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CRAFTY_SHIELD, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } +} + +DOUBLE_BATTLE_TEST("Acupressure works on the user if it's behind a Substitute (Gen5+)") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(opponentRight, MOVE_SUBSTITUTE); } + TURN { MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponentRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight); + } +} + +DOUBLE_BATTLE_TEST("Acupressure fails on its ally if it's behind a Substitute") +{ + GIVEN { + ASSUME(GetMoveEffect(MOVE_SUBSTITUTE) == EFFECT_SUBSTITUTE); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { + MOVE(opponentLeft, MOVE_SUBSTITUTE); + MOVE(opponentRight, MOVE_ACUPRESSURE, target: opponentLeft); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponentLeft); + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ACUPRESSURE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); + } + } +} + + +TO_DO_BATTLE_TEST("Acupressure fails on the user if all of its stats are maximized"); +TO_DO_BATTLE_TEST("Acupressure fails on the ally if all of its stats are maximized"); +TO_DO_BATTLE_TEST("Acupressure doesn't try to increase a stat that has been maximized"); +TO_DO_BATTLE_TEST("Acupressure increases one of its stats by 2 stages at random"); // Triple Battles required to test //TO_DO_BATTLE_TEST("Acupressure works on the ally if the user targeted itself but switched positions via Triple Battle shift before execution"); diff --git a/test/battle/move_effect/beat_up.c b/test/battle/move_effect/beat_up.c index 8f8c716fe5..1f8f15b7a2 100644 --- a/test/battle/move_effect/beat_up.c +++ b/test/battle/move_effect/beat_up.c @@ -200,7 +200,7 @@ SINGLE_BATTLE_TEST("Beat Up lists each party member's name") } } -SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage) +SINGLE_BATTLE_TEST("Beat Up's damage is typeless (up to Gen4)", s16 damage) { u16 defender = SPECIES_WOBBUFFET; u16 type1, type2; @@ -225,7 +225,7 @@ SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage) PARAMETRIZE { defender = SPECIES_SYLVEON; } // Fairy GIVEN { - WITH_CONFIG(B_BEAT_UP, GEN_3); + WITH_CONFIG(B_BEAT_UP, GEN_4); type1 = GetSpeciesType(defender, 0); type2 = GetSpeciesType(defender, 1); ASSUME(type2 == type1 || type2 == TYPE_MYSTERY); // Ensure monotype targets @@ -235,12 +235,8 @@ SINGLE_BATTLE_TEST("Beat Up's damage is typeless", s16 damage) TURN { MOVE(player, MOVE_BEAT_UP); } } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_BEAT_UP, player); + EFFECTIVENESS_SE(opponent, SE_EFFECTIVE); HP_BAR(opponent, captureDamage: &results[i].damage); - NONE_OF { - MESSAGE("It's super effective!"); - MESSAGE("It's not very effective..."); - MESSAGE("It doesn't affect"); - } } THEN { EXPECT_GT(results[i].damage, 0); } diff --git a/test/battle/move_effect/roost.c b/test/battle/move_effect/roost.c index f42ebad3ca..a1e674ac50 100644 --- a/test/battle/move_effect/roost.c +++ b/test/battle/move_effect/roost.c @@ -255,12 +255,14 @@ DOUBLE_BATTLE_TEST("Roost suppresses the user's not-yet-aquired Flying-type this SINGLE_BATTLE_TEST("Roost prevents a Flying-type user from being protected by Delta Stream") { GIVEN { - ASSUME(GetSpeciesType(SPECIES_RAYQUAZA, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { HP(1); Ability(ABILITY_DELTA_STREAM); } + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING); + PLAYER(SPECIES_RAYQUAZA) { HP(1); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_ROOST); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(player, MOVE_ROOST); MOVE(opponent, MOVE_ICE_BEAM); } } SCENE { + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); MESSAGE("Rayquaza used Roost!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player); MESSAGE("Rayquaza's HP was restored."); diff --git a/test/battle/move_effect/weather_ball.c b/test/battle/move_effect/weather_ball.c index 912a4515e8..70cd269f4f 100644 --- a/test/battle/move_effect/weather_ball.c +++ b/test/battle/move_effect/weather_ball.c @@ -97,6 +97,45 @@ SINGLE_BATTLE_TEST("Weather Ball doubles its power and turns to an Ice-type move } } +DOUBLE_BATTLE_TEST("Weather Ball doesn't double its power and stays a Normal-type move in strong winds", s16 damage) +{ + bool32 strongWinds; + enum Species species; + PARAMETRIZE { strongWinds = FALSE; species = SPECIES_WOBBUFFET; } + PARAMETRIZE { strongWinds = TRUE; species = SPECIES_WOBBUFFET; } + PARAMETRIZE { strongWinds = TRUE; species = SPECIES_GASTLY; } + + GIVEN { + ASSUME(GetMoveType(MOVE_WEATHER_BALL) == TYPE_NORMAL); + ASSUME(GetSpeciesType(SPECIES_GASTLY, 0) == TYPE_GHOST); + if (strongWinds) + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + else + PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_AIR_LOCK); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(species); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (strongWinds) + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { MOVE(playerRight, MOVE_WEATHER_BALL, target: opponentLeft); } + } SCENE { + if (strongWinds) + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + if (species == SPECIES_GASTLY) { + NONE_OF { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WEATHER_BALL, playerRight); + HP_BAR(opponentLeft); + } + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_WEATHER_BALL, playerRight); + HP_BAR(opponentLeft, captureDamage: &results[i].damage); + } + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + SINGLE_BATTLE_TEST("Weather Ball doesn't double its power in Sunlight or Rain if Cloud Nine/Air Lock is on the field", s16 damage) { enum Move setupMove; diff --git a/test/battle/stat_change_leaks.c b/test/battle/stat_change_leaks.c new file mode 100644 index 0000000000..51ff94ba08 --- /dev/null +++ b/test/battle/stat_change_leaks.c @@ -0,0 +1,55 @@ +#include "global.h" +#include "test/battle.h" + +AI_SINGLE_BATTLE_TEST("Type-absorbing ability checks don't queue stat increases") +{ + enum Ability ability; + enum Move absorbedMove; + enum Species species; + enum Stat boostedStat; + + PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_STORM_DRAIN; absorbedMove = MOVE_WATER_GUN; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; absorbedMove = MOVE_THUNDERBOLT; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_MARILL; ability = ABILITY_SAP_SIPPER; absorbedMove = MOVE_VINE_WHIP; boostedStat = STAT_ATK; } + + GIVEN { + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME_STAT_CHANGE(MOVE_GROWL, attack: -1); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(species) { Ability(ability); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(absorbedMove, MOVE_GROWL); Speed(2); } + } WHEN { + TURN { EXPECT_MOVE(opponent, MOVE_GROWL); } + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1); + if (boostedStat != STAT_ATK) + EXPECT_EQ(player->statStages[boostedStat], DEFAULT_STAT_STAGE); + } +} + +AI_SINGLE_BATTLE_TEST("Type-absorbing abilities only increase a stat once after AI checks") +{ + enum Ability ability; + enum Move absorbedMove; + enum Species species; + enum Stat boostedStat; + + PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_STORM_DRAIN; absorbedMove = MOVE_WATER_GUN; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_RAICHU; ability = ABILITY_LIGHTNING_ROD; absorbedMove = MOVE_THUNDERBOLT; boostedStat = STAT_SPATK; } + PARAMETRIZE { species = SPECIES_MARILL; ability = ABILITY_SAP_SIPPER; absorbedMove = MOVE_VINE_WHIP; boostedStat = STAT_ATK; } + + GIVEN { + ASSUME(GetMoveType(MOVE_WATER_GUN) == TYPE_WATER); + ASSUME(GetMoveType(MOVE_THUNDERBOLT) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT); + PLAYER(species) { Ability(ability); Speed(1); } + OPPONENT(SPECIES_WOBBUFFET) { Moves(absorbedMove); Speed(2); } + } WHEN { + TURN { EXPECT_MOVE(opponent, absorbedMove); } + } THEN { + EXPECT_EQ(player->statStages[boostedStat], DEFAULT_STAT_STAGE + 1); + } +} diff --git a/test/battle/trainer_slides.c b/test/battle/trainer_slides.c index 12e374ad40..fd78339a4c 100644 --- a/test/battle/trainer_slides.c +++ b/test/battle/trainer_slides.c @@ -1483,9 +1483,10 @@ AI_MULTI_BATTLE_TEST("Trainer Slide: Multi: Attacker Z Move") OPPONENT_B(SPECIES_WOBBUFFET) { Speed(1); Item(ITEM_NORMALIUM_Z); } } WHEN { TURN { - EXPECT_MOVE(opponentLeft, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); - MOVE(playerRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE, target: opponentLeft); - EXPECT_MOVE(opponentRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); } + EXPECT_MOVE(opponentLeft, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); + MOVE(playerRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE, target: opponentLeft); + EXPECT_MOVE(opponentRight, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); + } } SCENE { MESSAGE("Trainer A: This message plays before the attacker activates the Z-Move gimmick.{PAUSE_UNTIL_PRESS}"); MESSAGE("The opposing Wobbuffet surrounded itself with its Z-Power!"); diff --git a/test/battle/weather/strong_winds.c b/test/battle/weather/strong_winds.c index 3098ebd43a..d583bfc915 100644 --- a/test/battle/weather/strong_winds.c +++ b/test/battle/weather/strong_winds.c @@ -1,97 +1,77 @@ #include "global.h" #include "test/battle.h" -DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers") // Electric, Ice, Rock +ASSUMPTIONS +{ + ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); + ASSUME(GetMoveType(MOVE_ICE_BEAM) == TYPE_ICE); + ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); + ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_FLYING || GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); +} + +DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers") { enum Move move; - bool32 targetPlayer; - - PARAMETRIZE { move = MOVE_THUNDER_SHOCK; targetPlayer = TRUE; } - PARAMETRIZE { move = MOVE_ICE_BEAM; targetPlayer = TRUE; } - PARAMETRIZE { move = MOVE_ROCK_THROW; targetPlayer = TRUE; } - PARAMETRIZE { move = MOVE_THUNDER_SHOCK; targetPlayer = FALSE; } - PARAMETRIZE { move = MOVE_ICE_BEAM; targetPlayer = FALSE; } - PARAMETRIZE { move = MOVE_ROCK_THROW; targetPlayer = FALSE; } + PARAMETRIZE { move = MOVE_THUNDER_SHOCK; } + PARAMETRIZE { move = MOVE_ICE_BEAM; } + PARAMETRIZE { move = MOVE_ROCK_THROW; } GIVEN { - ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); - ASSUME(GetMoveType(MOVE_ICE_BEAM) == TYPE_ICE); - ASSUME(GetMoveType(MOVE_ROCK_THROW) == TYPE_ROCK); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, move); } PLAYER(SPECIES_PIDGEY); OPPONENT(SPECIES_PIDGEY); OPPONENT(SPECIES_WOBBUFFET); } WHEN { - if (targetPlayer) - TURN { MOVE(opponentLeft, move, target: playerRight); } - else - TURN { MOVE(playerRight, move, target: opponentLeft); } - } SCENE { - if (targetPlayer) { - if (move == MOVE_THUNDER_SHOCK) - MESSAGE("The opposing Pidgey used Thunder Shock!"); - else if (move == MOVE_ICE_BEAM) - MESSAGE("The opposing Pidgey used Ice Beam!"); - else - MESSAGE("The opposing Pidgey used Rock Throw!"); - MESSAGE("The mysterious strong winds weakened the attack!"); - ANIMATION(ANIM_TYPE_MOVE, move, opponentLeft); - } else { - if (move == MOVE_THUNDER_SHOCK) - MESSAGE("Pidgey used Thunder Shock!"); - else if (move == MOVE_ICE_BEAM) - MESSAGE("Pidgey used Ice Beam!"); - else - MESSAGE("Pidgey used Rock Throw!"); - MESSAGE("The mysterious strong winds weakened the attack!"); - ANIMATION(ANIM_TYPE_MOVE, move, playerRight); + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { + MOVE(playerLeft, move, target: opponentLeft); + MOVE(opponentRight, move, target: playerRight); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); + EFFECTIVENESS_SE(opponentLeft, SE_EFFECTIVE); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + EFFECTIVENESS_SE(playerRight, SE_EFFECTIVE); + HP_BAR(playerRight); } } -DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers - Inverse Battle", s16 damagePlayer, s16 damageOpponent) // Bug, Fighting, Grass +DOUBLE_BATTLE_TEST("Strong winds remove Flying-type weaknesses of all battlers - Inverse Battle") { enum Move move; - bool32 strongWinds; - - PARAMETRIZE { move = MOVE_BUG_BITE; strongWinds = FALSE; } - PARAMETRIZE { move = MOVE_BUG_BITE; strongWinds = TRUE; } - PARAMETRIZE { move = MOVE_KARATE_CHOP; strongWinds = FALSE; } - PARAMETRIZE { move = MOVE_KARATE_CHOP; strongWinds = TRUE; } - PARAMETRIZE { move = MOVE_VINE_WHIP; strongWinds = FALSE; } - PARAMETRIZE { move = MOVE_VINE_WHIP; strongWinds = TRUE; } + PARAMETRIZE { move = MOVE_BUG_BITE; } + PARAMETRIZE { move = MOVE_KARATE_CHOP; } + PARAMETRIZE { move = MOVE_VINE_WHIP; } + PARAMETRIZE { move = MOVE_MUD_SLAP; } GIVEN { FLAG_SET(B_FLAG_INVERSE_BATTLE); ASSUME(GetMoveType(MOVE_BUG_BITE) == TYPE_BUG); ASSUME(GetMoveType(MOVE_KARATE_CHOP) == TYPE_FIGHTING); ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); + ASSUME(GetMoveType(MOVE_MUD_SLAP) == TYPE_GROUND); ASSUME(GetSpeciesType(SPECIES_TORNADUS, 0) == TYPE_FLYING); ASSUME(GetSpeciesType(SPECIES_TORNADUS, 1) == TYPE_FLYING); - if (strongWinds) - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } - else - PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, move); } PLAYER(SPECIES_TORNADUS); OPPONENT(SPECIES_TORNADUS); OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(playerLeft, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { - MOVE(opponentLeft, move, target: playerRight); - MOVE(playerRight, move, target: opponentLeft); + MOVE(playerLeft, move, target: opponentLeft); + MOVE(opponentRight, move, target: playerRight); } } SCENE { - HP_BAR(playerRight, captureDamage: &results[i].damagePlayer); - HP_BAR(opponentLeft, captureDamage: &results[i].damageOpponent); - } FINALLY { - EXPECT_GT(results[0].damagePlayer, results[1].damagePlayer); - EXPECT_GT(results[0].damageOpponent, results[1].damageOpponent); - EXPECT_GT(results[2].damagePlayer, results[3].damagePlayer); - EXPECT_GT(results[2].damageOpponent, results[3].damageOpponent); - EXPECT_GT(results[4].damagePlayer, results[5].damagePlayer); - EXPECT_GT(results[4].damageOpponent, results[5].damageOpponent); + ABILITY_POPUP(playerLeft, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, move, playerLeft); + EFFECTIVENESS_SE(opponentLeft, SE_EFFECTIVE); + HP_BAR(opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, move, opponentRight); + EFFECTIVENESS_SE(playerRight, SE_EFFECTIVE); + HP_BAR(playerRight); } } @@ -99,16 +79,13 @@ SINGLE_BATTLE_TEST("Strong winds prevent Weakness Policy from activating on Flyi { GIVEN { ASSUME(GetItemHoldEffect(ITEM_WEAKNESS_POLICY) == HOLD_EFFECT_WEAKNESS_POLICY); - ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_THUNDER_SHOCK); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_THUNDER_SHOCK); } OPPONENT(SPECIES_PIDGEY) { Item(ITEM_WEAKNESS_POLICY); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(player, MOVE_THUNDER_SHOCK); } } SCENE { - MESSAGE("Rayquaza used Thunder Shock!"); - MESSAGE("The mysterious strong winds weakened the attack!"); + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_SHOCK, player); HP_BAR(opponent); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); @@ -118,35 +95,36 @@ SINGLE_BATTLE_TEST("Strong winds prevent Weakness Policy from activating on Flyi SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active") { GIVEN { - ASSUME(GetMoveType(MOVE_THUNDER_SHOCK) == TYPE_ELECTRIC); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_THUNDER_SHOCK, MOVE_CELEBRATE); } - OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_CELEBRATE); } + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 0) == TYPE_DRAGON); + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + OPPONENT(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_ROCK_THROW, MOVE_SKILL_SWAP); } } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); MOVE(opponent, MOVE_SKILL_SWAP); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); - MESSAGE("Rayquaza used Celebrate!"); - MESSAGE("The opposing Pidgey used Celebrate!"); + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + ABILITY_POPUP(player, ABILITY_ANTICIPATION); } } -SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active in Inverse Battle") +SINGLE_BATTLE_TEST("Anticipation still triggers with Strong Winds active - Inverse Battle") { GIVEN { FLAG_SET(B_FLAG_INVERSE_BATTLE); - ASSUME(GetMoveType(MOVE_VINE_WHIP) == TYPE_GRASS); - ASSUME(GetSpeciesType(SPECIES_TORNADUS, 0) == TYPE_FLYING); - ASSUME(GetSpeciesType(SPECIES_TORNADUS, 1) == TYPE_FLYING); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); Moves(MOVE_VINE_WHIP, MOVE_CELEBRATE); } - OPPONENT(SPECIES_TORNADUS) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_CELEBRATE); } + ASSUME(GetMoveType(MOVE_BUG_BITE) == TYPE_BUG); + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 0) == TYPE_DRAGON); + ASSUME(GetSpeciesType(SPECIES_RAYQUAZA_MEGA, 1) == TYPE_FLYING); + ASSUME(GetMoveEffect(MOVE_SKILL_SWAP) == EFFECT_SKILL_SWAP); + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } + OPPONENT(SPECIES_EEVEE) { Ability(ABILITY_ANTICIPATION); Moves(MOVE_BUG_BITE, MOVE_SKILL_SWAP); } } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE); MOVE(opponent, MOVE_CELEBRATE); } + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); MOVE(opponent, MOVE_SKILL_SWAP); } } SCENE { - ABILITY_POPUP(opponent, ABILITY_ANTICIPATION); - MESSAGE("Rayquaza used Celebrate!"); - MESSAGE("The opposing Tornadus used Celebrate!"); + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SKILL_SWAP, opponent); + ABILITY_POPUP(player, ABILITY_ANTICIPATION); } } @@ -154,18 +132,17 @@ SINGLE_BATTLE_TEST("Strong winds don't affect Stealth Rock's damage") { GIVEN { ASSUME(GetMoveEffect(MOVE_STEALTH_ROCK) == EFFECT_STEALTH_ROCK); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 0) == TYPE_NORMAL); - ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING); PLAYER(SPECIES_WOBBUFFET); - PLAYER(SPECIES_PIDGEY); - OPPONENT(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_PIDGEY){ HP(200); MaxHP(200); } + OPPONENT(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, MOVE_STEALTH_ROCK); } } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(opponent, MOVE_STEALTH_ROCK); } TURN { SWITCH(player, 1); } } SCENE { - s32 maxHP = GetMonData(&PLAYER_PARTY[1], MON_DATA_MAX_HP); + ABILITY_POPUP(opponent, ABILITY_DELTA_STREAM); ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); - HP_BAR(player, damage: maxHP / 4); + HP_BAR(player, damage: 50); } } @@ -185,11 +162,13 @@ SINGLE_BATTLE_TEST("Strong winds block weather-setting moves") ASSUME(GetMoveWeatherType(MOVE_SANDSTORM) == BATTLE_WEATHER_SANDSTORM); ASSUME(GetMoveWeatherType(MOVE_HAIL) == BATTLE_WEATHER_HAIL); ASSUME(GetMoveWeatherType(MOVE_SNOWSCAPE) == BATTLE_WEATHER_SNOW); - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { MOVE(opponent, move); } } SCENE { + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); NOT ANIMATION(ANIM_TYPE_MOVE, move, opponent); } THEN { EXPECT(gBattleWeather & B_WEATHER_STRONG_WINDS); @@ -206,10 +185,11 @@ SINGLE_BATTLE_TEST("Strong winds prevent other weather abilities") PARAMETRIZE { ability = ABILITY_SNOW_WARNING; species = SPECIES_ABOMASNOW; } GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(species) { Ability(ability); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { SWITCH(opponent, 1); } } SCENE { ABILITY_POPUP(opponent, ability); @@ -221,10 +201,11 @@ SINGLE_BATTLE_TEST("Strong winds prevent other weather abilities") SINGLE_BATTLE_TEST("Strong winds can be replaced by Desolate Land") { GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_GROUDON) { Item(ITEM_RED_ORB); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { SWITCH(opponent, 1); } } SCENE { ABILITY_POPUP(opponent, ABILITY_DESOLATE_LAND); @@ -237,10 +218,11 @@ SINGLE_BATTLE_TEST("Strong winds can be replaced by Desolate Land") SINGLE_BATTLE_TEST("Strong winds can be replaced by Primordial Sea") { GIVEN { - PLAYER(SPECIES_RAYQUAZA) { Ability(ABILITY_DELTA_STREAM); } + PLAYER(SPECIES_RAYQUAZA) { Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE); } OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_KYOGRE) { Item(ITEM_BLUE_ORB); } } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } TURN { SWITCH(opponent, 1); } } SCENE { ABILITY_POPUP(opponent, ABILITY_PRIMORDIAL_SEA); @@ -249,3 +231,24 @@ SINGLE_BATTLE_TEST("Strong winds can be replaced by Primordial Sea") EXPECT(gBattleWeather & B_WEATHER_RAIN_PRIMAL); } } + +SINGLE_BATTLE_TEST("Strong winds don't reduce Synthesis, Morning Sun or Moonlight recovery") +{ + enum Move move; + enum BattleMoveEffects effect; + PARAMETRIZE { move = MOVE_SYNTHESIS; effect = EFFECT_SYNTHESIS; } + PARAMETRIZE { move = MOVE_MORNING_SUN; effect = EFFECT_MORNING_SUN; } + PARAMETRIZE { move = MOVE_MOONLIGHT; effect = EFFECT_MOONLIGHT; } + + GIVEN { + ASSUME(GetMoveEffect(move) == effect); + PLAYER(SPECIES_RAYQUAZA) { HP(1); MaxHP(200); Moves(MOVE_DRAGON_ASCENT, MOVE_CELEBRATE, move); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_MEGA); } + TURN { MOVE(player, move); } + } SCENE { + ABILITY_POPUP(player, ABILITY_DELTA_STREAM); + HP_BAR(player, damage: -100); + } +} diff --git a/test/test_runner.c b/test/test_runner.c index 007ee6b21d..45684247f3 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -1,6 +1,6 @@ #include -#include "fake_rtc.h" #include "global.h" +#include "fake_rtc.h" #include "gpu_regs.h" #include "load_save.h" #include "main.h" @@ -135,6 +135,8 @@ void TestRunner_CheckMemory(void) if (gTestRunnerState.result == TEST_RESULT_PASS && !gTestRunnerState.expectLeaks) { + TestFreeConfigData(); + int i; const struct MemBlock *head = HeapHead(); const struct MemBlock *block = head; @@ -154,16 +156,11 @@ void TestRunner_CheckMemory(void) const char *location = MemBlockLocation(block); if (location) { - const char cmpString[] = "src/config_changes.c"; - if (strncmp(cmpString, location, sizeof(cmpString) - 1) != 0) - { - Test_MgbaPrintf("%s: %d bytes not freed", location, block->size); - gTestRunnerState.result = TEST_RESULT_FAIL; - - if (gTestRunnerState.expectedFailState == EXPECT_FAIL_OPEN) - gTestRunnerState.expectedFailState = EXPECT_FAIL_SUCCESS; - break; - } + Test_MgbaPrintf("%s: %d bytes not freed", location, block->size); + gTestRunnerState.result = TEST_RESULT_FAIL; + + if (gTestRunnerState.expectedFailState == EXPECT_FAIL_OPEN) + gTestRunnerState.expectedFailState = EXPECT_FAIL_SUCCESS; } else { @@ -182,7 +179,7 @@ void TestRunner_CheckMemory(void) { if (gTasks[i].isActive) { - Test_MgbaPrintf(":L%s:%d - %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); + Test_MgbaPrintf(":L%s:%d: %p: task not freed", gTestRunnerState.test->filename, SourceLine(0), gTasks[i].func); gTestRunnerState.result = TEST_RESULT_FAIL; if (gTestRunnerState.expectedFailState == EXPECT_FAIL_OPEN) @@ -254,7 +251,7 @@ top: if (gPersistentTestRunnerState.expectCrash) gTestRunnerState.expectedResult = TEST_RESULT_CRASH; - + gTestRunnerState.expectedFailLine = 0; gTestRunnerState.expectedFailState = NO_EXPECT_FAIL; } @@ -277,11 +274,21 @@ top: gTestRunnerState.state = STATE_EXIT; return; } - if (gTestRunnerState.test->runner != &gAssumptionsRunner) + if (gTestRunnerState.filterMode == TEST_FILTER_MODE_FILENAME_EXACT + && !ExactMatch(gTestRunnerArgv, gTestRunnerState.test->filename)) + { + ++gTestRunnerState.test; + continue; + } + // Run all assumption blocks when filtering on test name + // because it's possible that a test in this file could + // match. + // TODO: Delay running the assumptions block until we find a + // test name that matches. + else if (gTestRunnerState.test->runner != &gAssumptionsRunner) { if ((gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_PREFIX && !PrefixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) - || (gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_INFIX && !InfixMatch(gTestRunnerArgv, gTestRunnerState.test->name)) - || (gTestRunnerState.filterMode == TEST_FILTER_MODE_FILENAME_EXACT && !ExactMatch(gTestRunnerArgv, gTestRunnerState.test->filename))) + || (gTestRunnerState.filterMode == TEST_FILTER_MODE_TEST_NAME_INFIX && !InfixMatch(gTestRunnerArgv, gTestRunnerState.test->name))) { ++gTestRunnerState.test; continue; @@ -326,10 +333,8 @@ top: SeedRng(0); SeedRng2(0); if (gTestRunnerState.test->runner->setUp) - { gTestRunnerState.test->runner->setUp(gTestRunnerState.test->data); - gTestRunnerState.tearDown = TRUE; - } + gTestRunnerState.tearDown = TRUE; // NOTE: Assumes that the compiler interns __FILE__. if (gTestRunnerState.skipFilename == gTestRunnerState.test->filename) // Assumption fails for tests in this file. { @@ -349,10 +354,8 @@ top: gTestRunnerState.state = STATE_NEXT_TEST; if (gTestRunnerState.tearDown && gTestRunnerState.test->runner->tearDown) - { gTestRunnerState.test->runner->tearDown(gTestRunnerState.test->data); - gTestRunnerState.tearDown = FALSE; - } + gTestRunnerState.tearDown = FALSE; TestRunner_CheckMemory(); @@ -724,7 +727,7 @@ static void Intr_Timer2(void) if (gTestRunnerState.state == STATE_RUN_TEST) gTestRunnerState.state = STATE_REPORT_RESULT; gTestRunnerState.result = TEST_RESULT_TIMEOUT; - Test_MgbaPrintf(":L%s:%d - TIMEOUT", gTestRunnerState.test->filename, SourceLine(0)); + Test_MgbaPrintf(":L%s:%d: TIMEOUT", gTestRunnerState.test->filename, SourceLine(0)); ReinitCallbacks(); IRQ_LR = ((uintptr_t)JumpToAgbMainLoop & ~1) + 4; } @@ -760,7 +763,7 @@ void Test_ExitWithResult_(enum TestResult result, u32 stopLine, const void *retu gTestRunnerState.test->filename, stopLine, gTestRunnerState.expectedFailLine, stopLine); } - + ReinitCallbacks(); if (gTestRunnerState.state == STATE_REPORT_RESULT && gTestRunnerState.result != gTestRunnerState.expectedResult) @@ -817,12 +820,17 @@ static s32 MgbaPutchar_(s32 i, s32 c) return i; } -extern const u8 gWireless_RSEtoASCIITable[]; - -// Bare-bones, only supports plain %s, %S, and %d. +// Bare-bones, supports: +// - %s, %.*s: print an ASCII string. +// - %S, %.*S: print a GF-encoded string. +// - %d: print a signed integer. +// - %q: print a Q20.12 fixed-point number. +// - %p: print a pointer (which mgba-rom-test-hydra will convert into a +// symbol, if possible). static s32 MgbaVPrintf_(const char *fmt, va_list va) { s32 i = 0; + s32 n; s32 c, d; u32 p; const char *s; @@ -832,6 +840,16 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) switch ((c = *fmt++)) { case '%': + if (fmt[0] == '.' && fmt[1] == '*') + { + fmt += 2; + n = va_arg(va, int); + } + else + { + n = INT_MAX; + } + switch (*fmt++) { case '%': @@ -913,7 +931,9 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) if (++n == 2) { u *= 10; - i = MgbaPutchar_(i, '0' + ((u + UQ_4_12_ROUND) >> 12)); + // TODO: 'min' is a hack, we should have + // rounded up the previous number. + i = MgbaPutchar_(i, min('0' + ((u + UQ_4_12_ROUND) >> 12), '9')); break; } } @@ -921,7 +941,7 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) break; case 's': s = va_arg(va, const char *); - while ((c = *s++) != '\0') + while ((c = *s++) != '\0' && n-- > 0) i = MgbaPutchar_(i, c); break; case 'S': @@ -935,13 +955,9 @@ static s32 MgbaVPrintf_(const char *fmt, va_list va) } else { - while ((c = *pokeS++) != EOS) - { - if ((c = gWireless_RSEtoASCIITable[c]) != '\0') - i = MgbaPutchar_(i, c); - else - i = MgbaPutchar_(i, '?'); - } + extern char mini_pchar_decode(u8); + while ((c = *pokeS++) != EOS && n-- > 0) + i = MgbaPutchar_(i, mini_pchar_decode(c)); } break; } diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 34e9da72b9..ca24c7a4e9 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -290,7 +290,6 @@ static void BattleTest_SetUp(void *data) { const struct BattleTest *test = data; memset(STATE, 0, sizeof(*STATE)); - TestInitConfigData(); InvokeTestFunction(test); STATE->parameters = STATE->parametersCount; if (STATE->parametersCount == 0 && test->resultsSize > 0) @@ -382,6 +381,7 @@ static void BattleTest_Run(void *data) const struct BattleTest *test = data; memset(&DATA, 0, sizeof(DATA)); + TestInitConfigData(); DATA.recordedBattle.rngSeed = defaultSeed; DATA.recordedBattle.textSpeed = OPTIONS_TEXT_SPEED_FAST;