diff --git a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml index 24b57d117e..cdffd6838c 100644 --- a/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml +++ b/.github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml @@ -23,9 +23,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using as a base? options: - - 1.8.2 (Latest release) + - 1.8.3 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.8.2 - 1.8.1 - 1.8.0 - 1.7.4 diff --git a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml index 562468cce1..bf31df9931 100644 --- a/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml +++ b/.github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml @@ -23,9 +23,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using as a base? options: - - 1.8.2 (Latest release) + - 1.8.3 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.8.2 - 1.8.1 - 1.8.0 - 1.7.4 diff --git a/.github/ISSUE_TEMPLATE/04_other_errors.yaml b/.github/ISSUE_TEMPLATE/04_other_errors.yaml index 4658ecfb69..6920d34a83 100644 --- a/.github/ISSUE_TEMPLATE/04_other_errors.yaml +++ b/.github/ISSUE_TEMPLATE/04_other_errors.yaml @@ -23,9 +23,10 @@ body: label: Version description: What version of pokeemerald-expansion are you using as a base? options: - - 1.8.2 (Latest release) + - 1.8.3 (Latest release) - master (default, unreleased bugfixes) - upcoming (Edge) + - 1.8.2 - 1.8.1 - 1.8.0 - 1.7.4 diff --git a/.gitignore b/.gitignore index af9009dd01..ba80433cf7 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ prefabs.json *.sym *.js src/data/map_group_count.h +tools/trainerproc/trainerproc diff --git a/CHANGELOG.md b/CHANGELOG.md index dea05701d5..8aeeac5dec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,46 +1,47 @@ # Pokeemerald-Expansion Changelogs ## 1.8.x -- ### [Version 1.8.2](docs/changelogs/1.8.2.md) - Bugfix Release 🧹 -- ### [Version 1.8.1](docs/changelogs/1.8.1.md) - HOTFIX Release 🔥 -- ### [Version 1.8.0](docs/changelogs/1.8.0.md) - Feature Release ✨ +- ### [Version 1.8.3](docs/changelogs/1.8.x/1.8.3.md) - Bugfix Release 🧹 +- ### [Version 1.8.2](docs/changelogs/1.8.x/1.8.2.md) - Bugfix Release 🧹 +- ### [Version 1.8.1](docs/changelogs/1.8.x/1.8.1.md) - HOTFIX Release 🔥 +- ### [Version 1.8.0](docs/changelogs/1.8.x/1.8.0.md) - Feature Release ✨ ## 1.7.x -- ### [Version 1.7.4](docs/changelogs/1.7.4.md) - Bugfix Release 🧹 -- ### [Version 1.7.3](docs/changelogs/1.7.3.md) - Bugfix Release 🧹 -- ### [Version 1.7.2](docs/changelogs/1.7.2.md) - Bugfix Release 🧹 -- ### [Version 1.7.1](docs/changelogs/1.7.1.md) - Bugfix Release 🧹 -- ### [Version 1.7.0](docs/changelogs/1.7.0.md) - Feature Release ✨ +- ### [Version 1.7.4](docs/changelogs/1.7.x/1.7.4.md) - Bugfix Release 🧹 +- ### [Version 1.7.3](docs/changelogs/1.7.x/1.7.3.md) - Bugfix Release 🧹 +- ### [Version 1.7.2](docs/changelogs/1.7.x/1.7.2.md) - Bugfix Release 🧹 +- ### [Version 1.7.1](docs/changelogs/1.7.x/1.7.1.md) - Bugfix Release 🧹 +- ### [Version 1.7.0](docs/changelogs/1.7.x/1.7.0.md) - Feature Release ✨ ## 1.6.x -- ### [Version 1.6.2](docs/changelogs/1.6.2.md) - Bugfix Release 🧹 -- ### [Version 1.6.1](docs/changelogs/1.6.1.md) - HOTFIX Release 🔥 -- ### [Version 1.6.0](docs/changelogs/1.6.0.md) - Feature Release ✨ +- ### [Version 1.6.2](docs/changelogs/1.6.x/1.6.2.md) - Bugfix Release 🧹 +- ### [Version 1.6.1](docs/changelogs/1.6.x/1.6.1.md) - HOTFIX Release 🔥 +- ### [Version 1.6.0](docs/changelogs/1.6.x/1.6.0.md) - Feature Release ✨ ## 1.5.x -- ### [Version 1.5.3](docs/changelogs/1.5.3.md) - HOTFIX Release 🔥 -- ### [Version 1.5.2](docs/changelogs/1.5.2.md) - Bugfix Release 🧹 -- ### [Version 1.5.1](docs/changelogs/1.5.1.md) - Bugfix Release 🧹 -- ### [Version 1.5.0](docs/changelogs/1.5.0.md) - Feature Release ✨ +- ### [Version 1.5.3](docs/changelogs/1.5.x/1.5.3.md) - HOTFIX Release 🔥 +- ### [Version 1.5.2](docs/changelogs/1.5.x/1.5.2.md) - Bugfix Release 🧹 +- ### [Version 1.5.1](docs/changelogs/1.5.x/1.5.1.md) - Bugfix Release 🧹 +- ### [Version 1.5.0](docs/changelogs/1.5.x/1.5.0.md) - Feature Release ✨ ## 1.4.x -- ### [Version 1.4.3](docs/changelogs/1.4.3.md) - Bugfix Release 🧹 -- ### [Version 1.4.2](docs/changelogs/1.4.2.md) - Bugfix Release 🧹 -- ### [Version 1.4.1](docs/changelogs/1.4.1.md) - HOTFIX Release 🔥 -- ### [Version 1.4.0](docs/changelogs/1.4.0.md) - Feature Release ✨ +- ### [Version 1.4.3](docs/changelogs/1.4.x/1.4.3.md) - Bugfix Release 🧹 +- ### [Version 1.4.2](docs/changelogs/1.4.x/1.4.2.md) - Bugfix Release 🧹 +- ### [Version 1.4.1](docs/changelogs/1.4.x/1.4.1.md) - HOTFIX Release 🔥 +- ### [Version 1.4.0](docs/changelogs/1.4.x/1.4.0.md) - Feature Release ✨ ## 1.3.x -- ### [Version 1.3.0](docs/changelogs/1.3.0.md) - Feature Release ✨ +- ### [Version 1.3.0](docs/changelogs/1.3.x/1.3.0.md) - Feature Release ✨ ## 1.2.x -- ### [Version 1.2.0](docs/changelogs/1.2.0.md) - Feature Release ✨ +- ### [Version 1.2.0](docs/changelogs/1.2.x/1.2.0.md) - Feature Release ✨ ## 1.1.x -- ### [Version 1.1.1](docs/changelogs/1.1.1.md) - Bugfix Release 🧹 -- ### [Version 1.1.0](docs/changelogs/1.1.0.md) - Feature Release ✨ +- ### [Version 1.1.1](docs/changelogs/1.1.x/1.1.1.md) - Bugfix Release 🧹 +- ### [Version 1.1.0](docs/changelogs/1.1.x/1.1.0.md) - Feature Release ✨ ## 1.0.x -- ### [Version 1.0.0](docs/changelogs/1.0.0.md) - Feature Release ✨ +- ### [Version 1.0.0](docs/changelogs/1.0.x/1.0.0.md) - Feature Release ✨ ## Pre-1.0.x: -- ### [Version 0.9.0](docs/changelogs/0.9.0.md) - Retroactive Version 🦕 +- ### [Version 0.9.0](docs/changelogs/0.9.x/0.9.0.md) - Retroactive Version 🦕 diff --git a/README.md b/README.md index 6487086183..855ddc7b7f 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ Based off RHH's pokeemerald-expansion v1.8.0 https://github.com/rh-hideout/pokee ## What features are included? - ***IMPORTANT*❗❗ Read through these to learn what features you can toggle**: - - [Battle configurations](/include/config/battle.h) - - [Pokémon configurations](/include/config/pokemon.h) - - [Item configurations](/include/config/item.h) - - [Overworld configurations](/include/config/overworld.h) - - [Debug configurations](/include/config/debug.h) + - [Battle configurations](include/config/battle.h) + - [Pokémon configurations](include/config/pokemon.h) + - [Item configurations](include/config/item.h) + - [Overworld configurations](include/config/overworld.h) + - [Debug configurations](include/config/debug.h) - ***Upgraded battle engine.*** - Gen5+ damage calculation. - 2v2 Wild battles support. @@ -62,7 +62,7 @@ Based off RHH's pokeemerald-expansion v1.8.0 https://github.com/rh-hideout/pokee - Recalculating stats at the end of every battle. - Level 100 Pokémon can earn EVs. - Inverse battle support. - - TONS of other features listed [here](/include/config/battle.h). + - TONS of other features listed [here](include/config/battle.h). - ***Full Trainer customization*** - Nickname, EVs, IVs, moves, ability, ball, friendship, nature, gender, shininess. - Custom tag battle support (teaming up an NPC in a double battle). @@ -94,7 +94,7 @@ Based off RHH's pokeemerald-expansion v1.8.0 https://github.com/rh-hideout/pokee - All gender differences. - Custom female icons for female Hippopotas Hippowdon, Pikachu and Wobbufett - 3 Perfect IVs on Legendaries, Mythicals and Ultra Beasts. -- ***Customizable form change tables. Full list of methods [here](/include/constants/form_change_types.h).*** +- ***Customizable form change tables. Full list of methods [here](include/constants/form_change_types.h).*** - Item holding (eg. Giratina/Arceus) - Item using (eg. Oricorio) - Time of day option for Shaymin @@ -115,7 +115,7 @@ Based off RHH's pokeemerald-expansion v1.8.0 https://github.com/rh-hideout/pokee - Egg Move Transfer, including Mirror Herb (configurable). - Nature inheriting 100% of the time with Everstone (configurable) - Gen6+ Ability inheriting (configurable). -- ***Items from newer Generations. Full list [here](/include/constants/items.h).*** +- ***Items from newer Generations. Full list [here](include/constants/items.h).*** - ***Gen 6+ Exp. Share*** (configurable) - Berserk Gene - Most battle items from Gen 4+ @@ -170,7 +170,7 @@ With this, you'll get the latest version of pokeemerald-expansion, plus a couple - Check your current version. - You can check in the debug menu's `Utilities -> Expansion Version` option. - If the option is not available, you possibly have version 1.6.2 or older. In that case, please check the [changelogs](CHANGELOG.md) to determine your version based on the features available on your repository. -- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.8.2, use `git pull RHH expansion/1.8.2`). +- Once you have your remote set up, run the command `git pull RHH expansion/X.Y.Z`, replacing X, Y and Z with the digits of the respective version you want to update to (eg, to update to 1.8.3, use `git pull RHH expansion/1.8.3`). - ***Important:*** If you are several versions behind, we recommend updating one minor version at a time, skipping directly to the latest patch version (eg, 1.5.3 -> 1.6.2 -> 1.7.4 and so on) - Alternatively, you can update to unreleased versions of the expansion. - ***master (stable):*** It contains unreleased **bugfixes** that will come in the next patch version. To merge, use `git pull RHH master`. diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 25e0110a51..34f29950bd 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -710,8 +710,9 @@ .byte 0x7c .endm - .macro setrain + .macro setfieldweather weather:req .byte 0x7d + .byte \weather .endm .macro setreflect @@ -833,7 +834,7 @@ .byte 0x94 .endm - .macro setsandstorm + .macro unused_95 .byte 0x95 .endm @@ -1005,7 +1006,7 @@ .4byte \jumpInstr .endm - .macro setsunny + .macro unused_bb .byte 0xbb .endm @@ -1080,7 +1081,7 @@ .byte 0xc7 .endm - .macro sethail + .macro unused_c8 .byte 0xc8 .endm @@ -1409,10 +1410,6 @@ callnative BS_TryRevertWeatherForm .endm - .macro setsnow - callnative BS_SetSnow - .endm - .macro applysaltcure battler:req callnative BS_ApplySaltCure .byte \battler @@ -1636,6 +1633,15 @@ callnative BS_TryGulpMissile .endm + .macro tryquash failInstr:req + callnative BS_TryQuash + .4byte \failInstr + .endm + + .macro removeweather + callnative BS_RemoveWeather + .endm + @ various command changed to more readable macros .macro cancelmultiturnmoves battler:req various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES @@ -1827,11 +1833,6 @@ various \battler, VARIOUS_SET_LAST_USED_ABILITY .endm - .macro tryquash failInstr:req - various BS_ATTACKER, VARIOUS_TRY_QUASH - .4byte \failInstr - .endm - .macro tryafteryou failInstr:req various BS_ATTACKER, VARIOUS_AFTER_YOU .4byte \failInstr diff --git a/asm/macros/event.inc b/asm/macros/event.inc index 09d5247522..5b3a164077 100644 --- a/asm/macros/event.inc +++ b/asm/macros/event.inc @@ -2178,3 +2178,16 @@ .2byte \status1 .2byte \slot .endm + + @ Sets VAR_RESULT to the Pokémon in \slot's Tera Type + .macro checkteratype slot:req + callnative CheckTeraType + .2byte \slot + .endm + + @ Sets the Pokémon in \slot's Tera Type + .macro setteratype type:req, slot:req + callnative SetTeraType + .byte \type + .2byte \slot + .endm diff --git a/charmap.txt b/charmap.txt index 7271c621ca..872e9f76e4 100644 --- a/charmap.txt +++ b/charmap.txt @@ -464,6 +464,9 @@ FONT_NORMAL = FC 06 01 FONT_SHORT = FC 06 02 FONT_NARROW = FC 06 07 FONT_SMALL_NARROW = FC 06 08 +FONT_NARROWER = FC 06 0A +FONT_SMALL_NARROWER = FC 06 0B +FONT_SHORT_NARROW = FC 06 0C @ colors diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index e66f4c2a8e..5dd00b2b6a 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -20,6 +20,34 @@ .section script_data, "aw", %progbits +BattleScript_Terastallization:: + @ TODO: no string prints in S/V, but right now this helps with clarity + printstring STRINGID_PKMNTERASTALLIZEDINTO + @ TODO: replace this animation + playanimation BS_ATTACKER, B_ANIM_TOTEM_FLARE + waitanimation + end3 + +BattleScript_LowerAtkSpAtk:: + jumpifstat BS_EFFECT_BATTLER, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_LowerAtkSpAtkDoAnim + jumpifstat BS_EFFECT_BATTLER, CMP_EQUAL, STAT_SPATK, MIN_STAT_STAGE, BattleScript_LowerAtkSpAtkEnd +BattleScript_LowerAtkSpAtkDoAnim:: + setbyte sSTAT_ANIM_PLAYED, FALSE + playstatchangeanimation BS_EFFECT_BATTLER, BIT_ATK | BIT_SPATK, STAT_CHANGE_NEGATIVE + setstatchanger STAT_ATK, 1, TRUE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_LowerAtkSpAtkTrySpAtk + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_LowerAtkSpAtkTrySpAtk + printfromtable gStatDownStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_LowerAtkSpAtkTrySpAtk:: + setstatchanger STAT_SPATK, 1, TRUE + statbuffchange MOVE_EFFECT_AFFECTS_USER | STAT_CHANGE_ALLOW_PTR, BattleScript_LowerAtkSpAtkEnd + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_LowerAtkSpAtkEnd + printfromtable gStatDownStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_LowerAtkSpAtkEnd: + return + BattleScript_EffectTidyUp:: attackcanceler attackstring @@ -159,7 +187,7 @@ BattleScript_EffectChillyReception:: jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_RAIN_PRIMAL, BattleScript_EffectChillyReceptionBlockedByPrimalRain jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_STRONG_WINDS, BattleScript_EffectChillyReceptionBlockedByStrongWinds call BattleScript_EffectChillyReceptionPlayAnimation - setsnow + setfieldweather ENUM_WEATHER_SNOW call BattleScript_MoveWeatherChangeRet goto BattleScript_MoveSwitch BattleScript_EffectChillyReceptionPlayAnimation: @@ -4307,7 +4335,7 @@ BattleScript_EffectSandstorm:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setsandstorm + setfieldweather ENUM_WEATHER_SANDSTORM goto BattleScript_MoveWeatherChange BattleScript_EffectRollout:: @@ -4473,7 +4501,7 @@ BattleScript_EffectRainDance:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setrain + setfieldweather ENUM_WEATHER_RAIN BattleScript_MoveWeatherChange:: attackanimation waitanimation @@ -4491,7 +4519,7 @@ BattleScript_EffectSunnyDay:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setsunny + setfieldweather ENUM_WEATHER_SUN goto BattleScript_MoveWeatherChange BattleScript_ExtremelyHarshSunlightWasNotLessened: @@ -4849,7 +4877,7 @@ BattleScript_EffectHail:: attackstring ppreduce call BattleScript_CheckPrimalWeather - sethail + setfieldweather ENUM_WEATHER_HAIL goto BattleScript_MoveWeatherChange BattleScript_EffectTorment:: @@ -6298,6 +6326,21 @@ BattleScript_DmgHazardsOnTargetFainted:: moveendall goto BattleScript_HandleFaintedMon +BattleScript_DmgHazardsOnBattlerScripting:: + orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE + healthbarupdate BS_SCRIPTING + datahpupdate BS_SCRIPTING + call BattleScript_PrintHurtByDmgHazards + tryfaintmon BS_SCRIPTING + tryfaintmon_spikes BS_SCRIPTING, BattleScript_DmgHazardsOnBattlerScriptingFainted + return + +BattleScript_DmgHazardsOnBattlerScriptingFainted:: + setbyte sGIVEEXP_STATE, 0 + getexp BS_SCRIPTING + moveendall + goto BattleScript_HandleFaintedMon + BattleScript_DmgHazardsOnFaintedBattler:: orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_PASSIVE_DAMAGE healthbarupdate BS_FAINTED @@ -6639,6 +6682,7 @@ BattleScript_DoFutureAttackResult: checkteamslost BattleScript_FutureAttackEnd BattleScript_FutureAttackEnd:: moveendcase MOVEEND_RAGE + moveendcase MOVEEND_ABILITIES moveendfromto MOVEEND_ITEM_EFFECTS_ALL, MOVEEND_UPDATE_LAST_MOVES setbyte gMoveResultFlags, 0 end2 @@ -7050,6 +7094,29 @@ BattleScript_AttackerFormChangeEnd3NoPopup:: call BattleScript_AttackerFormChangeNoPopup end3 +BattleScript_AttackerFormChangeWithString:: + pause 5 + copybyte gBattlerAbility, gBattlerAttacker + call BattleScript_AbilityPopUp + flushtextbox +BattleScript_AttackerFormChangeWithStringNoPopup:: + handleformchange BS_ATTACKER, 0 + handleformchange BS_ATTACKER, 1 + playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE + waitanimation + handleformchange BS_ATTACKER, 2 + printstring STRINGID_PKMNTRANSFORMED + waitmessage B_WAIT_TIME_LONG + return + +BattleScript_AttackerFormChangeWithStringEnd3:: + call BattleScript_AttackerFormChangeWithString + end3 + +BattleScript_AttackerFormChangeWithStringEnd3NoPopup:: + call BattleScript_AttackerFormChangeWithStringNoPopup + end3 + BattleScript_AttackerFormChangeMoveEffect:: waitmessage 1 handleformchange BS_ATTACKER, 0 @@ -7801,6 +7868,7 @@ BattleScript_IntimidateEffect: statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_IntimidateLoopIncrement setgraphicalstatchangevalues jumpifability BS_TARGET, ABILITY_CONTRARY, BattleScript_IntimidateContrary + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_IntimidateWontDecrease playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 printstring STRINGID_PKMNCUTSATTACKWITH BattleScript_IntimidateEffect_WaitString: @@ -7817,6 +7885,10 @@ BattleScript_IntimidateEnd: pause B_WAIT_TIME_MED end3 +BattleScript_IntimidateWontDecrease: + printstring STRINGID_STATSWONTDECREASE + goto BattleScript_IntimidateEffect_WaitString + BattleScript_IntimidateContrary: call BattleScript_AbilityPopUpTarget jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_IntimidateContrary_WontIncrease @@ -7856,6 +7928,7 @@ BattleScript_SupersweetSyrupEffect: statbuffchange STAT_CHANGE_NOT_PROTECT_AFFECTED | STAT_CHANGE_ALLOW_PTR, BattleScript_SupersweetSyrupLoopIncrement setgraphicalstatchangevalues jumpifability BS_TARGET, ABILITY_CONTRARY, BattleScript_SupersweetSyrupContrary + jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_DECREASE, BattleScript_SupersweetSyrupWontDecrease playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1 printfromtable gStatDownStringIds BattleScript_SupersweetSyrupEffect_WaitString: @@ -7872,6 +7945,10 @@ BattleScript_SupersweetSyrupEnd: pause B_WAIT_TIME_MED end3 +BattleScript_SupersweetSyrupWontDecrease: + printstring STRINGID_STATSWONTDECREASE + goto BattleScript_SupersweetSyrupEffect_WaitString + BattleScript_SupersweetSyrupContrary: call BattleScript_AbilityPopUpTarget jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_SupersweetSyrupContrary_WontIncrease @@ -7945,7 +8022,7 @@ BattleScript_QuarkDriveActivates:: BattleScript_RuinAbilityActivates:: call BattleScript_AbilityPopUp - printstring STRINGID_ABILITYWEAKENEDFSURROUNDINGMONSSTAT + printstring STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT waitmessage B_WAIT_TIME_LONG end3 @@ -8318,6 +8395,13 @@ BattleScript_ProteanActivates:: waitmessage B_WAIT_TIME_LONG return +BattleScript_TeraShellDistortingTypeMatchups:: + pause B_WAIT_TIME_SHORTEST + call BattleScript_AbilityPopUp + printstring STRINGID_PKMNMADESHELLGLEAM + waitmessage B_WAIT_TIME_LONG + return + BattleScript_CursedBodyActivates:: call BattleScript_AbilityPopUp printstring STRINGID_CUSEDBODYDISABLED @@ -9223,6 +9307,25 @@ BattleScript_AnnounceAirLockCloudNine:: call BattleScript_ActivateWeatherAbilities end3 +BattleScript_ActivateTeraformZero:: + call BattleScript_AbilityPopUp + waitmessage B_WAIT_TIME_LONG + jumpifhalfword CMP_COMMON_BITS, gBattleWeather, B_WEATHER_ANY, BattleScript_ActivateTeraformZero_RemoveWeather + jumpifhalfword CMP_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ActivateTeraformZero_RemoveTerrain + goto BattleScript_ActivateTeraformZero_End +BattleScript_ActivateTeraformZero_RemoveWeather: + removeweather + printfromtable gWeatherEndsStringIds + waitmessage B_WAIT_TIME_LONG + jumpifhalfword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ActivateTeraformZero_End +BattleScript_ActivateTeraformZero_RemoveTerrain: + removeterrain + playanimation BS_ATTACKER, B_ANIM_RESTORE_BG + printfromtable gTerrainStringIds + waitmessage B_WAIT_TIME_LONG +BattleScript_ActivateTeraformZero_End: + end3 + BattleScript_QuickClawActivation:: flushtextbox playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT @@ -9968,5 +10071,5 @@ BattleScript_EffectSnow:: attackstring ppreduce call BattleScript_CheckPrimalWeather - setsnow + setfieldweather ENUM_WEATHER_SNOW goto BattleScript_MoveWeatherChange diff --git a/docs/changelogs/0.9.0.md b/docs/changelogs/0.9.x/0.9.0.md similarity index 100% rename from docs/changelogs/0.9.0.md rename to docs/changelogs/0.9.x/0.9.0.md diff --git a/docs/changelogs/1.0.0.md b/docs/changelogs/1.0.x/1.0.0.md similarity index 100% rename from docs/changelogs/1.0.0.md rename to docs/changelogs/1.0.x/1.0.0.md diff --git a/docs/changelogs/1.1.0.md b/docs/changelogs/1.1.x/1.1.0.md similarity index 100% rename from docs/changelogs/1.1.0.md rename to docs/changelogs/1.1.x/1.1.0.md diff --git a/docs/changelogs/1.1.1.md b/docs/changelogs/1.1.x/1.1.1.md similarity index 100% rename from docs/changelogs/1.1.1.md rename to docs/changelogs/1.1.x/1.1.1.md diff --git a/docs/changelogs/1.2.0.md b/docs/changelogs/1.2.x/1.2.0.md similarity index 100% rename from docs/changelogs/1.2.0.md rename to docs/changelogs/1.2.x/1.2.0.md diff --git a/docs/changelogs/1.3.0.md b/docs/changelogs/1.3.x/1.3.0.md similarity index 100% rename from docs/changelogs/1.3.0.md rename to docs/changelogs/1.3.x/1.3.0.md diff --git a/docs/changelogs/1.4.0.md b/docs/changelogs/1.4.x/1.4.0.md similarity index 100% rename from docs/changelogs/1.4.0.md rename to docs/changelogs/1.4.x/1.4.0.md diff --git a/docs/changelogs/1.4.1.md b/docs/changelogs/1.4.x/1.4.1.md similarity index 100% rename from docs/changelogs/1.4.1.md rename to docs/changelogs/1.4.x/1.4.1.md diff --git a/docs/changelogs/1.4.2.md b/docs/changelogs/1.4.x/1.4.2.md similarity index 100% rename from docs/changelogs/1.4.2.md rename to docs/changelogs/1.4.x/1.4.2.md diff --git a/docs/changelogs/1.4.3.md b/docs/changelogs/1.4.x/1.4.3.md similarity index 100% rename from docs/changelogs/1.4.3.md rename to docs/changelogs/1.4.x/1.4.3.md diff --git a/docs/changelogs/1.5.0.md b/docs/changelogs/1.5.x/1.5.0.md similarity index 100% rename from docs/changelogs/1.5.0.md rename to docs/changelogs/1.5.x/1.5.0.md diff --git a/docs/changelogs/1.5.1.md b/docs/changelogs/1.5.x/1.5.1.md similarity index 100% rename from docs/changelogs/1.5.1.md rename to docs/changelogs/1.5.x/1.5.1.md diff --git a/docs/changelogs/1.5.2.md b/docs/changelogs/1.5.x/1.5.2.md similarity index 100% rename from docs/changelogs/1.5.2.md rename to docs/changelogs/1.5.x/1.5.2.md diff --git a/docs/changelogs/1.5.3.md b/docs/changelogs/1.5.x/1.5.3.md similarity index 100% rename from docs/changelogs/1.5.3.md rename to docs/changelogs/1.5.x/1.5.3.md diff --git a/docs/changelogs/1.6.0.md b/docs/changelogs/1.6.x/1.6.0.md similarity index 100% rename from docs/changelogs/1.6.0.md rename to docs/changelogs/1.6.x/1.6.0.md diff --git a/docs/changelogs/1.6.1.md b/docs/changelogs/1.6.x/1.6.1.md similarity index 100% rename from docs/changelogs/1.6.1.md rename to docs/changelogs/1.6.x/1.6.1.md diff --git a/docs/changelogs/1.6.2.md b/docs/changelogs/1.6.x/1.6.2.md similarity index 100% rename from docs/changelogs/1.6.2.md rename to docs/changelogs/1.6.x/1.6.2.md diff --git a/docs/changelogs/1.7.0.md b/docs/changelogs/1.7.x/1.7.0.md similarity index 100% rename from docs/changelogs/1.7.0.md rename to docs/changelogs/1.7.x/1.7.0.md diff --git a/docs/changelogs/1.7.1.md b/docs/changelogs/1.7.x/1.7.1.md similarity index 100% rename from docs/changelogs/1.7.1.md rename to docs/changelogs/1.7.x/1.7.1.md diff --git a/docs/changelogs/1.7.2.md b/docs/changelogs/1.7.x/1.7.2.md similarity index 100% rename from docs/changelogs/1.7.2.md rename to docs/changelogs/1.7.x/1.7.2.md diff --git a/docs/changelogs/1.7.3.md b/docs/changelogs/1.7.x/1.7.3.md similarity index 100% rename from docs/changelogs/1.7.3.md rename to docs/changelogs/1.7.x/1.7.3.md diff --git a/docs/changelogs/1.7.4.md b/docs/changelogs/1.7.x/1.7.4.md similarity index 100% rename from docs/changelogs/1.7.4.md rename to docs/changelogs/1.7.x/1.7.4.md diff --git a/docs/changelogs/1.8.0.md b/docs/changelogs/1.8.x/1.8.0.md similarity index 100% rename from docs/changelogs/1.8.0.md rename to docs/changelogs/1.8.x/1.8.0.md diff --git a/docs/changelogs/1.8.1.md b/docs/changelogs/1.8.x/1.8.1.md similarity index 100% rename from docs/changelogs/1.8.1.md rename to docs/changelogs/1.8.x/1.8.1.md diff --git a/docs/changelogs/1.8.2.md b/docs/changelogs/1.8.x/1.8.2.md similarity index 100% rename from docs/changelogs/1.8.2.md rename to docs/changelogs/1.8.x/1.8.2.md diff --git a/docs/changelogs/1.8.x/1.8.3.md b/docs/changelogs/1.8.x/1.8.3.md new file mode 100644 index 0000000000..8449f56383 --- /dev/null +++ b/docs/changelogs/1.8.x/1.8.3.md @@ -0,0 +1,132 @@ +# Version 1.8.3 + +```md +## How to update +- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`. +- Once you have your remote set up, run the command `git pull RHH expansion/1.8.3`. +``` + +## 💥 *Softlock/Crash fixes* 💥 +* Fixed AI bug that caused an infinite loop when player mon has only status moves by @Pawkkie and @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4403 +* Temporarely disabled `AI_FLAG_SMART_MON_CHOICES` flag in double battles to prevent a softlock by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4405 +* Fixed debug option "Fill PC Boxes Fast" softlocking the game by @mrgriffin in https://github.com/rh-hideout/pokeemerald-expansion/pull/4428 +* Fixed infinite loop caused by Leftovers with `AI_FLAG_SMART_MON_CHOICES` by @Pokabbie and @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4453 + +## 🧬 General 🧬 +### Changed +* Updated outdated macOS instructions in `INSTALL.md` by @jschoeny in https://github.com/rh-hideout/pokeemerald-expansion/pull/4407 +* Made filepath links in `README.md` relative by @lolbinarycat in https://github.com/rh-hideout/pokeemerald-expansion/pull/4509 +### Fixed +* Fixed abilities not being properly inherited via breeding for species/abilities with IDs over 255 by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4411 +* Fixed Hard Level Caps issues by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4420 + * Fixed Pokémon being able to surpass cap if they gained enough experience at once. + * Fixed Exp. Candies ignoring hard caps. + * Fixed Pokémon gaining 1 experience if they are at the level cap. +* Fixed evolution tracker issues by @cawtds in https://github.com/rh-hideout/pokeemerald-expansion/pull/4503 + * `EVO_LEVEL_MOVE_TWENTY_TIMES` no longer increases with every move. + * `EVO_LEVEL_RECOIL_DAMAGE_MALE/FEMALE` is no longer updated twice than intended. + +## ✨ Feature Branches ✨ +### ***TheXaman's HGSS Pokédex Plus***: +#### Fixed +* Fixed Pokémon data page not properly handling `u16` Exp. Yields by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4432 + * Cleanup by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4445 + +## 🐉 Pokémon 🐉 +### Changed +* Further Gen 9 Pokémon icon improvements by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4413 + * Original sprites by [ezerart on DeviantArt](https://www.deviantart.com/ezerart/art/Pokemon-Gen-9-Icon-sprites-3DS-Style-944211258). Palette assignments and 2nd frames by kittenchilly. + * Cyclizar, Dipplin, Farigiraf, Glimmet, Glimmora, Greavard, Iron Moth, Revavroom, Tadbulb, Paldean Tauros (all three of them), Tinkaton and Paldean Wooper. +* Further Gen 9 Pokémon front/back sprite improvements by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4414 + * Source: [PokéCommunity](https://www.pokecommunity.com/threads/ds-style-gen-vii-and-beyond-pok%C3%A9mon-sprite-repository-in-64x64.368703/post-10814369) + * Dolliv, Arboliva, Charcadet, Mabosstiff, Tinkatink, Tinkatuff, Tinkaton and Chien-Pao. +### Fixed +* Fixed Lycanroc Dusk and Midnight forms using Midday's backsprite by @Eemeliri in https://github.com/rh-hideout/pokeemerald-expansion/pull/4430 +* Fixed Tatsugiri Droopy back sprite palette by @cafei-uh in https://github.com/rh-hideout/pokeemerald-expansion/pull/4455 + +## ⚔️ Battle General ⚔️ ## +### Changed +* Turned `B_RESTORE_HELD_BATTLE_ITEMS` into a generational config by @LOuroboros in https://github.com/rh-hideout/pokeemerald-expansion/pull/4402 +### Fixed +* Fixed battle Partner trainer class and potential OOB-related issues by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4422 + +## 🤹 Moves 🤹 +### Fixed +* Fixed Quash not properly working when `B_RECALC_TURN_AFTER_ACTIONS` is set to `GEN_8` or greater by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4419 +* Fixed Will-O-Wisp's name capitalization in gMovesInfo by @LOuroboros in https://github.com/rh-hideout/pokeemerald-expansion/pull/4425 +* Fixed Thunder Cage not printing the right battle message by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4426 +* Fixed Diamond Storm missing its effect by @PhallenTree in https://github.com/rh-hideout/pokeemerald-expansion/pull/4489 +* Fixed Mortal Spin's description by @PhallenTree in https://github.com/rh-hideout/pokeemerald-expansion/pull/4489 +* Fixed Assist being able to call `MOVE_NONE` by @PhallenTree in https://github.com/rh-hideout/pokeemerald-expansion/pull/4491 + +## 🎭 Abilities 🎭 +### Changed +* Changed the Embody Aspect defines to use the full form name, to be in line with the species define by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4439 + * Eg. `ABILITY_EMBODY_ASPECT_TEAL` -> `ABILITY_EMBODY_ASPECT_TEAL_MASK`. +### Fixed +* Fixed Intimidate/Supersweet Syrup playing their animation and not printing the right message for battlers at -6 stage Attack/Evasion by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4406 +* Fixed ability pop ups not respecting `abilityPopupOverwrite` in tests by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4423 +* Fixed Dancer copying multi-target moves by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4437 +* Fixed Hospitality triggering on a fainted mon by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4450 +* Fixed Embody Aspect (Teal Mask) boosting Sp. Attack instead of Speed by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4439 +* Fixed lingering long ability popup names by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4456 +* Fixed Fur Coat not being skipped by Mold Breaker abilities by @Bassoonian in https://github.com/rh-hideout/pokeemerald-expansion/pull/4459 +* Fixed Color change not being triggered by Future Sight or Doom Desire by @AlexOn1ine and @hedara90 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4472 +* Fixes Magic Bounce only working for battlers in certain positions by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4464 +* Fixed Costar, Zero to Hero, Supreme Overlord and Ruin abilities' switch-in battle messages showing sometimes incorrectly by @PhallenTree in https://github.com/rh-hideout/pokeemerald-expansion/pull/4500 + * Cleanup by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4511 + +## 🧶 Items 🧶 +### Fixed +* Fixed typo in Rotom Catalogue description by @mrgriffin in https://github.com/rh-hideout/pokeemerald-expansion/pull/4433 +* Eject item fixes (Eject Button/Pack): + * Fixed regression from 1.8.2 that caused Eject Pack to not trigger upon self-inflicted stat decreases by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4463 + * Fixed Eject Items causing wrong Pokémon taking damage by entry hazards by @PhallenTree in https://github.com/rh-hideout/pokeemerald-expansion/pull/4465 + * Cleanup by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4497 +* Fixed Flute Items being consumed in battle by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4496 +* Fixed Red Card activating if the holder was switched in in the same turn (eg. via Endure) by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4482 + +## 🤖 Battle AI 🤖 +### Changed +* `AI_FLAG_SMART_SWITCHING` flag now automatically sets `AI_FLAG_SMART_MON_CHOICES` as well by @Sneed69 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4405 + * Cleanup by @AlexOn1ine in https://github.com/rh-hideout/pokeemerald-expansion/pull/4409 +* Corrected `IsDamageMoveUsable`'s name to `IsDamageMoveUnusable` by @WillKolada in https://github.com/rh-hideout/pokeemerald-expansion/pull/4476 +* Fixed AI not knowing that Steam Roller fails when there's no terrain by @WillKolada in https://github.com/rh-hideout/pokeemerald-expansion/pull/4476 + * Cleanup by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4498 + +## 🧪 Test Runner 🧪 +### Added +* Added missing Color change tests by @hedara90 in https://github.com/rh-hideout/pokeemerald-expansion/pull/4472 +### Changed +### Fixed +* Fixed AI test error messages by @mrgriffin in https://github.com/rh-hideout/pokeemerald-expansion/pull/4404 + * The error messages for `EXPECT_MOVE` and `EXPECT_SWITCH` were backwards, saying, e.g. `Expected MOVE, got SWITCH` when it should say `Expected SWITCH, got MOVE`. +* Fixed typos in Embody Aspect tests by @kittenchilly in https://github.com/rh-hideout/pokeemerald-expansion/pull/4439 +* Fixed Battle Test organization by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/4504 + * Fixed Cud Chew's file being in the move effect folder. + * Fixed Cud Chew's file name and test names (Cud Chuw). + * Fixed Gastro Acid and Role Play's files being in the ability folder. + * Moved Recoil file to move flags folder. + * Renamed White Herb's file to `restore_stats.c`. + * Renamed Techno Blast's file to `change_type_on_item.c`. + * `semi_invulnerable_moves.c` to `semi_invulnerable.c`. + * `two_turn_moves.c` to `two_turns_attack.c`. + * Combined Burn Up/Double Shock to a single file `fail_if_not_arg_type.c` + * Added Spit Up/Swallow files that point Stockpile's file. + * Moved secondary effect files to their own folder. + * Combinations of secondary effects moved to their own folder + * Split `hit_set_entry_hazards.c` to separate files for Spikes/Stealth Rock. + * Grouped Hex/Venoshock to the same file `double_power_on_arg_status.c` + +## New Contributors +* @jschoeny made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4407 +* @Eemeliri made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4430 +* @cafei-uh made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4455 +* @PhallenTree made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4465 +* @WillKolada made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4476 +* @cawtds made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4503 +* @lolbinarycat made their first contribution in https://github.com/rh-hideout/pokeemerald-expansion/pull/4509 + +**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.8.2...expansion/1.8.3 + + diff --git a/docs/changelogs/template.md b/docs/changelogs/template.md index 6d1ce784a2..b70a44ce54 100644 --- a/docs/changelogs/template.md +++ b/docs/changelogs/template.md @@ -7,7 +7,7 @@ ``` ## 🌋 *IMPORTANT CHANGES* 🌋 -* We deleted the whole repo LOL by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/3367 +* N/A ## 💥 *Softlock/Crash fixes* 💥 * N/A @@ -119,7 +119,7 @@ ## New Contributors -* Tony +* N/A **Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.Y.Z...expansion/1.Y.Z diff --git a/gflib/text.c b/gflib/text.c index cc6a6e90f2..c4ed5f4dbe 100644 --- a/gflib/text.c +++ b/gflib/text.c @@ -23,17 +23,26 @@ static u16 FontFunc_ShortCopy2(struct TextPrinter *); static u16 FontFunc_ShortCopy3(struct TextPrinter *); static u16 FontFunc_Narrow(struct TextPrinter *); static u16 FontFunc_SmallNarrow(struct TextPrinter *); +static u16 FontFunc_Narrower(struct TextPrinter *); +static u16 FontFunc_SmallNarrower(struct TextPrinter *); +static u16 FontFunc_ShortNarrow(struct TextPrinter *); static void DecompressGlyph_Small(u16, bool32); static void DecompressGlyph_Normal(u16, bool32); static void DecompressGlyph_Short(u16, bool32); static void DecompressGlyph_Narrow(u16, bool32); static void DecompressGlyph_SmallNarrow(u16, bool32); static void DecompressGlyph_Bold(u16); +static void DecompressGlyph_Narrower(u16, bool32); +static void DecompressGlyph_SmallNarrower(u16, bool32); +static void DecompressGlyph_ShortNarrow(u16, bool32); static u32 GetGlyphWidth_Small(u16, bool32); static u32 GetGlyphWidth_Normal(u16, bool32); static u32 GetGlyphWidth_Short(u16, bool32); static u32 GetGlyphWidth_Narrow(u16, bool32); static u32 GetGlyphWidth_SmallNarrow(u16, bool32); +static u32 GetGlyphWidth_Narrower(u16, bool32); +static u32 GetGlyphWidth_SmallNarrower(u16, bool32); +static u32 GetGlyphWidth_ShortNarrow(u16, bool32); static EWRAM_DATA struct TextPrinter sTempTextPrinter = {0}; static EWRAM_DATA struct TextPrinter sTextPrinters[WINDOWS_MAX] = {0}; @@ -81,15 +90,18 @@ static const u8 sWindowVerticalScrollSpeeds[] = { static const struct GlyphWidthFunc sGlyphWidthFuncs[] = { - { FONT_SMALL, GetGlyphWidth_Small }, - { FONT_NORMAL, GetGlyphWidth_Normal }, - { FONT_SHORT, GetGlyphWidth_Short }, - { FONT_SHORT_COPY_1, GetGlyphWidth_Short }, - { FONT_SHORT_COPY_2, GetGlyphWidth_Short }, - { FONT_SHORT_COPY_3, GetGlyphWidth_Short }, - { FONT_BRAILLE, GetGlyphWidth_Braille }, - { FONT_NARROW, GetGlyphWidth_Narrow }, - { FONT_SMALL_NARROW, GetGlyphWidth_SmallNarrow } + { FONT_SMALL, GetGlyphWidth_Small }, + { FONT_NORMAL, GetGlyphWidth_Normal }, + { FONT_SHORT, GetGlyphWidth_Short }, + { FONT_SHORT_COPY_1, GetGlyphWidth_Short }, + { FONT_SHORT_COPY_2, GetGlyphWidth_Short }, + { FONT_SHORT_COPY_3, GetGlyphWidth_Short }, + { FONT_BRAILLE, GetGlyphWidth_Braille }, + { FONT_NARROW, GetGlyphWidth_Narrow }, + { FONT_SMALL_NARROW, GetGlyphWidth_SmallNarrow }, + { FONT_NARROWER, GetGlyphWidth_Narrower }, + { FONT_SMALL_NARROWER, GetGlyphWidth_SmallNarrower }, + { FONT_SHORT_NARROW, GetGlyphWidth_ShortNarrow }, }; struct @@ -217,21 +229,54 @@ static const struct FontInfo sFontInfos[] = .fgColor = 1, .bgColor = 2, .shadowColor = 15, - } + }, + [FONT_NARROWER] = { + .fontFunction = FontFunc_Narrower, + .maxLetterWidth = 5, + .maxLetterHeight = 16, + .letterSpacing = 0, + .lineSpacing = 0, + .fgColor = 2, + .bgColor = 1, + .shadowColor = 3, + }, + [FONT_SMALL_NARROWER] = { + .fontFunction = FontFunc_SmallNarrower, + .maxLetterWidth = 5, + .maxLetterHeight = 8, + .letterSpacing = 0, + .lineSpacing = 0, + .fgColor = 2, + .bgColor = 1, + .shadowColor = 3, + }, + [FONT_SHORT_NARROW] = { + .fontFunction = FontFunc_ShortNarrow, + .maxLetterWidth = 5, + .maxLetterHeight = 14, + .letterSpacing = 0, + .lineSpacing = 0, + .fgColor = 2, + .bgColor = 1, + .shadowColor = 3, + }, }; static const u8 sMenuCursorDimensions[][2] = { - [FONT_SMALL] = { 8, 12 }, - [FONT_NORMAL] = { 8, 15 }, - [FONT_SHORT] = { 8, 14 }, - [FONT_SHORT_COPY_1] = { 8, 14 }, - [FONT_SHORT_COPY_2] = { 8, 14 }, - [FONT_SHORT_COPY_3] = { 8, 14 }, - [FONT_BRAILLE] = { 8, 16 }, - [FONT_NARROW] = { 8, 15 }, - [FONT_SMALL_NARROW] = { 8, 8 }, - [FONT_BOLD] = {} + [FONT_SMALL] = { 8, 12 }, + [FONT_NORMAL] = { 8, 15 }, + [FONT_SHORT] = { 8, 14 }, + [FONT_SHORT_COPY_1] = { 8, 14 }, + [FONT_SHORT_COPY_2] = { 8, 14 }, + [FONT_SHORT_COPY_3] = { 8, 14 }, + [FONT_BRAILLE] = { 8, 16 }, + [FONT_NARROW] = { 8, 15 }, + [FONT_SMALL_NARROW] = { 8, 8 }, + [FONT_BOLD] = {}, + [FONT_NARROWER] = { 8, 15 }, + [FONT_SMALL_NARROWER] = { 8, 8 }, + [FONT_SHORT_NARROW] = { 8, 14 }, }; static const u16 sFontBoldJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/bold.hwjpnfont"); @@ -813,6 +858,42 @@ static u16 FontFunc_SmallNarrow(struct TextPrinter *textPrinter) return RenderText(textPrinter); } +static u16 FontFunc_Narrower(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasFontIdBeenSet == FALSE) + { + subStruct->fontId = FONT_NARROWER; + subStruct->hasFontIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +static u16 FontFunc_SmallNarrower(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasFontIdBeenSet == FALSE) + { + subStruct->fontId = FONT_SMALL_NARROWER; + subStruct->hasFontIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + +static u16 FontFunc_ShortNarrow(struct TextPrinter *textPrinter) +{ + struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); + + if (subStruct->hasFontIdBeenSet == FALSE) + { + subStruct->fontId = FONT_SHORT_NARROW; + subStruct->hasFontIdBeenSet = TRUE; + } + return RenderText(textPrinter); +} + void TextPrinterInitDownArrowCounters(struct TextPrinter *textPrinter) { struct TextPrinterSubStruct *subStruct = (struct TextPrinterSubStruct *)(&textPrinter->subStructFields); @@ -1250,6 +1331,15 @@ static u16 RenderText(struct TextPrinter *textPrinter) case FONT_SMALL_NARROW: DecompressGlyph_SmallNarrow(currChar, textPrinter->japanese); break; + case FONT_NARROWER: + DecompressGlyph_Narrower(currChar, textPrinter->japanese); + break; + case FONT_SMALL_NARROWER: + DecompressGlyph_SmallNarrower(currChar, textPrinter->japanese); + break; + case FONT_SHORT_NARROW: + DecompressGlyph_ShortNarrow(currChar, textPrinter->japanese); + break; case FONT_BRAILLE: break; } @@ -2012,3 +2102,204 @@ static void DecompressGlyph_Bold(u16 glyphId) gCurGlyph.width = 8; gCurGlyph.height = 12; } + +static void DecompressGlyph_Narrower(u16 glyphId, bool32 isJapanese) +{ + const u16 *glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFontNormalJapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 15; + } + else + { + glyphs = gFontNarrowerLatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFontNarrowerLatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 15; + } +} + +static u32 GetGlyphWidth_Narrower(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFontNarrowerLatinGlyphWidths[glyphId]; +} + +static void DecompressGlyph_SmallNarrower(u16 glyphId, bool32 isJapanese) +{ + const u16 *glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFontSmallJapaneseGlyphs + (0x100 * (glyphId >> 0x4)) + (0x8 * (glyphId % 0x10)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); + gCurGlyph.width = 8; + gCurGlyph.height = 15; + } + else + { + glyphs = gFontSmallNarrowerLatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFontSmallNarrowerLatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 15; + } +} + +static u32 GetGlyphWidth_SmallNarrower(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return 8; + else + return gFontSmallNarrowerLatinGlyphWidths[glyphId]; +} + +static void DecompressGlyph_ShortNarrow(u16 glyphId, bool32 isJapanese) +{ + const u16 *glyphs; + + if (isJapanese == TRUE) + { + glyphs = gFontShortJapaneseGlyphs + (0x100 * (glyphId >> 0x3)) + (0x10 * (glyphId & 0x7)); + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x80, gCurGlyph.gfxBufferBottom); // gCurGlyph + 0x20 + DecompressGlyphTile(glyphs + 0x88, gCurGlyph.gfxBufferBottom + 8); // gCurGlyph + 0x60 + gCurGlyph.width = gFontShortJapaneseGlyphWidths[glyphId]; + gCurGlyph.height = 14; + } + else + { + glyphs = gFontShortNarrowLatinGlyphs + (0x20 * glyphId); + gCurGlyph.width = gFontShortNarrowLatinGlyphWidths[glyphId]; + + if (gCurGlyph.width <= 8) + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + } + else + { + DecompressGlyphTile(glyphs, gCurGlyph.gfxBufferTop); + DecompressGlyphTile(glyphs + 0x8, gCurGlyph.gfxBufferTop + 8); + DecompressGlyphTile(glyphs + 0x10, gCurGlyph.gfxBufferBottom); + DecompressGlyphTile(glyphs + 0x18, gCurGlyph.gfxBufferBottom + 8); + } + + gCurGlyph.height = 14; + } +} + +static u32 GetGlyphWidth_ShortNarrow(u16 glyphId, bool32 isJapanese) +{ + if (isJapanese == TRUE) + return gFontShortJapaneseGlyphWidths[glyphId]; + else + return gFontShortNarrowLatinGlyphWidths[glyphId]; +} + +static const s8 sNarrowerFontIds[] = +{ + [FONT_SMALL] = FONT_SMALL_NARROW, + [FONT_NORMAL] = FONT_NARROW, + [FONT_SHORT] = FONT_SHORT_NARROW, + [FONT_SHORT_COPY_1] = FONT_SHORT_NARROW, + [FONT_SHORT_COPY_2] = FONT_SHORT_NARROW, + [FONT_SHORT_COPY_3] = FONT_SHORT_NARROW, + [FONT_BRAILLE] = -1, + [FONT_NARROW] = FONT_NARROWER, + [FONT_SMALL_NARROW] = FONT_SMALL_NARROWER, + [FONT_BOLD] = -1, + [FONT_NARROWER] = -1, + [FONT_SMALL_NARROWER] = -1, + [FONT_SHORT_NARROW] = -1, +}; + +// If the narrowest font ID doesn't fit the text, we still return that +// ID because clipping is better than crashing. +u32 GetFontIdToFit(const u8 *string, u32 fontId, u32 letterSpacing, u32 widthPx) +{ + for (;;) + { + s32 narrowerFontId = sNarrowerFontIds[fontId]; + if (narrowerFontId == -1) + return fontId; + if (GetStringWidth(fontId, string, letterSpacing) <= widthPx) + return fontId; + fontId = narrowerFontId; + } +} + +u8 *PrependFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width) +{ + + u32 fitFontId = GetFontIdToFit(start, fontId, 0, width); + if (fitFontId != fontId) + { + memmove(&start[3], &start[0], end - start); + start[0] = EXT_CTRL_CODE_BEGIN; + start[1] = EXT_CTRL_CODE_FONT; + start[2] = fitFontId; + end[3] = EOS; + return end + 3; + } + else + { + return end; + } +} + +u8 *WrapFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width) +{ + + u32 fitFontId = GetFontIdToFit(start, fontId, 0, width); + if (fitFontId != fontId) + { + memmove(&start[3], &start[0], end - start); + start[0] = EXT_CTRL_CODE_BEGIN; + start[1] = EXT_CTRL_CODE_FONT; + start[2] = fitFontId; + end[3] = EXT_CTRL_CODE_BEGIN; + end[4] = EXT_CTRL_CODE_FONT; + end[5] = fontId; + end[6] = EOS; + return end + 6; + } + else + { + return end; + } +} diff --git a/gflib/text.h b/gflib/text.h index 7e1d7bfb11..0b12edc363 100644 --- a/gflib/text.h +++ b/gflib/text.h @@ -26,6 +26,9 @@ enum { FONT_NARROW, FONT_SMALL_NARROW, // Very similar to FONT_SMALL, some glyphs are narrower FONT_BOLD, // JP glyph set only + FONT_NARROWER, + FONT_SMALL_NARROWER, + FONT_SHORT_NARROW, }; // Return values for font functions @@ -190,4 +193,8 @@ u8 GetMenuCursorDimensionByFont(u8 fontId, u8 whichDimension); u16 FontFunc_Braille(struct TextPrinter *textPrinter); u32 GetGlyphWidth_Braille(u16 glyphId, bool32 isJapanese); +u32 GetFontIdToFit(const u8 *string, u32 widestFontId, u32 letterSpacing, u32 widthPx); +u8 *PrependFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width); +u8 *WrapFontIdToFit(u8 *start, u8 *end, u32 fontId, u32 width); + #endif // GUARD_TEXT_H diff --git a/gflib/window.c b/gflib/window.c index 61264000ea..5e77283945 100644 --- a/gflib/window.c +++ b/gflib/window.c @@ -712,3 +712,13 @@ static u32 GetNumActiveWindowsOnBg8Bit(u32 bgId) } return windowsNum; } + +u32 WindowWidthPx(u32 windowId) +{ + return gWindows[windowId].window.width * TILE_WIDTH; +} + +u32 WindowTemplateWidthPx(const struct WindowTemplate *template) +{ + return template->width * TILE_WIDTH; +} diff --git a/gflib/window.h b/gflib/window.h index 85e385cb9f..2fd0bddb20 100644 --- a/gflib/window.h +++ b/gflib/window.h @@ -73,6 +73,8 @@ void FillWindowPixelBuffer8Bit(u32 windowId, u8 fillValue); void FillWindowPixelRect8Bit(u32 windowId, u8 fillValue, u16 x, u16 y, u16 width, u16 height); void BlitBitmapRectToWindow4BitTo8Bit(u32 windowId, const u8 *pixels, u16 srcX, u16 srcY, u16 srcWidth, int srcHeight, u16 destX, u16 destY, u16 rectWidth, u16 rectHeight, u8 paletteNum); void CopyWindowToVram8Bit(u32 windowId, u8 mode); +u32 WindowWidthPx(u32 windowId); +u32 WindowTemplateWidthPx(const struct WindowTemplate *template); extern struct Window gWindows[]; extern void *gWindowBgTilemapBuffers[]; diff --git a/graphics/battle_interface/bug_indicator.png b/graphics/battle_interface/bug_indicator.png new file mode 100644 index 0000000000..7ab7dc6dfa Binary files /dev/null and b/graphics/battle_interface/bug_indicator.png differ diff --git a/graphics/battle_interface/dark_indicator.png b/graphics/battle_interface/dark_indicator.png new file mode 100644 index 0000000000..149d2155a3 Binary files /dev/null and b/graphics/battle_interface/dark_indicator.png differ diff --git a/graphics/battle_interface/dragon_indicator.png b/graphics/battle_interface/dragon_indicator.png new file mode 100644 index 0000000000..4c1d9e1f78 Binary files /dev/null and b/graphics/battle_interface/dragon_indicator.png differ diff --git a/graphics/battle_interface/electric_indicator.png b/graphics/battle_interface/electric_indicator.png new file mode 100644 index 0000000000..518907dc05 Binary files /dev/null and b/graphics/battle_interface/electric_indicator.png differ diff --git a/graphics/battle_interface/fairy_indicator.png b/graphics/battle_interface/fairy_indicator.png new file mode 100644 index 0000000000..a41736eeec Binary files /dev/null and b/graphics/battle_interface/fairy_indicator.png differ diff --git a/graphics/battle_interface/fighting_indicator.png b/graphics/battle_interface/fighting_indicator.png new file mode 100644 index 0000000000..6102ab6846 Binary files /dev/null and b/graphics/battle_interface/fighting_indicator.png differ diff --git a/graphics/battle_interface/fire_indicator.png b/graphics/battle_interface/fire_indicator.png new file mode 100644 index 0000000000..4d3e59d543 Binary files /dev/null and b/graphics/battle_interface/fire_indicator.png differ diff --git a/graphics/battle_interface/flying_indicator.png b/graphics/battle_interface/flying_indicator.png new file mode 100644 index 0000000000..767954b706 Binary files /dev/null and b/graphics/battle_interface/flying_indicator.png differ diff --git a/graphics/battle_interface/ghost_indicator.png b/graphics/battle_interface/ghost_indicator.png new file mode 100644 index 0000000000..c1aeec6059 Binary files /dev/null and b/graphics/battle_interface/ghost_indicator.png differ diff --git a/graphics/battle_interface/grass_indicator.png b/graphics/battle_interface/grass_indicator.png new file mode 100644 index 0000000000..81fa2589d0 Binary files /dev/null and b/graphics/battle_interface/grass_indicator.png differ diff --git a/graphics/battle_interface/ground_indicator.png b/graphics/battle_interface/ground_indicator.png new file mode 100644 index 0000000000..7a306510fe Binary files /dev/null and b/graphics/battle_interface/ground_indicator.png differ diff --git a/graphics/battle_interface/ice_indicator.png b/graphics/battle_interface/ice_indicator.png new file mode 100644 index 0000000000..a40d96f018 Binary files /dev/null and b/graphics/battle_interface/ice_indicator.png differ diff --git a/graphics/battle_interface/normal_indicator.png b/graphics/battle_interface/normal_indicator.png new file mode 100644 index 0000000000..029827e296 Binary files /dev/null and b/graphics/battle_interface/normal_indicator.png differ diff --git a/graphics/battle_interface/poison_indicator.png b/graphics/battle_interface/poison_indicator.png new file mode 100644 index 0000000000..c2646d0a71 Binary files /dev/null and b/graphics/battle_interface/poison_indicator.png differ diff --git a/graphics/battle_interface/psychic_indicator.png b/graphics/battle_interface/psychic_indicator.png new file mode 100644 index 0000000000..f70352d2ee Binary files /dev/null and b/graphics/battle_interface/psychic_indicator.png differ diff --git a/graphics/battle_interface/rock_indicator.png b/graphics/battle_interface/rock_indicator.png new file mode 100644 index 0000000000..0329ec678c Binary files /dev/null and b/graphics/battle_interface/rock_indicator.png differ diff --git a/graphics/battle_interface/steel_indicator.png b/graphics/battle_interface/steel_indicator.png new file mode 100644 index 0000000000..e84d9fa1b0 Binary files /dev/null and b/graphics/battle_interface/steel_indicator.png differ diff --git a/graphics/battle_interface/stellar_indicator.png b/graphics/battle_interface/stellar_indicator.png new file mode 100644 index 0000000000..7551e2b230 Binary files /dev/null and b/graphics/battle_interface/stellar_indicator.png differ diff --git a/graphics/battle_interface/tera_indicator.pal b/graphics/battle_interface/tera_indicator.pal new file mode 100644 index 0000000000..d4ab140472 --- /dev/null +++ b/graphics/battle_interface/tera_indicator.pal @@ -0,0 +1,19 @@ +JASC-PAL +0100 +16 +0 0 0 +98 83 124 +207 63 109 +83 105 175 +80 144 216 +216 208 179 +254 115 121 +148 155 163 +99 188 91 +147 192 47 +255 156 85 +199 182 140 +113 206 198 +117 206 192 +245 210 55 +255 255 255 diff --git a/graphics/battle_interface/tera_trigger.png b/graphics/battle_interface/tera_trigger.png new file mode 100644 index 0000000000..5498ea8806 Binary files /dev/null and b/graphics/battle_interface/tera_trigger.png differ diff --git a/graphics/battle_interface/water_indicator.png b/graphics/battle_interface/water_indicator.png new file mode 100644 index 0000000000..bdeb401f4a Binary files /dev/null and b/graphics/battle_interface/water_indicator.png differ diff --git a/graphics/fonts/latin_narrower.png b/graphics/fonts/latin_narrower.png new file mode 100644 index 0000000000..22847ef099 Binary files /dev/null and b/graphics/fonts/latin_narrower.png differ diff --git a/graphics/fonts/latin_short_narrow.png b/graphics/fonts/latin_short_narrow.png new file mode 100644 index 0000000000..cf48712719 Binary files /dev/null and b/graphics/fonts/latin_short_narrow.png differ diff --git a/graphics/fonts/latin_small_narrower.png b/graphics/fonts/latin_small_narrower.png new file mode 100644 index 0000000000..a183bed7cc Binary files /dev/null and b/graphics/fonts/latin_small_narrower.png differ diff --git a/graphics/pokemon/tatsugiri/droopy/back.png b/graphics/pokemon/tatsugiri/droopy/back.png index 6d998537f2..381ae4278e 100644 Binary files a/graphics/pokemon/tatsugiri/droopy/back.png and b/graphics/pokemon/tatsugiri/droopy/back.png differ diff --git a/graphics/types/stellar.png b/graphics/types/stellar.png new file mode 100644 index 0000000000..ee18b997ea Binary files /dev/null and b/graphics/types/stellar.png differ diff --git a/graphics_file_rules.mk b/graphics_file_rules.mk index 6a2728aff4..9f5d9d6c79 100644 --- a/graphics_file_rules.mk +++ b/graphics_file_rules.mk @@ -22,7 +22,7 @@ STARTERGFXDIR := graphics/starter_choose NAMINGGFXDIR := graphics/naming_screen SPINDAGFXDIR := graphics/pokemon/spinda/spots -types := normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy +types := normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy stellar contest_types := cool beauty cute smart tough ### Tilesets ### @@ -238,6 +238,15 @@ $(FONTGFXDIR)/narrow.latfont: $(FONTGFXDIR)/latin_narrow.png $(FONTGFXDIR)/small_narrow.latfont: $(FONTGFXDIR)/latin_small_narrow.png $(GFX) $< $@ +$(FONTGFXDIR)/narrower.latfont: $(FONTGFXDIR)/latin_narrower.png + $(GFX) $< $@ + +$(FONTGFXDIR)/small_narrower.latfont: $(FONTGFXDIR)/latin_small_narrower.png + $(GFX) $< $@ + +$(FONTGFXDIR)/short_narrow.latfont: $(FONTGFXDIR)/latin_short_narrow.png + $(GFX) $< $@ + $(FONTGFXDIR)/small.hwjpnfont: $(FONTGFXDIR)/japanese_small.png $(GFX) $< $@ diff --git a/include/battle.h b/include/battle.h index 1274ffcbfc..b5ecf08335 100644 --- a/include/battle.h +++ b/include/battle.h @@ -15,6 +15,7 @@ #include "pokeball.h" #include "battle_debug.h" #include "battle_dynamax.h" +#include "battle_terastal.h" #include "random.h" // for rng_value_t // Helper for accessing command arguments and advancing gBattlescriptCurrInstr. @@ -177,7 +178,6 @@ struct ProtectStruct u32 flinchImmobility:1; u32 notFirstStrike:1; u32 palaceUnableToUseMove:1; - u32 usesBouncedMove:1; u32 usedHealBlockedMove:1; u32 usedGravityPreventedMove:1; u32 powderSelfDmg:1; @@ -363,6 +363,8 @@ struct AiLogicData bool8 weatherHasEffect; // The same as WEATHER_HAS_EFFECT. Stored here, so it's called only once. u8 mostSuitableMonId[MAX_BATTLERS_COUNT]; // Stores result of GetMostSuitableMonToSwitchInto, which decides which generic mon the AI would switch into if they decide to switch. This can be overruled by specific mons found in ShouldSwitch; the final resulting mon is stored in AI_monToSwitchIntoId. struct SwitchinCandidate switchinCandidate; // Struct used for deciding which mon to switch to in battle_ai_switch_items.c + bool8 shouldTerastal[MAX_BATTLERS_COUNT]; + bool8 shouldDynamax[MAX_BATTLERS_COUNT]; }; struct AI_ThinkingStruct @@ -611,6 +613,17 @@ struct DynamaxData u16 levelUpHP; }; +struct TeraData +{ + bool8 toTera; // flags using gBitTable + bool8 isTerastallized[NUM_BATTLE_SIDES]; // stored as a bitfield for each side's party members + bool8 alreadyTerastallized[MAX_BATTLERS_COUNT]; + bool8 playerSelect; + u32 stellarBoostFlags[NUM_BATTLE_SIDES]; // stored as a bitfield of flags for all types for each side + u8 triggerSpriteId; + u8 indicatorSpriteId[MAX_BATTLERS_COUNT]; +}; + struct LostItem { u16 originalItem:15; @@ -733,6 +746,7 @@ struct BattleStruct struct UltraBurstData burst; struct ZMoveData zmove; struct DynamaxData dynamax; + struct TeraData tera; const u8 *trainerSlideMsg; bool8 trainerSlideLowHpMsgDone; u8 introState; @@ -756,9 +770,10 @@ struct BattleStruct u8 quickClawBattlerId; struct LostItem itemLost[PARTY_SIZE]; // Player's team that had items consumed or stolen (two bytes per party member) u8 forcedSwitch:4; // For each battler + u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects u8 blunderPolicy:1; // should blunder policy activate u8 swapDamageCategory:1; // Photon Geyser, Shell Side Arm, Light That Burns the Sky - u8 additionalEffectsCounter:4; // A counter for the additionalEffects applied by the current move in Cmd_setadditionaleffects + u8 bouncedMoveIsUsed:1; u8 ballSpriteIds[2]; // item gfx, window gfx u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. @@ -787,6 +802,7 @@ struct BattleStruct u8 trainerSlideDynamaxMsgDone:1; u8 pledgeMove:1; u8 isSkyBattle:1; + u8 poisonPuppeteerConfusion:1; u32 aiDelayTimer; // Counts number of frames AI takes to choose an action. u32 aiDelayFrames; // Number of frames it took to choose an action. u8 timesGotHit[NUM_BATTLE_SIDES][PARTY_SIZE]; @@ -800,6 +816,7 @@ struct BattleStruct u8 quickClawRandom[MAX_BATTLERS_COUNT]; u8 quickDrawRandom[MAX_BATTLERS_COUNT]; u8 boosterEnergyActivates; + u8 distortedTypeMatchups; }; // The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider, @@ -829,9 +846,9 @@ STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLER #define TARGET_TURN_DAMAGED ((gSpecialStatuses[gBattlerTarget].physicalDmg != 0 || gSpecialStatuses[gBattlerTarget].specialDmg != 0) || (gBattleStruct->enduredDamage & gBitTable[gBattlerTarget])) #define BATTLER_TURN_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0) || (gBattleStruct->enduredDamage & gBitTable[battler])) -#define IS_BATTLER_OF_TYPE(battlerId, type)((GetBattlerType(battlerId, 0) == type || GetBattlerType(battlerId, 1) == type || (GetBattlerType(battlerId, 2) != TYPE_MYSTERY && GetBattlerType(battlerId, 2) == type))) - -#define IS_BATTLER_TYPELESS(battlerId)(GetBattlerType(battlerId, 0) == TYPE_MYSTERY && GetBattlerType(battlerId, 1) == TYPE_MYSTERY && GetBattlerType(battlerId, 2) == TYPE_MYSTERY) +#define IS_BATTLER_OF_TYPE(battlerId, type)((GetBattlerType(battlerId, 0, FALSE) == type || GetBattlerType(battlerId, 1, FALSE) == type || (GetBattlerType(battlerId, 2, FALSE) != TYPE_MYSTERY && GetBattlerType(battlerId, 2, FALSE) == type))) +#define IS_BATTLER_OF_BASE_TYPE(battlerId, type)((GetBattlerType(battlerId, 0, TRUE) == type || GetBattlerType(battlerId, 1, TRUE) == type || (GetBattlerType(battlerId, 2, TRUE) != TYPE_MYSTERY && GetBattlerType(battlerId, 2, TRUE) == type))) +#define IS_BATTLER_TYPELESS(battlerId)(GetBattlerType(battlerId, 0, FALSE) == TYPE_MYSTERY && GetBattlerType(battlerId, 1, FALSE) == TYPE_MYSTERY && GetBattlerType(battlerId, 2, FALSE) == TYPE_MYSTERY) #define SET_BATTLER_TYPE(battlerId, type) \ { \ diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 99c0ab9e30..5e157a2766 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -101,6 +101,7 @@ enum { #define RET_MEGA_EVOLUTION (1 << 7) #define RET_ULTRA_BURST (1 << 6) #define RET_DYNAMAX (1 << 5) +#define RET_TERASTAL (1 << 4) struct UnusedControllerStruct { diff --git a/include/battle_gfx_sfx_util.h b/include/battle_gfx_sfx_util.h index 95c97cabaa..968f8d48dc 100644 --- a/include/battle_gfx_sfx_util.h +++ b/include/battle_gfx_sfx_util.h @@ -31,6 +31,7 @@ void BattleStopLowHpSound(void); u8 GetMonHPBarLevel(struct Pokemon *mon); void HandleBattleLowHpMusicChange(void); void SetBattlerSpriteAffineMode(u8 affineMode); +void CreateEnemyShadowSprite(u32 battler); void LoadAndCreateEnemyShadowSprites(void); void SpriteCB_SetInvisible(struct Sprite *sprite); void SetBattlerShadowSpriteCallback(u8 battler, u16 species); diff --git a/include/battle_interface.h b/include/battle_interface.h index b26205d810..f32017745f 100644 --- a/include/battle_interface.h +++ b/include/battle_interface.h @@ -57,12 +57,36 @@ enum #define TAG_DYNAMAX_TRIGGER_TILE 0xD77D #define TAG_DYNAMAX_INDICATOR_TILE 0xD77E +#define TAG_NORMAL_INDICATOR_TILE 0xD77F +#define TAG_FIGHTING_INDICATOR_TILE 0xD780 +#define TAG_FLYING_INDICATOR_TILE 0xD781 +#define TAG_POISON_INDICATOR_TILE 0xD782 +#define TAG_GROUND_INDICATOR_TILE 0xD783 +#define TAG_ROCK_INDICATOR_TILE 0xD784 +#define TAG_BUG_INDICATOR_TILE 0xD785 +#define TAG_GHOST_INDICATOR_TILE 0xD786 +#define TAG_STEEL_INDICATOR_TILE 0xD787 +// empty spot for TYPE_MYSTERY +#define TAG_FIRE_INDICATOR_TILE 0xD789 +#define TAG_WATER_INDICATOR_TILE 0xD78A +#define TAG_GRASS_INDICATOR_TILE 0xD78B +#define TAG_ELECTRIC_INDICATOR_TILE 0xD78C +#define TAG_PSYCHIC_INDICATOR_TILE 0xD78D +#define TAG_ICE_INDICATOR_TILE 0xD78E +#define TAG_DRAGON_INDICATOR_TILE 0xD78F +#define TAG_DARK_INDICATOR_TILE 0xD790 +#define TAG_FAIRY_INDICATOR_TILE 0xD791 +#define TAG_STELLAR_INDICATOR_TILE 0xD792 +#define TAG_TERA_TRIGGER_TILE 0xD793 + #define TAG_MEGA_TRIGGER_PAL 0xD777 #define TAG_MEGA_INDICATOR_PAL 0xD778 #define TAG_MISC_INDICATOR_PAL 0xD779 // Alpha, Omega, and Dynamax indicators use the same palette as each of them only uses 4 different colors. #define TAG_ZMOVE_TRIGGER_PAL 0xD77B #define TAG_BURST_TRIGGER_PAL 0xD77C #define TAG_DYNAMAX_TRIGGER_PAL 0xD77D +#define TAG_TERA_INDICATOR_PAL 0xD77E +#define TAG_TERA_TRIGGER_PAL 0xD77F enum { diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 540390bb53..fcf69e53dc 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -52,6 +52,7 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem); u8 GetCatchingBattler(void); u32 GetHighestStatId(u32 battlerId); bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType); +bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef); bool32 IsMoveNotAllowedInSkyBattles(u32 move); bool32 DoSwitchInAbilities(u32 battlerId); u8 GetFirstFaintedPartyIndex(u8 battlerId); diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 1a7654d37b..fae2e09e30 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -80,6 +80,7 @@ extern const u8 BattleScript_EncoredNoMore[]; extern const u8 BattleScript_DestinyBondTakesLife[]; extern const u8 BattleScript_DmgHazardsOnAttacker[]; extern const u8 BattleScript_DmgHazardsOnTarget[]; +extern const u8 BattleScript_DmgHazardsOnBattlerScripting[]; extern const u8 BattleScript_DmgHazardsOnFaintedBattler[]; extern const u8 BattleScript_PerishSongTakesLife[]; extern const u8 BattleScript_PerishSongCountGoesDown[]; @@ -364,6 +365,8 @@ extern const u8 BattleScript_DancerActivates[]; extern const u8 BattleScript_AftermathDmg[]; extern const u8 BattleScript_AttackerFormChange[]; extern const u8 BattleScript_AttackerFormChangeEnd3[]; +extern const u8 BattleScript_AttackerFormChangeWithString[]; +extern const u8 BattleScript_AttackerFormChangeWithStringEnd3[]; extern const u8 BattleScript_TargetFormChange[]; extern const u8 BattleScript_AnticipationActivates[]; extern const u8 BattleScript_SlowStartEnds[]; @@ -382,6 +385,7 @@ extern const u8 BattleScript_CheekPouchActivates[]; extern const u8 BattleScript_TotemVar[]; extern const u8 BattleScript_TotemFlaredToLife[]; extern const u8 BattleScript_AnnounceAirLockCloudNine[]; +extern const u8 BattleScript_ActivateTeraformZero[]; extern const u8 BattleScript_BattlerAbilityStatRaiseOnSwitchIn[]; extern const u8 BattleScript_CottonDownActivates[]; extern const u8 BattleScript_BallFetch[]; @@ -436,6 +440,7 @@ extern const u8 BattleScript_PastelVeilActivates[]; extern const u8 BattleScript_MimicryActivatesEnd3[]; extern const u8 BattleScript_ApplyMimicry[]; extern const u8 BattleScript_AttackerFormChangeEnd3NoPopup[]; +extern const u8 BattleScript_AttackerFormChangeWithStringEnd3NoPopup[]; extern const u8 BattleScript_AttackerFormChangeMoveEffect[]; extern const u8 BattleScript_BothCanNoLongerEscape[]; extern const u8 BattleScript_OctolockEndTurn[]; @@ -499,7 +504,10 @@ extern const u8 BattleScript_TheSwampDisappeared[]; extern const u8 BattleScript_ItemRestoreHP_Party[]; extern const u8 BattleScript_EffectPsychicNoise[]; extern const u8 BattleScript_AromaVeilProtectsRet[]; +extern const u8 BattleScript_LowerAtkSpAtk[]; +extern const u8 BattleScript_Terastallization[]; extern const u8 BattleScript_BoosterEnergyEnd2[]; +extern const u8 BattleScript_TeraShellDistortingTypeMatchups[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/battle_terastal.h b/include/battle_terastal.h new file mode 100644 index 0000000000..078bf39079 --- /dev/null +++ b/include/battle_terastal.h @@ -0,0 +1,30 @@ +#ifndef GUARD_BATTLE_TERASTAL_H +#define GUARD_BATTLE_TERASTAL_H + +void PrepareBattlerForTera(u32 battler); +bool32 CanTerastallize(u32 battler); +u32 GetBattlerTeraType(u32 battler); +bool32 IsTerastallized(u32 battler); +void ExpendTypeStellarBoost(u32 battler, u32 type); +bool32 IsTypeStellarBoosted(u32 battler, u32 type); +uq4_12_t GetTeraMultiplier(u32 battler, u32 type); + +u16 GetTeraTypeRGB(u32 type); + +void ChangeTeraTriggerSprite(u8 spriteId, u8 animId); +void CreateTeraTriggerSprite(u8 battler, u8 palId); +bool32 IsTeraTriggerSpriteActive(void); +void HideTeraTriggerSprite(void); +void DestroyTeraTriggerSprite(void); + +void TeraIndicator_LoadSpriteGfx(void); +bool32 TeraIndicator_ShouldBeInvisible(u32 battler); +u8 TeraIndicator_GetSpriteId(u32 healthboxSpriteId); +void TeraIndicator_SetVisibilities(u32 healthboxId, bool32 invisible); +void TeraIndicator_UpdateOamPriorities(u32 healthboxId, u32 oamPriority); +void TeraIndicator_UpdateLevel(u32 healthboxId, u32 level); +void TeraIndicator_CreateSprite(u32 battler, u32 healthboxSpriteId); +void TeraIndicator_DestroySprite(u32 healthboxSpriteId); +void TeraIndicator_UpdateType(u32 battler, u32 healthboxSpriteId); + +#endif diff --git a/include/battle_util.h b/include/battle_util.h index 3298c4d31f..894bb8a745 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -251,7 +251,7 @@ bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2); bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2); u32 CalcSecondaryEffectChance(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); bool32 MoveEffectIsGuaranteed(u32 battler, u32 battlerAbility, const struct AdditionalEffect *additionalEffect); -u8 GetBattlerType(u32 battler, u8 typeIndex); +u8 GetBattlerType(u32 battler, u8 typeIndex, bool32 ignoreTera); bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon); bool8 IsMonBannedFromSkyBattles(u16 species); void RemoveBattlerType(u32 battler, u8 type); diff --git a/include/config/battle.h b/include/config/battle.h index 40d7bd1147..18379d4add 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -39,10 +39,11 @@ #define B_MULTIPLE_TARGETS_DMG GEN_LATEST // In Gen4+, damage dealt by moves that hit multiple targets at once is reduced to 75%. Before, it was 50%. // Type settings +#define B_EXPANDED_TYPE_NAMES TRUE // If TRUE, type names are increased from 6 characters to 8 characters. #define B_GHOSTS_ESCAPE GEN_LATEST // In Gen6+, abilities like Shadow Tag or moves like Mean Look fail on Ghost-type Pokémon. They can also escape any Wild Battle. #define B_PARALYZE_ELECTRIC GEN_LATEST // In Gen6+, Electric-type Pokémon can't be paralyzed. #define B_POWDER_GRASS GEN_LATEST // In Gen6+, Grass-type Pokémon are immune to powder and spore moves. -#define B_STEEL_RESISTANCES GEN_LATEST // In Gen6+, Steel-type Pokémon are no longer resistant to Dark-type and Ghost-type moves. +#define B_UPDATED_TYPE_MATCHUPS GEN_LATEST // Updates Type matchups. Refer to sTypeEffectivenessTable for details. #define B_PRANKSTER_DARK_TYPES GEN_LATEST // In Gen7+, Prankster-elevated status moves do not affect Dark type Pokémon. #define B_SHEER_COLD_IMMUNITY GEN_LATEST // In Gen7+, Ice-types are immune to Sheer Cold #define B_ROOST_PURE_FLYING GEN_LATEST // In Gen5+, Roost makes pure Flying-types into Normal-type. @@ -179,6 +180,8 @@ #define B_FLAG_NO_CATCHING 0 // If this flag is set, the ability to catch wild Pokémon is disabled. #define B_FLAG_AI_VS_AI_BATTLE 0 // If this flag is set, the player's mons will be controlled by the ai next battles. #define B_FLAG_DYNAMAX_BATTLE 0 // If this flag is set, the ability to Dynamax in battle is enabled for all trainers. +#define B_FLAG_TERA_ORB_CHARGED 0 // If this flag is set, the Tera Orb is charged. It is automatically set upon healing and cleared upon Terastallizing once configured. +#define B_FLAG_TERA_ORB_NO_COST 0 // If this flag is set, the Tera Orb does not use up its charge upon Terastallization. In S/V, this occurs after an event with Terapagos. // Var Settings // To use the following features in scripting, replace the 0s with the var ID you're assigning it to. @@ -212,7 +215,7 @@ #define B_SHOW_TARGETS TRUE // If set to TRUE, all available targets, for moves hitting 2 or 3 Pokémon, will be shown before selecting a move. #define B_SHOW_CATEGORY_ICON TRUE // If set to TRUE, it will show an icon in the summary showing the move's category. #define B_HIDE_HEALTHBOX_IN_ANIMS TRUE // If set to TRUE, hides healthboxes during move animations. -#define B_EXPANDED_MOVE_NAMES FALSE // If set to TRUE, move names are increased from 12 characters to 16 characters. +#define B_EXPANDED_MOVE_NAMES TRUE // If set to FALSE, move names are decreased from 16 characters to 12 characters. #define B_WAIT_TIME_MULTIPLIER 16 // This determines how long text pauses in battle last. Vanilla is 16. Lower values result in faster battles. #define B_QUICK_MOVE_CURSOR_TO_RUN FALSE // If set to TRUE, pushing B in the battle options against a wild encounter will move the cursor to the run option diff --git a/include/config/item.h b/include/config/item.h index 1a1a196a16..644a73ade6 100644 --- a/include/config/item.h +++ b/include/config/item.h @@ -2,6 +2,7 @@ #define GUARD_CONFIG_ITEM_H // Item config +#define I_EXPANDED_ITEM_NAMES TRUE // If set to FALSE, item names are decreased from 20 characters to 14 characters. #define I_SHINY_CHARM_ADDITIONAL_ROLLS 2 // Amount of additional shiny rolls if the player has the Shiny Charm. Set it to 0 to disable Shiny Charm's effects. #define I_KEY_FOSSILS GEN_LATEST // In Gen4+, all Gen 3 fossils became regular items. #define I_KEY_ESCAPE_ROPE GEN_LATEST // In Gen8, Escape Rope became a Key Item. Keep in mind, this will make it free to buy in marts. diff --git a/include/config/test.h b/include/config/test.h new file mode 100644 index 0000000000..4101f7a559 --- /dev/null +++ b/include/config/test.h @@ -0,0 +1,13 @@ +#ifndef GUARD_CONFIG_TEST_H +#define GUARD_CONFIG_TEST_H + +#undef B_EXPANDED_MOVE_NAMES +#define B_EXPANDED_MOVE_NAMES TRUE +#undef I_EXPANDED_ITEM_NAMES +#define I_EXPANDED_ITEM_NAMES TRUE +#undef POKEMON_NAME_LENGTH +#define POKEMON_NAME_LENGTH 12 +#undef B_EXPANDED_TYPE_NAMES +#define B_EXPANDED_TYPE_NAMES TRUE + +#endif // GUARD_CONFIG_TEST_H diff --git a/include/constants/abilities.h b/include/constants/abilities.h index 3cced68bb1..8568206137 100644 --- a/include/constants/abilities.h +++ b/include/constants/abilities.h @@ -326,10 +326,10 @@ #define ABILITY_MYCELIUM_MIGHT 298 #define ABILITY_HOSPITALITY 299 #define ABILITY_MINDS_EYE 300 -#define ABILITY_EMBODY_ASPECT_TEAL 301 -#define ABILITY_EMBODY_ASPECT_HEARTHFLAME 302 -#define ABILITY_EMBODY_ASPECT_WELLSPRING 303 -#define ABILITY_EMBODY_ASPECT_CORNERSTONE 304 +#define ABILITY_EMBODY_ASPECT_TEAL_MASK 301 +#define ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK 302 +#define ABILITY_EMBODY_ASPECT_WELLSPRING_MASK 303 +#define ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK 304 #define ABILITY_TOXIC_CHAIN 305 #define ABILITY_SUPERSWEET_SYRUP 306 #define ABILITY_TERA_SHIFT 307 diff --git a/include/constants/battle.h b/include/constants/battle.h index 0acb857ad0..4ca7eabdca 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -299,7 +299,7 @@ #define B_WEATHER_HAIL_PERMANENT (1 << 10) #define B_WEATHER_HAIL (B_WEATHER_HAIL_TEMPORARY | B_WEATHER_HAIL_PERMANENT) #define B_WEATHER_STRONG_WINDS (1 << 11) -#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW) +#define B_WEATHER_ANY (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_SUN | B_WEATHER_HAIL | B_WEATHER_STRONG_WINDS | B_WEATHER_SNOW | B_WEATHER_FOG) #define B_WEATHER_PRIMAL_ANY (B_WEATHER_RAIN_PRIMAL | B_WEATHER_SUN_PRIMAL | B_WEATHER_STRONG_WINDS) #define B_WEATHER_SNOW_TEMPORARY (1 << 12) #define B_WEATHER_SNOW_PERMANENT (1 << 13) @@ -402,8 +402,9 @@ #define MOVE_EFFECT_FLORAL_HEALING 77 #define MOVE_EFFECT_SECRET_POWER 78 #define MOVE_EFFECT_PSYCHIC_NOISE 79 +#define MOVE_EFFECT_TERA_BLAST 80 -#define NUM_MOVE_EFFECTS 80 +#define NUM_MOVE_EFFECTS 81 #define MOVE_EFFECT_AFFECTS_USER 0x2000 #define MOVE_EFFECT_CERTAIN 0x4000 diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 0cf0862f15..abb1a9ab0f 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -350,6 +350,8 @@ enum { EFFECT_DRAGON_CHEER, EFFECT_LAST_RESPECTS, EFFECT_TIDY_UP, + EFFECT_TERA_BLAST, + EFFECT_TERA_STARSTORM, NUM_BATTLE_MOVE_EFFECTS, }; diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 641e644ebc..ef8803ce42 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -131,113 +131,112 @@ #define VARIOUS_SET_SIMPLE_BEAM 39 #define VARIOUS_TRY_ENTRAINMENT 40 #define VARIOUS_SET_LAST_USED_ABILITY 41 -#define VARIOUS_TRY_QUASH 42 -#define VARIOUS_INVERT_STAT_STAGES 43 -#define VARIOUS_TRY_ME_FIRST 44 -#define VARIOUS_JUMP_IF_BATTLE_END 45 -#define VARIOUS_TRY_ELECTRIFY 46 -#define VARIOUS_TRY_REFLECT_TYPE 47 -#define VARIOUS_TRY_SOAK 48 -#define VARIOUS_HANDLE_MEGA_EVO 49 -#define VARIOUS_TRY_LAST_RESORT 50 -#define VARIOUS_SET_ARG_TO_BATTLE_DAMAGE 51 -#define VARIOUS_TRY_HIT_SWITCH_TARGET 52 -#define VARIOUS_TRY_AUTOTOMIZE 53 -#define VARIOUS_ABILITY_POPUP 54 -#define VARIOUS_JUMP_IF_TARGET_ALLY 55 -#define VARIOUS_TRY_SYNCHRONOISE 56 -#define VARIOUS_PSYCHO_SHIFT 57 -#define VARIOUS_CURE_STATUS 58 -#define VARIOUS_POWER_TRICK 59 -#define VARIOUS_AFTER_YOU 60 -#define VARIOUS_BESTOW 61 -#define VARIOUS_JUMP_IF_NOT_GROUNDED 62 -#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 63 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 64 -#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 65 -#define VARIOUS_SET_AURORA_VEIL 66 -#define VARIOUS_TRY_THIRD_TYPE 67 -#define VARIOUS_ACUPRESSURE 68 -#define VARIOUS_SET_POWDER 69 -#define VARIOUS_SPECTRAL_THIEF 70 -#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 71 -#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 72 -#define VARIOUS_JUMP_IF_ROAR_FAILS 73 -#define VARIOUS_TRY_INSTRUCT 74 -#define VARIOUS_JUMP_IF_NOT_BERRY 75 -#define VARIOUS_TRACE_ABILITY 76 -#define VARIOUS_UPDATE_NICK 77 -#define VARIOUS_TRY_ILLUSION_OFF 78 -#define VARIOUS_SET_SPRITEIGNORE0HP 79 -#define VARIOUS_HANDLE_FORM_CHANGE 80 -#define VARIOUS_GET_STAT_VALUE 81 -#define VARIOUS_JUMP_IF_FULL_HP 82 -#define VARIOUS_LOSE_TYPE 83 -#define VARIOUS_TRY_ACTIVATE_SOULHEART 84 -#define VARIOUS_TRY_ACTIVATE_RECEIVER 85 -#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 86 -#define VARIOUS_TRY_FRISK 87 -#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 88 -#define VARIOUS_TRY_FAIRY_LOCK 89 -#define VARIOUS_JUMP_IF_NO_ALLY 90 -#define VARIOUS_POISON_TYPE_IMMUNITY 91 -#define VARIOUS_JUMP_IF_HOLD_EFFECT 92 -#define VARIOUS_INFATUATE_WITH_BATTLER 93 -#define VARIOUS_SET_LAST_USED_ITEM 94 -#define VARIOUS_PARALYZE_TYPE_IMMUNITY 95 -#define VARIOUS_JUMP_IF_ABSENT 96 -#define VARIOUS_DESTROY_ABILITY_POPUP 97 -#define VARIOUS_TOTEM_BOOST 98 -#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 99 -#define VARIOUS_MOVEEND_ITEM_EFFECTS 100 -#define VARIOUS_TERRAIN_SEED 101 -#define VARIOUS_MAKE_INVISIBLE 102 -#define VARIOUS_ROOM_SERVICE 103 -#define VARIOUS_EERIE_SPELL_PP_REDUCE 104 -#define VARIOUS_JUMP_IF_TEAM_HEALTHY 105 -#define VARIOUS_TRY_HEAL_QUARTER_HP 106 -#define VARIOUS_REMOVE_TERRAIN 107 -#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 108 -#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 109 -#define VARIOUS_GET_ROTOTILLER_TARGETS 110 -#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 111 -#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 112 -#define VARIOUS_CONSUME_BERRY 113 -#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 114 -#define VARIOUS_JUMP_IF_SPECIES 115 -#define VARIOUS_UPDATE_ABILITY_POPUP 116 -#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 117 -#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 118 -#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 119 -#define VARIOUS_SHELL_SIDE_ARM_CHECK 120 -#define VARIOUS_TRY_NO_RETREAT 121 -#define VARIOUS_TRY_TAR_SHOT 122 -#define VARIOUS_CAN_TAR_SHOT_WORK 123 -#define VARIOUS_CHECK_POLTERGEIST 124 -#define VARIOUS_CUT_1_3_HP_RAISE_STATS 125 -#define VARIOUS_TRY_END_NEUTRALIZING_GAS 126 -#define VARIOUS_JUMP_IF_UNDER_200 127 -#define VARIOUS_SET_SKY_DROP 128 -#define VARIOUS_CLEAR_SKY_DROP 129 -#define VARIOUS_SKY_DROP_YAWN 130 -#define VARIOUS_CURE_CERTAIN_STATUSES 131 -#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 132 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 133 -#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 134 -#define VARIOUS_SAVE_BATTLER_ITEM 135 -#define VARIOUS_RESTORE_BATTLER_ITEM 136 -#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 137 -#define VARIOUS_SET_BEAK_BLAST 138 -#define VARIOUS_SWAP_SIDE_STATUSES 139 -#define VARIOUS_SWAP_STATS 140 -#define VARIOUS_TEATIME_INVUL 141 -#define VARIOUS_TEATIME_TARGETS 142 -#define VARIOUS_TRY_WIND_RIDER_POWER 143 -#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 144 -#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 145 -#define VARIOUS_STORE_HEALING_WISH 146 -#define VARIOUS_HIT_SWITCH_TARGET_FAILED 147 -#define VARIOUS_TRY_REVIVAL_BLESSING 148 +#define VARIOUS_INVERT_STAT_STAGES 42 +#define VARIOUS_TRY_ME_FIRST 43 +#define VARIOUS_JUMP_IF_BATTLE_END 44 +#define VARIOUS_TRY_ELECTRIFY 45 +#define VARIOUS_TRY_REFLECT_TYPE 46 +#define VARIOUS_TRY_SOAK 47 +#define VARIOUS_HANDLE_MEGA_EVO 48 +#define VARIOUS_TRY_LAST_RESORT 49 +#define VARIOUS_SET_ARG_TO_BATTLE_DAMAGE 50 +#define VARIOUS_TRY_HIT_SWITCH_TARGET 51 +#define VARIOUS_TRY_AUTOTOMIZE 52 +#define VARIOUS_ABILITY_POPUP 53 +#define VARIOUS_JUMP_IF_TARGET_ALLY 54 +#define VARIOUS_TRY_SYNCHRONOISE 55 +#define VARIOUS_PSYCHO_SHIFT 56 +#define VARIOUS_CURE_STATUS 57 +#define VARIOUS_POWER_TRICK 58 +#define VARIOUS_AFTER_YOU 59 +#define VARIOUS_BESTOW 60 +#define VARIOUS_JUMP_IF_NOT_GROUNDED 61 +#define VARIOUS_HANDLE_TRAINER_SLIDE_MSG 62 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_FIRST_OFF 63 +#define VARIOUS_TRY_TRAINER_SLIDE_MSG_LAST_ON 64 +#define VARIOUS_SET_AURORA_VEIL 65 +#define VARIOUS_TRY_THIRD_TYPE 66 +#define VARIOUS_ACUPRESSURE 67 +#define VARIOUS_SET_POWDER 68 +#define VARIOUS_SPECTRAL_THIEF 69 +#define VARIOUS_GRAVITY_ON_AIRBORNE_MONS 70 +#define VARIOUS_CHECK_IF_GRASSY_TERRAIN_HEALS 71 +#define VARIOUS_JUMP_IF_ROAR_FAILS 72 +#define VARIOUS_TRY_INSTRUCT 73 +#define VARIOUS_JUMP_IF_NOT_BERRY 74 +#define VARIOUS_TRACE_ABILITY 75 +#define VARIOUS_UPDATE_NICK 76 +#define VARIOUS_TRY_ILLUSION_OFF 77 +#define VARIOUS_SET_SPRITEIGNORE0HP 78 +#define VARIOUS_HANDLE_FORM_CHANGE 79 +#define VARIOUS_GET_STAT_VALUE 80 +#define VARIOUS_JUMP_IF_FULL_HP 81 +#define VARIOUS_LOSE_TYPE 82 +#define VARIOUS_TRY_ACTIVATE_SOULHEART 83 +#define VARIOUS_TRY_ACTIVATE_RECEIVER 84 +#define VARIOUS_TRY_ACTIVATE_BEAST_BOOST 85 +#define VARIOUS_TRY_FRISK 86 +#define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 87 +#define VARIOUS_TRY_FAIRY_LOCK 88 +#define VARIOUS_JUMP_IF_NO_ALLY 89 +#define VARIOUS_POISON_TYPE_IMMUNITY 90 +#define VARIOUS_JUMP_IF_HOLD_EFFECT 91 +#define VARIOUS_INFATUATE_WITH_BATTLER 92 +#define VARIOUS_SET_LAST_USED_ITEM 93 +#define VARIOUS_PARALYZE_TYPE_IMMUNITY 94 +#define VARIOUS_JUMP_IF_ABSENT 95 +#define VARIOUS_DESTROY_ABILITY_POPUP 96 +#define VARIOUS_TOTEM_BOOST 97 +#define VARIOUS_TRY_ACTIVATE_GRIM_NEIGH 98 +#define VARIOUS_MOVEEND_ITEM_EFFECTS 99 +#define VARIOUS_TERRAIN_SEED 100 +#define VARIOUS_MAKE_INVISIBLE 101 +#define VARIOUS_ROOM_SERVICE 102 +#define VARIOUS_EERIE_SPELL_PP_REDUCE 103 +#define VARIOUS_JUMP_IF_TEAM_HEALTHY 104 +#define VARIOUS_TRY_HEAL_QUARTER_HP 105 +#define VARIOUS_REMOVE_TERRAIN 106 +#define VARIOUS_JUMP_IF_PRANKSTER_BLOCKED 107 +#define VARIOUS_TRY_TO_CLEAR_PRIMAL_WEATHER 108 +#define VARIOUS_GET_ROTOTILLER_TARGETS 109 +#define VARIOUS_JUMP_IF_NOT_ROTOTILLER_AFFECTED 110 +#define VARIOUS_TRY_ACTIVATE_BATTLE_BOND 111 +#define VARIOUS_CONSUME_BERRY 112 +#define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 113 +#define VARIOUS_JUMP_IF_SPECIES 114 +#define VARIOUS_UPDATE_ABILITY_POPUP 115 +#define VARIOUS_JUMP_IF_WEATHER_AFFECTED 116 +#define VARIOUS_JUMP_IF_LEAF_GUARD_PROTECTED 117 +#define VARIOUS_SET_ATTACKER_STICKY_WEB_USER 118 +#define VARIOUS_SHELL_SIDE_ARM_CHECK 119 +#define VARIOUS_TRY_NO_RETREAT 120 +#define VARIOUS_TRY_TAR_SHOT 121 +#define VARIOUS_CAN_TAR_SHOT_WORK 122 +#define VARIOUS_CHECK_POLTERGEIST 123 +#define VARIOUS_CUT_1_3_HP_RAISE_STATS 124 +#define VARIOUS_TRY_END_NEUTRALIZING_GAS 125 +#define VARIOUS_JUMP_IF_UNDER_200 126 +#define VARIOUS_SET_SKY_DROP 127 +#define VARIOUS_CLEAR_SKY_DROP 128 +#define VARIOUS_SKY_DROP_YAWN 129 +#define VARIOUS_CURE_CERTAIN_STATUSES 130 +#define VARIOUS_TRY_RESET_NEGATIVE_STAT_STAGES 131 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_BERRY 132 +#define VARIOUS_JUMP_IF_LAST_USED_ITEM_HOLD_EFFECT 133 +#define VARIOUS_SAVE_BATTLER_ITEM 134 +#define VARIOUS_RESTORE_BATTLER_ITEM 135 +#define VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM 136 +#define VARIOUS_SET_BEAK_BLAST 137 +#define VARIOUS_SWAP_SIDE_STATUSES 138 +#define VARIOUS_SWAP_STATS 139 +#define VARIOUS_TEATIME_INVUL 140 +#define VARIOUS_TEATIME_TARGETS 141 +#define VARIOUS_TRY_WIND_RIDER_POWER 142 +#define VARIOUS_ACTIVATE_WEATHER_CHANGE_ABILITIES 143 +#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 144 +#define VARIOUS_STORE_HEALING_WISH 145 +#define VARIOUS_HIT_SWITCH_TARGET_FAILED 146 +#define VARIOUS_TRY_REVIVAL_BLESSING 147 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/include/constants/battle_string_ids.h b/include/constants/battle_string_ids.h index 86b48f9d4a..b337d5f92a 100644 --- a/include/constants/battle_string_ids.h +++ b/include/constants/battle_string_ids.h @@ -635,7 +635,7 @@ #define STRINGID_SUNLIGHTACTIVATEDABILITY 633 #define STRINGID_STATWASHEIGHTENED 634 #define STRINGID_ELECTRICTERRAINACTIVATEDABILITY 635 -#define STRINGID_ABILITYWEAKENEDFSURROUNDINGMONSSTAT 636 +#define STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT 636 #define STRINGID_ATTACKERGAINEDSTRENGTHFROMTHEFALLEN 637 #define STRINGID_PKMNSABILITYPREVENTSABILITY 638 #define STRINGID_PREPARESHELLTRAP 639 @@ -707,12 +707,14 @@ #define STRINGID_BIZARREARENACREATED 705 #define STRINGID_BIZARREAREACREATED 706 #define STRINGID_TIDYINGUPCOMPLETE 707 -#define STRINGID_BOOSTERENERGYACTIVATES 708 -#define STRINGID_FOGCREPTUP 709 -#define STRINGID_FOGISDEEP 710 -#define STRINGID_FOGLIFTED 711 +#define STRINGID_PKMNTERASTALLIZEDINTO 708 +#define STRINGID_BOOSTERENERGYACTIVATES 709 +#define STRINGID_FOGCREPTUP 710 +#define STRINGID_FOGISDEEP 711 +#define STRINGID_FOGLIFTED 712 +#define STRINGID_PKMNMADESHELLGLEAM 713 -#define BATTLESTRINGS_COUNT 712 +#define BATTLESTRINGS_COUNT 714 // This is the string id that gBattleStringsTable starts with. // String ids before this (e.g. STRINGID_INTROMSG) are not in the table, @@ -766,6 +768,16 @@ #define B_MSG_STARTED_SNOW 6 #define B_MSG_STARTED_FOG 7 +// gWeatherEndsStringIds +#define B_MSG_WEATHER_END_RAIN 0 +#define B_MSG_WEATHER_END_SANDSTORM 1 +#define B_MSG_WEATHER_END_SUN 2 +#define B_MSG_WEATHER_END_HAIL 3 +#define B_MSG_WEATHER_END_STRONG_WINDS 4 +#define B_MSG_WEATHER_END_SNOW 5 +#define B_MSG_WEATHER_END_FOG 6 +#define B_MSG_WEATHER_END_COUNT 7 + // gRainContinuesStringIds #define B_MSG_RAIN_CONTINUES 0 #define B_MSG_DOWNPOUR_CONTINUES 1 diff --git a/include/constants/expansion.h b/include/constants/expansion.h index b72429d619..e1e228fd9b 100644 --- a/include/constants/expansion.h +++ b/include/constants/expansion.h @@ -1,10 +1,10 @@ #ifndef GUARD_CONSTANTS_EXPANSION_H #define GUARD_CONSTANTS_EXPANSION_H -// 1.8.2 +// 1.8.3 #define EXPANSION_VERSION_MAJOR 1 #define EXPANSION_VERSION_MINOR 8 -#define EXPANSION_VERSION_PATCH 2 +#define EXPANSION_VERSION_PATCH 3 // FALSE if this this version of Expansion is not a tagged commit, i.e. // it contains unreleased changes. diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index 51325baf25..d23dc0d2bd 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -61,7 +61,7 @@ #define FORM_CHANGE_END_BATTLE_TERRAIN 8 // Form change that activates when the Pokémon is switched out in battle. -// - No parameters. +// param1: ability to check, optional #define FORM_CHANGE_BATTLE_SWITCH 9 // Form change that activates when the Pokémon's HP % passes a certain threshold. diff --git a/include/constants/global.h b/include/constants/global.h index b8ac7559a8..8b91af77fa 100644 --- a/include/constants/global.h +++ b/include/constants/global.h @@ -102,9 +102,10 @@ #define CONTEST_CATEGORIES_COUNT 5 // string lengths -#define ITEM_NAME_LENGTH 14 +#define ITEM_NAME_LENGTH ((I_EXPANDED_ITEM_NAMES == TRUE) ? 20 : 14) #define ITEM_NAME_PLURAL_LENGTH ITEM_NAME_LENGTH + 2 // 2 is used for the instance where a word's suffix becomes y->ies -#define POKEMON_NAME_LENGTH 10 +#define POKEMON_NAME_LENGTH 12 +#define VANILLA_POKEMON_NAME_LENGTH 10 #define POKEMON_NAME_BUFFER_SIZE max(20, POKEMON_NAME_LENGTH + 1) // Frequently used buffer size. Larger than necessary #define PLAYER_NAME_LENGTH 7 #define MAIL_WORDS_COUNT 9 @@ -116,7 +117,7 @@ #define WONDER_NEWS_TEXT_LENGTH 40 #define WONDER_CARD_BODY_TEXT_LINES 4 #define WONDER_NEWS_BODY_TEXT_LINES 10 -#define TYPE_NAME_LENGTH 6 +#define TYPE_NAME_LENGTH ((B_EXPANDED_TYPE_NAMES == TRUE) ? 8 : 6) #define ABILITY_NAME_LENGTH ((B_EXPANDED_ABILITY_NAMES == TRUE) ? 16 : 12) #define TRAINER_NAME_LENGTH 10 @@ -170,4 +171,8 @@ #define CONNECTION_DIVE 5 #define CONNECTION_EMERGE 6 +#if TESTING +#include "config/test.h" +#endif + #endif // GUARD_CONSTANTS_GLOBAL_H diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 1adefd4938..343bf1a049 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -22,7 +22,8 @@ #define TYPE_DRAGON 16 #define TYPE_DARK 17 #define TYPE_FAIRY 18 -#define NUMBER_OF_MON_TYPES 19 +#define TYPE_STELLAR 19 +#define NUMBER_OF_MON_TYPES 20 // Pokémon egg groups #define EGG_GROUP_NONE 0 diff --git a/include/data.h b/include/data.h index b7d7773627..9f76afb1db 100644 --- a/include/data.h +++ b/include/data.h @@ -82,6 +82,7 @@ struct TrainerMon bool8 gender:2; bool8 isShiny:1; u8 dynamaxLevel:4; + u8 teraType:5; bool8 gigantamaxFactor:1; bool8 shouldDynamax:1; bool8 shouldTerastal:1; @@ -119,6 +120,7 @@ struct TypeInfo u8 palette; u16 zMove; u16 maxMove; + const u32 *const paletteTMHM; //u16 enhanceItem; //u16 berry; //u16 gem; @@ -206,14 +208,14 @@ static inline const u8 GetTrainerClassFromId(u16 trainerId) static inline const u8 *GetTrainerClassNameFromId(u16 trainerId) { if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) - return gTrainerClasses[gBattlePartners[trainerId].trainerClass].name; + return gTrainerClasses[gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass].name; return gTrainerClasses[GetTrainerClassFromId(trainerId)].name; } static inline const u8 *GetTrainerNameFromId(u16 trainerId) { if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) - return gBattlePartners[trainerId].trainerName; + return gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerName; return gTrainers[SanitizeTrainerId(trainerId)].trainerName; } diff --git a/include/daycare.h b/include/daycare.h index daea812bed..2747a66850 100644 --- a/include/daycare.h +++ b/include/daycare.h @@ -10,7 +10,7 @@ struct RecordMixingDaycareMail bool16 cantHoldItem[DAYCARE_MON_COUNT]; }; -u8 *GetMonNickname2(struct Pokemon *mon, u8 *dest); +u8 *GetMonNicknameVanilla(struct Pokemon *mon, u8 *dest); u8 *GetBoxMonNickname(struct BoxPokemon *mon, u8 *dest); u8 CountPokemonInDaycare(struct DayCare *daycare); void InitDaycareMailRecordMixing(struct DayCare *daycare, struct RecordMixingDaycareMail *mixMail); diff --git a/include/fonts.h b/include/fonts.h index c21c75942d..a6be35db98 100644 --- a/include/fonts.h +++ b/include/fonts.h @@ -15,5 +15,11 @@ extern const u16 gFontNarrowLatinGlyphs[]; extern const u8 gFontNarrowLatinGlyphWidths[]; extern const u16 gFontSmallNarrowLatinGlyphs[]; extern const u8 gFontSmallNarrowLatinGlyphWidths[]; +extern const u8 gFontNarrowerLatinGlyphWidths[]; +extern const u16 gFontNarrowerLatinGlyphs[]; +extern const u8 gFontSmallNarrowerLatinGlyphWidths[]; +extern const u16 gFontSmallNarrowerLatinGlyphs[]; +extern const u8 gFontShortNarrowLatinGlyphWidths[]; +extern const u16 gFontShortNarrowLatinGlyphs[]; #endif // GUARD_FONTS_H diff --git a/include/frontier_util.h b/include/frontier_util.h index f445949ef9..637b7f91bb 100644 --- a/include/frontier_util.h +++ b/include/frontier_util.h @@ -25,6 +25,4 @@ u8 GetFrontierBrainMonNature(u8 monId); u8 GetFrontierBrainMonEvs(u8 monId, u8 evStatId); s32 GetFronterBrainSymbol(void); -extern const u16 gFrontierBannedSpecies[]; - #endif // GUARD_FRONTIER_UTIL_H diff --git a/include/global.h b/include/global.h index 941d21ee26..72e0f8d145 100644 --- a/include/global.h +++ b/include/global.h @@ -288,7 +288,7 @@ struct BattleTowerPokemon u32 gap:1; u32 abilityNum:1; u32 personality; - u8 nickname[POKEMON_NAME_LENGTH + 1]; + u8 nickname[VANILLA_POKEMON_NAME_LENGTH + 1]; u8 friendship; }; @@ -313,7 +313,7 @@ struct BattleTowerInterview u16 playerSpecies; u16 opponentSpecies; u8 opponentName[PLAYER_NAME_LENGTH + 1]; - u8 opponentMonNickname[POKEMON_NAME_LENGTH + 1]; + u8 opponentMonNickname[VANILLA_POKEMON_NAME_LENGTH + 1]; u8 opponentLanguage; }; @@ -747,7 +747,7 @@ struct ContestWinner u32 trainerId; u16 species; u8 contestCategory; - u8 monName[POKEMON_NAME_LENGTH + 1]; + u8 monName[VANILLA_POKEMON_NAME_LENGTH + 1]; u8 trainerName[PLAYER_NAME_LENGTH + 1]; u8 contestRank:7; bool8 isShiny:1; @@ -767,7 +767,7 @@ struct DaycareMail { struct Mail message; u8 otName[PLAYER_NAME_LENGTH + 1]; - u8 monName[POKEMON_NAME_LENGTH + 1]; + u8 monName[VANILLA_POKEMON_NAME_LENGTH + 1]; u8 gameLanguage:4; u8 monLanguage:4; }; diff --git a/include/global.tv.h b/include/global.tv.h index 9c3902e7cc..6bc6d08f86 100644 --- a/include/global.tv.h +++ b/include/global.tv.h @@ -82,7 +82,7 @@ typedef union // size = 0x24 /*0x00*/ u8 kind; /*0x01*/ bool8 active; /*0x02*/ u16 species; - /*0x04*/ u8 pokemonName[POKEMON_NAME_LENGTH + 1]; + /*0x04*/ u8 pokemonName[VANILLA_POKEMON_NAME_LENGTH + 1]; /*0x0F*/ u8 trainerName[PLAYER_NAME_LENGTH + 1]; /*0x17*/ u8 unused[3]; /*0x1A*/ u8 random; @@ -98,7 +98,7 @@ typedef union // size = 0x24 /*0x01*/ bool8 active; /*0x02*/ u16 species; /*0x04*/ u16 words[2]; - /*0x08*/ u8 pokemonNickname[POKEMON_NAME_LENGTH + 1]; + /*0x08*/ u8 pokemonNickname[VANILLA_POKEMON_NAME_LENGTH + 1]; /*0x13*/ u8 contestCategory:3; u8 contestRank:2; u8 contestResult:2; @@ -196,7 +196,7 @@ typedef union // size = 0x24 /*0x01*/ bool8 active; /*0x02*/ u8 playerName[PLAYER_NAME_LENGTH + 1]; /*0x0A*/ u8 contestCategory; - /*0x0B*/ u8 nickname[POKEMON_NAME_LENGTH + 1]; + /*0x0B*/ u8 nickname[VANILLA_POKEMON_NAME_LENGTH + 1]; /*0x16*/ u8 pokeblockState; /*0x17*/ u8 language; /*0x18*/ u8 pokemonNameLanguage; @@ -209,7 +209,7 @@ typedef union // size = 0x24 /*0x01*/ bool8 active; /*0x02*/ u8 language; /*0x03*/ u8 language2; - /*0x04*/ u8 nickname[POKEMON_NAME_LENGTH + 1]; + /*0x04*/ u8 nickname[VANILLA_POKEMON_NAME_LENGTH + 1]; /*0x0F*/ u8 ball; /*0x10*/ u16 species; /*0x12*/ u8 nBallsUsed; @@ -409,7 +409,7 @@ typedef union // size = 0x24 /*0x01*/ bool8 active; /*0x02*/ u8 nRibbons; /*0x03*/ u8 selectedRibbon; - /*0x04*/ u8 nickname[POKEMON_NAME_LENGTH + 1]; + /*0x04*/ u8 nickname[VANILLA_POKEMON_NAME_LENGTH + 1]; /*0x0F*/ u8 language; /*0x10*/ u8 pokemonNameLanguage; /*0x11*/ u8 filler_12[2]; diff --git a/include/item.h b/include/item.h index 53121d1127..88c9fe5e3f 100644 --- a/include/item.h +++ b/include/item.h @@ -37,8 +37,8 @@ extern struct BagPocket gBagPockets[]; void ApplyNewEncryptionKeyToBagItems(u32 newKey); void ApplyNewEncryptionKeyToBagItems_(u32 newKey); void SetBagItemsPointers(void); -void CopyItemName(u16 itemId, u8 *dst); -void CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity); +u8 *CopyItemName(u16 itemId, u8 *dst); +u8 *CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity); bool8 IsBagPocketNonEmpty(u8 pocket); bool8 CheckBagHasItem(u16 itemId, u16 count); bool8 HasAtLeastOneBerry(void); diff --git a/include/list_menu.h b/include/list_menu.h index 23caaf4b4c..1e6c0f95fa 100644 --- a/include/list_menu.h +++ b/include/list_menu.h @@ -40,8 +40,9 @@ struct ListMenuTemplate const struct ListMenuItem *items; void (* moveCursorFunc)(s32 itemIndex, bool8 onInit, struct ListMenu *list); void (* itemPrintFunc)(u8 windowId, u32 itemId, u8 y); - u16 totalItems; - u16 maxShowed; + u16 totalItems:12; + u16 maxShowed:12; + u16 textNarrowWidth:8; u8 windowId; u8 header_X; u8 item_X; diff --git a/include/pokemon.h b/include/pokemon.h index 1d913d1166..52338357c1 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -28,6 +28,7 @@ enum { MON_DATA_HP_LOST, MON_DATA_ENCRYPT_SEPARATOR, MON_DATA_NICKNAME, + MON_DATA_NICKNAME10, MON_DATA_SPECIES, MON_DATA_HELD_ITEM, MON_DATA_MOVE1, @@ -424,8 +425,8 @@ struct SpeciesInfo /*0x8C*/ /* 0x7A */ u32 isLegendary:1; u32 isMythical:1; u32 isUltraBeast:1; + u32 isParadox:1; u32 isTotem:1; - u32 isParadoxForm:1; u32 isMegaEvolution:1; u32 isPrimalReversion:1; u32 isUltraBurst:1; @@ -437,8 +438,9 @@ struct SpeciesInfo /*0x8C*/ u32 cannotBeTraded:1; u32 allPerfectIVs:1; u32 dexForceRequired:1; // This species will be taken into account for Pokédex ratings even if they have the "isMythical" flag set. - u32 tmIlliterate:1; // This species will be unable to learn the universal moves. - u32 padding4:15; + u32 tmIlliterate:1; // This species will be unable to learn the universal moves. + u32 isFrontierBanned:1; // This species is not allowed to participate in Battle Frontier facilities. + u32 padding4:14; // Move Data /* 0x80 */ const struct LevelUpMove *levelUpLearnset; /* 0x84 */ const u16 *teachableLearnset; @@ -664,8 +666,6 @@ void SetMonMoveSlot(struct Pokemon *mon, u16 move, u8 slot); void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot); void GiveMonInitialMoveset(struct Pokemon *mon); void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon); -void GiveMonInitialMoveset_Fast(struct Pokemon *mon); -void GiveBoxMonInitialMoveset_Fast(struct BoxPokemon *boxMon); u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove); void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move); void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move); diff --git a/include/test/battle.h b/include/test/battle.h index 62b0680486..c4bd89f91b 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -935,6 +935,8 @@ struct MoveContext // TODO: u8 zMove:1; u16 dynamax:1; u16 explicitDynamax:1; + u16 tera:1; + u16 explicitTera:1; u16 allowed:1; u16 explicitAllowed:1; u16 notExpected:1; // Has effect only with EXPECT_MOVE diff --git a/include/test/test.h b/include/test/test.h index 790563e772..dbd547ba9f 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -215,6 +215,8 @@ static inline struct Benchmark BenchmarkStop(void) #define PARAMETRIZE if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter) +#define PARAMETRIZE_LABEL(f, label) if (gFunctionTestRunnerState->parameters++ == gFunctionTestRunnerState->runParameter && (MgbaPrintf_(":N%s: " f " (%d/%d)", gTestRunnerState.test->name, label, gFunctionTestRunnerState->runParameter + 1, gFunctionTestRunnerState->parameters), 1)) + #define TO_DO \ do { \ Test_ExpectedResult(TEST_RESULT_TODO); \ diff --git a/migration_scripts/convert_partner_parties.py b/migration_scripts/convert_partner_parties.py new file mode 100644 index 0000000000..e726dcc723 --- /dev/null +++ b/migration_scripts/convert_partner_parties.py @@ -0,0 +1,319 @@ +# If you have extra members in 'TrainerMon': +# 1. Add a regular expression which matches that member (e.g. 'shadow_definition'). +# 2. Match that regular expression in 'convert' and write into 'attributes' with the key that 'trainerproc' should parse. +# 3. Add the key used in 'attributes' to 'pokemon_attribute_order'. +# 4. Update 'trainerproc.c' to parse the new key. + +import re +import sys + +is_blank = re.compile(r'^[ \t]*(//.*)?$') + +begin_party_definition = re.compile(r'struct TrainerMon (\w+)\[\] =') +end_party_definition = re.compile(r'^};') +begin_pokemon_definition = re.compile(r'^ { *$') +end_pokemon_definition = re.compile(r'^ },? *$') +level_definition = re.compile(r'\.lvl = (\d+)') +species_definition = re.compile(r'\.species = SPECIES_(\w+)') +gender_definition = re.compile(r'\.gender = TRAINER_MON_(\w+)') +nickname_definition = re.compile(r'\.nickname = COMPOUND_STRING\("([^"]+)"\)') +item_definition = re.compile(r'\.heldItem = ITEM_(\w+)') +ball_definition = re.compile(r'\.ball = ITEM_(\w+)') +ability_definition = re.compile(r'\.ability = ABILITY_(\w+)') +friendship_definition = re.compile(r'\.friendship = (\d+)') +shiny_definition = re.compile(r'\.isShiny = (\w+)') +ivs_definition = re.compile(r'\.iv = TRAINER_PARTY_IVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)') +evs_definition = re.compile(r'\.ev = TRAINER_PARTY_EVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)') +moves_definition = re.compile(r'\.moves = \{([^}]+)\}') +move_definition = re.compile(r'MOVE_(\w+)') +nature_definition = re.compile(r'\.nature = NATURE_(\w+)') + +# NOTE: These are just for aesthetics, the Pokemon would still compile +# without them. +species_replacements = { + "CHIEN_PAO": "Chien-Pao", + "CHI_YU": "Chi-Yu", + "HAKAMO_O": "Hakamo-o", + "HO_OH": "Ho-Oh", + "JANGMO_O": "Jangmo-o", + "KOMMO_O": "Kommo-o", + "PORYGON_Z": "Porygon-Z", + "ROTOM_": "Rotom-", + "TING_LU": "Ting-Lu", + "TYPE_NULL": "Type: Null", + "WO_CHIEN": "Wo-Chien", + + "_ALOLAN": "-Alola", + "_AQUA_BREED": "-Aqua", + "_BATTLE_BOND": "-Bond", + "_BLAZE_BREED": "-Blaze", + "_CAP": "", + "_CLOAK": "", + "_COMBAT_BREED": "-Combat", + "_CROWED_SHIELD": "-Crowned", + "_CROWED_SWORD": "-Crowned", + "_DRIVE": "", + "_EAST_SEA": "-East", + "_FAMILY_OF_FOUR": "-Four", + "_FEMALE": "-F", + "_FLOWER": "", + "_GALARIAN": "-Galar", + "_GIGANTAMAX": "-Gmax", + "_HISUIAN": "-Hisui", + "_ICE_RIDER": "-Ice", + "_NOICE_FACE": "-Noice", + "_ORIGIN": "-Origin", + "_ORIGINAL_COLOR": "-Original", + "_PALDEAN": "-Paldea", + "_PLUMAGE": "", + "_POKE_BALL": "-Pokeball", + "_SHADOW_RIDER": "-Shadow", + "_STRIKE_STYLE": "-Style", + "_TOTEM": "-Totem", + "_ZEN_MODE": "-Zen", +} + +pokemon_attribute_order = ['Level', 'Ability', 'IVs', 'EVs', 'Happiness', 'Shiny', 'Ball'] + +class Pokemon: + def __init__(self): + self.nickname = None + self.species = None + self.gender = None + self.item = None + self.nature = None + self.attributes = {} + self.attributes['IVs'] = "0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe" + self.moves = [] + +def convert_parties(in_path, in_h): + party_identifier = None + party = None + pokemon = None + parties = {} + + for line_no, line in enumerate(in_h, 1): + try: + line = line[:-1] + if m := begin_party_definition.search(line): + if party: + raise Exception(f"unexpected start of party") + [identifier] = m.groups() + party_identifier = identifier + party = [] + elif end_party_definition.search(line): + if not party: + raise Exception(f"unexpected end of party") + parties[party_identifier] = party + party = None + elif begin_pokemon_definition.search(line): + if pokemon: + raise Exception(f"unexpected start of Pokemon") + pokemon = Pokemon() + elif end_pokemon_definition.search(line): + if not pokemon: + raise Exception(f"unexpected end of Pokemon") + else: + party.append(pokemon) + pokemon = None + elif m := level_definition.search(line): + [level] = m.groups() + pokemon.attributes['Level'] = level + elif m := species_definition.search(line): + [species_] = m.groups() + for match, replacement in species_replacements.items(): + species_ = species_.replace(match, replacement) + pokemon.species = species_.replace("_", " ").title() + elif m := gender_definition.search(line): + [gender_] = m.groups() + if gender_ == 'MALE': + pokemon.gender = 'M' + elif gender_ == 'FEMALE': + pokemon.gender = 'F' + else: + raise Exception(f"unknown gender: '{gender_}'") + elif m := nickname_definition.search(line): + [nickname] = m.groups() + pokemon.nickname = nickname + elif m := item_definition.search(line): + [item_] = m.groups() + pokemon.item = item_.replace("_", " ").title() + elif m := ball_definition.search(line): + [ball] = m.groups() + pokemon.attributes['Ball'] = ball.replace("_", " ").title() + elif m := ability_definition.search(line): + [ability] = m.groups() + pokemon.attributes['Ability'] = ability.replace("_", " ").title() + elif m := friendship_definition.search(line): + [friendship] = m.groups() + pokemon.attributes['Happiness'] = friendship + elif m := shiny_definition.search(line): + [shiny] = m.groups() + if shiny == 'TRUE': + pokemon.attributes['Shiny'] = 'Yes' + elif shiny == 'FALSE': + pokemon.attributes['Shiny'] = 'No' + else: + raise Exception(f"unknown isShiny: '{shiny}'") + elif m := ivs_definition.search(line): + [hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()] + stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed} + pokemon.attributes['IVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items()) + elif m := evs_definition.search(line): + [hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()] + stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed} + pokemon.attributes['EVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items() if value != '0') + elif m := moves_definition.search(line): + [moves_] = m.groups() + pokemon.moves = [move.replace("_", " ").title() for move in move_definition.findall(moves_) if move != "NONE"] + elif m := nature_definition.search(line): + [nature_] = m.groups() + pokemon.nature = nature_.replace("_", " ").title() + elif is_blank.search(line): + pass + else: + raise Exception(f"could not parse '{line.strip()}'") + except Exception as e: + print(f"{in_path}:{line_no}: {e}") + return parties + +is_trainer_skip = re.compile(r'(const struct Trainer gBattlePartners\[\] = \{)|(^ \{$)|(\.partySize =)|(\.party = NULL)|(\.mugshotEnabled = TRUE)|(\};)') + +begin_trainer_definition = re.compile(r' \[(PARTNER_\w+)\] =') +end_trainer_definition = re.compile(r' }') +trainer_class_definition = re.compile(r'\.trainerClass = TRAINER_CLASS_(\w+)') +encounter_music_gender_definition = re.compile(r'\.encounterMusic_gender = (F_TRAINER_FEMALE \| )?TRAINER_ENCOUNTER_MUSIC_(\w+)') +trainer_pic_definition = re.compile(r'\.trainerPic = TRAINER_BACK_PIC_(\w+)') +trainer_name_definition = re.compile(r'\.trainerName = _\("([^"]*)"\)') +trainer_items_definition = re.compile(r'\.items = \{([^}]*)\}') +trainer_item_definition = re.compile(r'ITEM_(\w+)') +trainer_ai_flags_definition = re.compile(r'\.aiFlags = (.*)') +trainer_ai_flag_definition = re.compile(r'AI_FLAG_(\w+)') +trainer_party_definition = re.compile(r'\.party = TRAINER_PARTY\((\w+)\)') +trainer_mugshot_definition = re.compile(r'\.mugshotColor = MUGSHOT_COLOR_(\w+)') +trainer_starting_status_definition = re.compile(r'\.startingStatus = STARTING_STATUS_(\w+)') + +class_fixups = { + "Rs": "RS", +} + +pic_fixups = { + "Rs": "RS", +} + +class Trainer: + def __init__(self, id_): + self.id = id_ + self.class_ = None + self.encounter_music = None + self.gender = None + self.pic = None + self.name = None + self.items = [] + self.ai_flags = None + self.mugshot = None + self.starting_status = None + self.party = None + +def convert_trainers(in_path, in_h, parties, out_party): + newlines = 0 + trainer = None + for line_no, line in enumerate(in_h, 1): + try: + line = line[:-1] + if m := begin_trainer_definition.search(line): + if trainer: + raise Exception(f"unexpected start of trainer") + [id_] = m.groups() + trainer = Trainer(id_) + elif m := trainer_class_definition.search(line): + [class_] = m.groups() + class_ = class_.replace("_", " ").title() + for match, replacement in class_fixups.items(): + class_ = class_.replace(match, replacement) + trainer.class_ = class_ + elif m := encounter_music_gender_definition.search(line): + [is_female, music] = m.groups() + trainer.gender = 'Female' if is_female else 'Male' + trainer.encounter_music = music.replace("_", " ").title() + elif m := trainer_pic_definition.search(line): + [pic] = m.groups() + pic = pic.replace("_", " ").title() + for match, replacement in pic_fixups.items(): + pic = pic.replace(match, replacement) + trainer.pic = pic + elif m := trainer_name_definition.search(line): + [name] = m.groups() + trainer.name = name + elif m := trainer_items_definition.search(line): + [items] = m.groups() + trainer.items = " / ".join(item.replace("_", " ").title() for item in trainer_item_definition.findall(items) if item != "NONE") + elif m := trainer_ai_flags_definition.search(line): + [ai_flags] = m.groups() + trainer.ai_flags = " / ".join(ai_flag.replace("_", " ").title() for ai_flag in trainer_ai_flag_definition.findall(ai_flags)) + elif m := trainer_mugshot_definition.search(line): + [color] = m.groups() + trainer.mugshot = color.title() + elif m := trainer_starting_status_definition.search(line): + [starting_status] = m.groups() + trainer.starting_status = starting_status.replace("_", " ").title() + elif m := trainer_party_definition.search(line): + [party] = m.groups() + trainer.party = parties[party] + elif end_trainer_definition.search(line): + if not trainer: + raise Exception(f"unexpected end of trainer") + while newlines > 0: + out_party.write(f"\n") + newlines -= 1 + newlines = 1 + out_party.write(f"=== {trainer.id} ===\n") + out_party.write(f"Name: {trainer.name}\n") + out_party.write(f"Class: {trainer.class_}\n") + out_party.write(f"Pic: {trainer.pic}\n") + out_party.write(f"Gender: {trainer.gender}\n") + out_party.write(f"Music: {trainer.encounter_music}\n") + if trainer.items: + out_party.write(f"Items: {trainer.items}\n") + if trainer.ai_flags: + out_party.write(f"AI: {trainer.ai_flags}\n") + if trainer.mugshot: + out_party.write(f"Mugshot: {trainer.mugshot}\n") + if trainer.starting_status: + out_party.write(f"Starting Status: {trainer.starting_status}\n") + if trainer.party: + for i, pokemon in enumerate(trainer.party): + out_party.write(f"\n") + if pokemon.nickname: + out_party.write(f"{pokemon.nickname} ({pokemon.species})") + else: + out_party.write(f"{pokemon.species}") + if pokemon.gender: + out_party.write(f" ({pokemon.gender})") + if pokemon.item and pokemon.item != 'None': + out_party.write(f" @ {pokemon.item}") + out_party.write(f"\n") + if pokemon.nature: + out_party.write(f"{pokemon.nature} Nature\n") + for key in pokemon_attribute_order: + if key in pokemon.attributes: + out_party.write(f"{key}: {pokemon.attributes[key]}\n") + for move in pokemon.moves: + out_party.write(f"- {move}\n") + trainer = None + elif is_blank.search(line) or is_trainer_skip.search(line): + pass + else: + raise Exception(f"could not parse '{line.strip()}'") + except Exception as e: + print(f"{in_path}:{line_no}: {e}") + +if __name__ == '__main__': + try: + [argv0, trainers_in_path, parties_in_path, out_path] = sys.argv + except: + print(f"usage: python3 {sys.argv[0]} ") + else: + with open(trainers_in_path, "r") as trainers_in_h, open(parties_in_path, "r") as parties_in_h, open(out_path, "w") as out_party: + parties = convert_parties(parties_in_path, parties_in_h) + trainers = convert_trainers(trainers_in_path, trainers_in_h, parties, out_party) diff --git a/migration_scripts/convert_parties.py b/migration_scripts/convert_trainer_parties.py similarity index 100% rename from migration_scripts/convert_parties.py rename to migration_scripts/convert_trainer_parties.py diff --git a/src/battle_ai_main.c b/src/battle_ai_main.c index 3d1c7e934b..da8b3764a3 100644 --- a/src/battle_ai_main.c +++ b/src/battle_ai_main.c @@ -9,6 +9,7 @@ #include "battle_factory.h" #include "battle_setup.h" #include "battle_z_move.h" +#include "battle_terastal.h" #include "data.h" #include "debug.h" #include "event_data.h" @@ -398,6 +399,23 @@ static void SetBattlerAiData(u32 battler, struct AiLogicData *aiData) aiData->speedStats[battler] = GetBattlerTotalSpeedStatArgs(battler, ability, holdEffect); } +static void SetBattlerAiGimmickData(u32 battler, struct AiLogicData *aiData) +{ + bool32 isSecondTrainer = (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT; + u16 trainerId = isSecondTrainer ? gTrainerBattleOpponent_B : gTrainerBattleOpponent_A; + const struct TrainerMon *party = GetTrainerPartyFromId(trainerId); + if (party != NULL) + { + aiData->shouldDynamax[battler] = CanDynamax(battler) && (party[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]].shouldDynamax); + aiData->shouldTerastal[battler] = CanTerastallize(battler) && (party[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]].shouldTerastal); + } + else + { + aiData->shouldDynamax[battler] = FALSE; + aiData->shouldTerastal[battler] = FALSE; + } +} + static u32 Ai_SetMoveAccuracy(struct AiLogicData *aiData, u32 battlerAtk, u32 battlerDef, u32 move) { u32 accuracy; @@ -467,6 +485,7 @@ void SetAiLogicDataForTurn(struct AiLogicData *aiData) continue; SetBattlerAiData(battlerAtk, aiData); + SetBattlerAiGimmickData(battlerAtk, aiData); SetBattlerAiMovesData(aiData, battlerAtk, battlersCount); } } @@ -2367,20 +2386,20 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_SOAK: if (PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) - || (GetBattlerType(battlerDef, 0) == TYPE_WATER - && GetBattlerType(battlerDef, 1) == TYPE_WATER - && GetBattlerType(battlerDef, 2) == TYPE_MYSTERY)) + || (GetBattlerType(battlerDef, 0, FALSE) == TYPE_WATER + && GetBattlerType(battlerDef, 1, FALSE) == TYPE_WATER + && GetBattlerType(battlerDef, 2, FALSE) == TYPE_MYSTERY)) ADJUST_SCORE(-10); // target is already water-only break; case EFFECT_THIRD_TYPE: switch (move) { case MOVE_TRICK_OR_TREAT: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GHOST) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) || IsTerastallized(battlerDef)) ADJUST_SCORE(-10); break; case MOVE_FORESTS_CURSE: - if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove)) + if (IS_BATTLER_OF_TYPE(battlerDef, TYPE_GRASS) || PartnerMoveIsSameAsAttacker(BATTLE_PARTNER(battlerAtk), battlerDef, move, aiData->partnerMove) || IsTerastallized(battlerDef)) ADJUST_SCORE(-10); break; } @@ -2514,9 +2533,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) case EFFECT_SYNCHRONOISE: //Check holding ring target or is of same type if (aiData->holdEffects[battlerDef] == HOLD_EFFECT_RING_TARGET - || IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 0)) - || IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 1)) - || IS_BATTLER_OF_TYPE(battlerDef, GetBattlerType(battlerAtk, 2))) + || DoBattlersShareType(battlerAtk, battlerDef)) break; else ADJUST_SCORE(-10); @@ -2940,9 +2957,8 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score) break; case EFFECT_SOAK: if (atkPartnerAbility == ABILITY_WONDER_GUARD - && (GetBattlerType(battlerAtkPartner, 0) != TYPE_WATER - || GetBattlerType(battlerAtkPartner, 1) != TYPE_WATER - || GetBattlerType(battlerAtkPartner, 2) != TYPE_WATER)) + && IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_WATER) + && !IsTerastallized(battlerAtkPartner)) { RETURN_SCORE_PLUS(WEAK_EFFECT); } diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index f08251e2a5..273fb2c998 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -1535,7 +1535,7 @@ static u32 GetSwitchinHitsToKO(s32 damageTaken, u32 battler) s32 currentHP = startingHP; // No damage being dealt - if ((damageTaken + statusDamage + recurringDamage < recurringHealing) || damageTaken + statusDamage + recurringDamage == 0) + if ((damageTaken + statusDamage + recurringDamage <= recurringHealing) || damageTaken + statusDamage + recurringDamage == 0) return startingHP; // Mon fainted to hazards diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index 40f3da2b5a..18dd3fc0c7 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -366,7 +366,7 @@ static inline s32 LowestRollDmg(s32 dmg) return dmg; } -bool32 IsDamageMoveUsable(u32 move, u32 battlerAtk, u32 battlerDef) +bool32 IsDamageMoveUnusable(u32 move, u32 battlerAtk, u32 battlerDef) { s32 moveType; struct AiLogicData *aiData = AI_DATA; @@ -438,6 +438,10 @@ bool32 IsDamageMoveUsable(u32 move, u32 battlerAtk, u32 battlerDef) if (!IS_BATTLER_OF_TYPE(battlerAtk, gMovesInfo[move].argument)) return TRUE; break; + case EFFECT_HIT_SET_REMOVE_TERRAIN: + if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_ANY) && gMovesInfo[move].argument == ARG_TRY_REMOVE_TERRAIN_FAIL) + return TRUE; + break; } return FALSE; @@ -448,14 +452,16 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes s32 dmg, moveType; uq4_12_t effectivenessMultiplier; bool32 isDamageMoveUnusable = FALSE; + bool32 toggledDynamax = FALSE; + bool32 toggledTera = FALSE; struct AiLogicData *aiData = AI_DATA; SetBattlerData(battlerAtk); SetBattlerData(battlerDef); + // Temporarily enable Z-Moves for damage calcs if (considerZPower && IsViableZMove(battlerAtk, move)) { - //temporarily enable z moves for damage calcs gBattleStruct->zmove.baseMoves[battlerAtk] = move; gBattleStruct->zmove.active = TRUE; } @@ -465,6 +471,18 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes if (gMovesInfo[move].effect == EFFECT_NATURE_POWER) move = GetNaturePowerMove(); + // Temporarily enable other gimmicks for damage calcs if planned + if (AI_DATA->shouldDynamax[battlerAtk]) + { + toggledDynamax = TRUE; + gBattleStruct->dynamax.dynamaxed[battlerAtk] = TRUE; + } + if (AI_DATA->shouldTerastal[battlerAtk]) + { + toggledTera = TRUE; + gBattleStruct->tera.isTerastallized[GetBattlerSide(battlerAtk)] |= gBitTable[gBattlerPartyIndexes[battlerAtk]]; + } + gBattleStruct->dynamicMoveType = 0; @@ -472,7 +490,7 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes GET_MOVE_TYPE(move, moveType); if (gMovesInfo[move].power) - isDamageMoveUnusable = IsDamageMoveUsable(move, battlerAtk, battlerDef); + isDamageMoveUnusable = IsDamageMoveUnusable(move, battlerAtk, battlerDef); effectivenessMultiplier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, aiData->abilities[battlerDef], FALSE); if (gMovesInfo[move].power && !isDamageMoveUnusable) @@ -582,6 +600,10 @@ s32 AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u8 *typeEffectivenes gBattleStruct->swapDamageCategory = FALSE; gBattleStruct->zmove.active = FALSE; gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE; + if (toggledDynamax) + gBattleStruct->dynamax.dynamaxed[battlerAtk] = FALSE; + if (toggledTera) + gBattleStruct->tera.isTerastallized[GetBattlerSide(battlerAtk)] &= ~(gBitTable[gBattlerPartyIndexes[battlerAtk]]); return dmg; } diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index abcdd44c35..7ce0e0c36c 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -6523,6 +6523,11 @@ void PrepareDoubleTeamAnim(u32 taskId, u32 animBattler, bool32 forAllySwitch) gSprites[spriteId].sBattlerFlank = (animBattler != ANIM_ATTACKER); else gSprites[spriteId].sBattlerFlank = (animBattler == ANIM_ATTACKER); + + // correct direction on opponent side + if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT) + gSprites[spriteId].sBattlerFlank ^= 1; + gSprites[spriteId].callback = AnimDoubleTeam; task->tBlendSpritesCount++; } @@ -6548,11 +6553,21 @@ static inline void SwapStructData(void *s1, void *s2, void *data, u32 size) static void ReloadBattlerSprites(u32 battler, struct Pokemon *party) { - BattleLoadMonSpriteGfx(&party[gBattlerPartyIndexes[battler]], battler); + struct Pokemon *mon = &party[gBattlerPartyIndexes[battler]]; + BattleLoadMonSpriteGfx(mon, battler); CreateBattlerSprite(battler); - UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &party[gBattlerPartyIndexes[battler]], HEALTHBOX_ALL); + UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL); // If battler is mega evolved / primal reversed, hide the sprite until the move animation finishes. MegaIndicator_SetVisibilities(gHealthboxSpriteIds[battler], TRUE); + + // Try to recreate shadow sprite + if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId < MAX_SPRITES) + { + DestroySprite(&gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId]); + gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId = MAX_SPRITES; + CreateEnemyShadowSprite(battler); + SetBattlerShadowSpriteCallback(battler, GetMonData(mon, MON_DATA_SPECIES)); + } } static void AnimTask_AllySwitchDataSwap(u8 taskId) diff --git a/src/battle_controller_opponent.c b/src/battle_controller_opponent.c index 597d0b7c5f..1622b94e9d 100644 --- a/src/battle_controller_opponent.c +++ b/src/battle_controller_opponent.c @@ -544,13 +544,6 @@ static void OpponentHandleChooseMove(u32 battler) default: { u16 chosenMove = moveInfo->moves[chosenMoveId]; - bool32 isSecondTrainer = (GetBattlerPosition(battler) == B_POSITION_OPPONENT_RIGHT) && (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && !BATTLE_TWO_VS_ONE_OPPONENT; - u16 trainerId = isSecondTrainer ? gTrainerBattleOpponent_B : gTrainerBattleOpponent_A; - const struct TrainerMon *party = GetTrainerPartyFromId(trainerId); - bool32 shouldDynamax = FALSE; - if (party != NULL) - shouldDynamax = party[isSecondTrainer ? gBattlerPartyIndexes[battler] - MULTI_PARTY_SIZE : gBattlerPartyIndexes[battler]].shouldDynamax; - if (GetBattlerMoveTargetType(battler, chosenMove) & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER)) gBattlerTarget = battler; if (GetBattlerMoveTargetType(battler, chosenMove) & MOVE_TARGET_BOTH) @@ -568,8 +561,11 @@ static void OpponentHandleChooseMove(u32 battler) else if (CanUltraBurst(battler)) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_ULTRA_BURST) | (gBattlerTarget << 8)); // If opponent can Dynamax and is allowed in the partydata, do it. - else if (CanDynamax(battler) && shouldDynamax) + else if (CanDynamax(battler) && AI_DATA->shouldDynamax[battler]) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_DYNAMAX) | (gBattlerTarget << 8)); + // If opponent can Terastal and is allowed in the partydata, do it. + else if (CanTerastallize(battler) && AI_DATA->shouldTerastal[battler]) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (RET_TERASTAL) | (gBattlerTarget << 8)); else BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, (chosenMoveId) | (gBattlerTarget << 8)); } diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index d6bd7fa7ac..8feee4c172 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -455,6 +455,8 @@ static void HandleInputChooseTarget(u32 battler) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8)); else if (gBattleStruct->dynamax.playerSelect) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8)); + else if (gBattleStruct->tera.playerSelect) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_TERASTAL | (gMultiUsePlayerCursor << 8)); else BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8)); EndBounceEffect(gMultiUsePlayerCursor, BOUNCE_HEALTHBOX); @@ -617,6 +619,8 @@ static void HandleInputShowEntireFieldTargets(u32 battler) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8)); else if (gBattleStruct->dynamax.playerSelect) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8)); + else if (gBattleStruct->tera.playerSelect) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_TERASTAL | (gMultiUsePlayerCursor << 8)); else BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8)); HideTriggerSprites(); @@ -649,6 +653,8 @@ static void HandleInputShowTargets(u32 battler) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8)); else if (gBattleStruct->dynamax.playerSelect) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8)); + else if (gBattleStruct->tera.playerSelect) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_TERASTAL | (gMultiUsePlayerCursor << 8)); else BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8)); HideTriggerSprites(); @@ -688,17 +694,8 @@ static void HandleInputChooseMove(u32 battler) if (JOY_NEW(A_BUTTON)) { PlaySE(SE_SELECT); - if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_CURSE) - { - if (moveInfo->monType1 != TYPE_GHOST && moveInfo->monType2 != TYPE_GHOST && moveInfo->monType3 != TYPE_GHOST) - moveTarget = MOVE_TARGET_USER; - else - moveTarget = MOVE_TARGET_SELECTED; - } - else - { - moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[gMoveSelectionCursor[battler]]); - } + + moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[gMoveSelectionCursor[battler]]); if (gBattleStruct->zmove.viewing) { @@ -773,6 +770,8 @@ static void HandleInputChooseMove(u32 battler) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_ULTRA_BURST | (gMultiUsePlayerCursor << 8)); else if (gBattleStruct->dynamax.playerSelect) BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_DYNAMAX | (gMultiUsePlayerCursor << 8)); + else if (gBattleStruct->tera.playerSelect) + BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | RET_TERASTAL | (gMultiUsePlayerCursor << 8)); else BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, gMoveSelectionCursor[battler] | (gMultiUsePlayerCursor << 8)); HideTriggerSprites(); @@ -811,6 +810,7 @@ static void HandleInputChooseMove(u32 battler) gBattleStruct->mega.playerSelect = FALSE; gBattleStruct->burst.playerSelect = FALSE; gBattleStruct->dynamax.playerSelect = FALSE; + gBattleStruct->tera.playerSelect = FALSE; gBattleStruct->zmove.viable = FALSE; BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, 0xFFFF); HideTriggerSprites(); @@ -919,6 +919,13 @@ static void HandleInputChooseMove(u32 battler) ChangeDynamaxTriggerSprite(gBattleStruct->dynamax.triggerSpriteId, gBattleStruct->dynamax.playerSelect); PlaySE(SE_SELECT); } + else if (CanTerastallize(battler)) + { + gBattleStruct->tera.playerSelect ^= 1; + ChangeTeraTriggerSprite(gBattleStruct->tera.triggerSpriteId, gBattleStruct->tera.playerSelect); + MoveSelectionDisplayMoveType(battler); // For Tera Blast / Tera Starstorm + PlaySE(SE_SELECT); + } } } @@ -927,6 +934,7 @@ static void ReloadMoveNames(u32 battler) gBattleStruct->mega.playerSelect = FALSE; gBattleStruct->burst.playerSelect = FALSE; gBattleStruct->dynamax.playerSelect = FALSE; + gBattleStruct->tera.playerSelect = FALSE; gBattleStruct->zmove.viewing = FALSE; MoveSelectionDestroyCursorAt(battler); MoveSelectionDisplayMoveNames(battler); @@ -1730,33 +1738,38 @@ static void MoveSelectionDisplayPpNumber(u32 battler) static void MoveSelectionDisplayMoveType(u32 battler) { - u8 *txtPtr; + u8 *txtPtr, *end; u8 type; u32 speciesId; - struct Pokemon *mon; struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]); txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType); - *(txtPtr)++ = EXT_CTRL_CODE_BEGIN; - *(txtPtr)++ = EXT_CTRL_CODE_FONT; - *(txtPtr)++ = FONT_NORMAL; - if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_IVY_CUDGEL) + type = gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].type; + + if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_BLAST) { - mon = &GetSideParty(GetBattlerSide(battler))[gBattlerPartyIndexes[battler]]; - speciesId = GetMonData(mon, MON_DATA_SPECIES); + if (gBattleStruct->tera.playerSelect || IsTerastallized(battler)) + type = GetBattlerTeraType(battler); + } + else if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_IVY_CUDGEL) + { + speciesId = gBattleMons[battler].species; if (speciesId == SPECIES_OGERPON_WELLSPRING_MASK || speciesId == SPECIES_OGERPON_WELLSPRING_MASK_TERA || speciesId == SPECIES_OGERPON_HEARTHFLAME_MASK || speciesId == SPECIES_OGERPON_HEARTHFLAME_MASK_TERA || speciesId == SPECIES_OGERPON_CORNERSTONE_MASK || speciesId == SPECIES_OGERPON_CORNERSTONE_MASK_TERA) type = gBattleMons[battler].type2; - else - type = gMovesInfo[MOVE_IVY_CUDGEL].type; } - else - type = gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].type; + else if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_STARSTORM) + { + if (gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR + || (gBattleStruct->tera.playerSelect && gBattleMons[battler].species == SPECIES_TERAPAGOS_TERASTAL)) + type = TYPE_STELLAR; + } - StringCopy(txtPtr, gTypesInfo[type].name); + end = StringCopy(txtPtr, gTypesInfo[type].name); + PrependFontIdToFit(txtPtr, end, FONT_NORMAL, WindowWidthPx(B_WIN_MOVE_TYPE) - 25); BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_TYPE); } @@ -2060,6 +2073,7 @@ static void PlayerHandleChooseMove(u32 battler) gBattleStruct->mega.playerSelect = FALSE; gBattleStruct->burst.playerSelect = FALSE; gBattleStruct->dynamax.playerSelect = FALSE; + gBattleStruct->tera.playerSelect = FALSE; if (!IsMegaTriggerSpriteActive()) gBattleStruct->mega.triggerSpriteId = 0xFF; if (CanMegaEvolve(battler)) @@ -2074,6 +2088,10 @@ static void PlayerHandleChooseMove(u32 battler) CreateDynamaxTriggerSprite(battler, 0); if (!IsZMoveTriggerSpriteActive()) gBattleStruct->zmove.triggerSpriteId = 0xFF; + if (!IsTeraTriggerSpriteActive()) + gBattleStruct->tera.triggerSpriteId = 0xFF; + if (CanTerastallize(battler)) + CreateTeraTriggerSprite(battler, 0); GetUsableZMoves(battler, moveInfo->moves); gBattleStruct->zmove.viable = IsZMoveUsable(battler, gMoveSelectionCursor[battler]); diff --git a/src/battle_dome.c b/src/battle_dome.c index 95490a54ea..ca105beb17 100644 --- a/src/battle_dome.c +++ b/src/battle_dome.c @@ -4256,6 +4256,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId) textPrinter.currentChar = GetSpeciesName(DOME_MONS[trainerTourneyId][i]); else textPrinter.currentChar = GetSpeciesName(gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].species); + textPrinter.fontId = GetFontIdToFit(textPrinter.currentChar, FONT_SHORT, 0, 60); textPrinter.windowId = WIN_TRAINER_MON1_NAME + i + windowId; if (i == 1) @@ -4267,6 +4268,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId) CopyWindowToVram(WIN_TRAINER_MON1_NAME + i + windowId, COPYWIN_FULL); AddTextPrinter(&textPrinter, 0, NULL); } + textPrinter.fontId = FONT_SHORT; PutWindowTilemap(windowId + WIN_TRAINER_FLAVOR_TEXT); CopyWindowToVram(windowId + WIN_TRAINER_FLAVOR_TEXT, COPYWIN_FULL); diff --git a/src/battle_gfx_sfx_util.c b/src/battle_gfx_sfx_util.c index 09b85e7768..8cc5afb424 100644 --- a/src/battle_gfx_sfx_util.c +++ b/src/battle_gfx_sfx_util.c @@ -263,17 +263,7 @@ u16 ChooseMoveAndTargetInBattlePalace(u32 battler) } } - if (moveInfo->moves[chosenMoveId] == MOVE_CURSE) - { - if (moveInfo->monType1 != TYPE_GHOST && moveInfo->monType2 != TYPE_GHOST && moveInfo->monType3 != TYPE_GHOST) - moveTarget = MOVE_TARGET_USER; - else - moveTarget = MOVE_TARGET_SELECTED; - } - else - { - moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveId]); - } + moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[chosenMoveId]); if (moveTarget & MOVE_TARGET_USER) chosenMoveId |= (battler << 8); @@ -645,6 +635,13 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler) BlendPalette(paletteOffset, 16, 4, RGB(31, 0, 12)); CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16)); } + + // Terastallization's tint + if (IsTerastallized(battler)) + { + BlendPalette(paletteOffset, 16, 8, GetTeraTypeRGB(GetBattlerTeraType(battler))); + CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16)); + } } void BattleGfxSfxDummy2(u16 species) @@ -710,6 +707,7 @@ bool8 BattleLoadAllHealthBoxesGfx(u8 state) LoadSpritePalette(&sSpritePalettes_HealthBoxHealthBar[0]); LoadSpritePalette(&sSpritePalettes_HealthBoxHealthBar[1]); MegaIndicator_LoadSpritesGfx(); + TeraIndicator_LoadSpriteGfx(); } else if (!IsDoubleBattle()) { @@ -1100,27 +1098,36 @@ void SetBattlerSpriteAffineMode(u8 affineMode) #define tBattlerId data[0] -void LoadAndCreateEnemyShadowSprites(void) +void CreateEnemyShadowSprite(u32 battler) { - u8 battler; - - LoadCompressedSpriteSheet(&gSpriteSheet_EnemyShadow); - - battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId = CreateSprite(&gSpriteTemplate_EnemyShadow, GetBattlerSpriteCoord(battler, BATTLER_COORD_X), GetBattlerSpriteCoord(battler, BATTLER_COORD_Y) + 29, 0xC8); - gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId].data[0] = battler; + if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId < MAX_SPRITES) + gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId].data[0] = battler; +} +void LoadAndCreateEnemyShadowSprites(void) +{ + u8 battler; + u32 i; + + LoadCompressedSpriteSheet(&gSpriteSheet_EnemyShadow); + + // initialize shadow sprite ids + for (i = 0; i < gBattlersCount; i++) + { + gBattleSpritesDataPtr->healthBoxesData[i].shadowSpriteId = MAX_SPRITES; + } + + battler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + CreateEnemyShadowSprite(battler); + if (IsDoubleBattle()) { battler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); - gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId = CreateSprite(&gSpriteTemplate_EnemyShadow, - GetBattlerSpriteCoord(battler, BATTLER_COORD_X), - GetBattlerSpriteCoord(battler, BATTLER_COORD_Y) + 29, - 0xC8); - gSprites[gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId].data[0] = battler; + CreateEnemyShadowSprite(battler); } } @@ -1161,6 +1168,8 @@ void SetBattlerShadowSpriteCallback(u8 battler, u16 species) // The player's shadow is never seen. if (GetBattlerSide(battler) == B_SIDE_PLAYER || gBattleScripting.monCaught) return; + if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId >= MAX_SPRITES) + return; if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies != SPECIES_NONE) species = gBattleSpritesDataPtr->battlerData[battler].transformSpecies; diff --git a/src/battle_interface.c b/src/battle_interface.c index 34cdec6e5c..4ae7726d14 100644 --- a/src/battle_interface.c +++ b/src/battle_interface.c @@ -172,6 +172,7 @@ enum static const u8 *GetHealthboxElementGfxPtr(u8); static u8 *AddTextPrinterAndCreateWindowOnHealthbox(const u8 *, u32, u32, u32, u32 *); +static u8 *AddTextPrinterAndCreateWindowOnHealthboxToFit(const u8 *, u32, u32, u32, u32 *, u32); static void RemoveWindowOnHealthbox(u32 windowId); static void UpdateHpTextInHealthboxInDoubles(u32 healthboxSpriteId, u32 maxOrCurrent, s16 currHp, s16 maxHp); @@ -854,6 +855,9 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId) // Create mega indicator sprite. MegaIndicator_CreateSprite(battlerId, healthboxLeftSpriteId); + // Create tera indicator sprites. + TeraIndicator_CreateSprite(battlerId, healthboxLeftSpriteId); + gBattleStruct->ballSpriteIds[0] = MAX_SPRITES; gBattleStruct->ballSpriteIds[1] = MAX_SPRITES; @@ -937,6 +941,7 @@ void SetHealthboxSpriteInvisible(u8 healthboxSpriteId) gSprites[gSprites[healthboxSpriteId].hMain_HealthBarSpriteId].invisible = TRUE; gSprites[gSprites[healthboxSpriteId].oam.affineParam].invisible = TRUE; MegaIndicator_SetVisibilities(healthboxSpriteId, TRUE); + TeraIndicator_SetVisibilities(healthboxSpriteId, TRUE); } void SetHealthboxSpriteVisible(u8 healthboxSpriteId) @@ -945,6 +950,7 @@ void SetHealthboxSpriteVisible(u8 healthboxSpriteId) gSprites[gSprites[healthboxSpriteId].hMain_HealthBarSpriteId].invisible = FALSE; gSprites[gSprites[healthboxSpriteId].oam.affineParam].invisible = FALSE; MegaIndicator_SetVisibilities(healthboxSpriteId, FALSE); + TeraIndicator_SetVisibilities(healthboxSpriteId, FALSE); } static void UpdateSpritePos(u8 spriteId, s16 x, s16 y) @@ -971,6 +977,7 @@ static void TryToggleHealboxVisibility(u32 priority, u32 healthboxLeftSpriteId, gSprites[healthboxRightSpriteId].invisible = invisible; gSprites[healthbarSpriteId].invisible = invisible; MegaIndicator_SetVisibilities(healthboxLeftSpriteId, invisible); + TeraIndicator_SetVisibilities(healthboxLeftSpriteId, invisible); } void UpdateOamPriorityInAllHealthboxes(u8 priority, bool32 hideHPBoxes) @@ -988,6 +995,7 @@ void UpdateOamPriorityInAllHealthboxes(u8 priority, bool32 hideHPBoxes) gSprites[healthbarSpriteId].oam.priority = priority; MegaIndicator_UpdateOamPriority(healthboxLeftSpriteId, priority); + TeraIndicator_UpdateOamPriorities(healthboxLeftSpriteId, priority); if (B_HIDE_HEALTHBOX_IN_ANIMS == TRUE && hideHPBoxes && IsBattlerAlive(i)) TryToggleHealboxVisibility(priority, healthboxLeftSpriteId, healthboxRightSpriteId, healthbarSpriteId); @@ -1050,6 +1058,13 @@ static void UpdateLvlInHealthbox(u8 healthboxSpriteId, u8 lvl) MegaIndicator_UpdateLevel(healthboxSpriteId, lvl); MegaIndicator_SetVisibilities(healthboxSpriteId, FALSE); } + else if (IsTerastallized(battler)) + { + objVram = ConvertIntToDecimalStringN(text, lvl, STR_CONV_MODE_LEFT_ALIGN, 3); + xPos = 5 * (3 - (objVram - (text + 2))) - 1; + TeraIndicator_UpdateLevel(healthboxSpriteId, lvl); + TeraIndicator_SetVisibilities(healthboxSpriteId, FALSE); + } else { text[0] = CHAR_EXTRA_SYMBOL; @@ -1473,6 +1488,7 @@ void HideTriggerSprites(void) HideBurstTriggerSprite(); HideZMoveTriggerSprite(); HideDynamaxTriggerSprite(); + HideTeraTriggerSprite(); } void DestroyMegaTriggerSprite(void) @@ -2281,24 +2297,21 @@ static void UpdateNickInHealthbox(u8 healthboxSpriteId, struct Pokemon *mon) if ((species == SPECIES_NIDORAN_F || species == SPECIES_NIDORAN_M) && StringCompare(nickname, GetSpeciesName(species)) == 0) gender = 100; - // AddTextPrinterAndCreateWindowOnHealthbox's arguments are the same in all 3 cases. - // It's possible they may have been different in early development phases. switch (gender) { default: StringCopy(ptr, gText_HealthboxGender_None); - windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId); break; case MON_MALE: StringCopy(ptr, gText_HealthboxGender_Male); - windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId); break; case MON_FEMALE: StringCopy(ptr, gText_HealthboxGender_Female); - windowTileData = AddTextPrinterAndCreateWindowOnHealthbox(gDisplayedStringBattle, 0, 3, 2, &windowId); break; } + windowTileData = AddTextPrinterAndCreateWindowOnHealthboxToFit(gDisplayedStringBattle, 0, 3, 2, &windowId, 54); + spriteTileNum = gSprites[healthboxSpriteId].oam.tileNum * TILE_SIZE_4BPP; if (GetBattlerSide(gSprites[healthboxSpriteId].data[6]) == B_SIDE_PLAYER) @@ -2532,6 +2545,10 @@ void UpdateHealthboxAttribute(u8 healthboxSpriteId, struct Pokemon *mon, u8 elem u32 battlerId = gSprites[healthboxSpriteId].hMain_Battler; s32 maxHp = GetMonData(mon, MON_DATA_MAX_HP); s32 currHp = GetMonData(mon, MON_DATA_HP); + + // This fixes a bug that should likely never happen involving switching between two Teras. + if (elementId == HEALTHBOX_ALL) + TeraIndicator_UpdateType(battlerId, healthboxSpriteId); if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) { @@ -2887,7 +2904,7 @@ u8 GetHPBarLevel(s16 hp, s16 maxhp) return result; } -static u8 *AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 bgColor, u32 *windowId) +static u8 *AddTextPrinterAndCreateWindowOnHealthboxWithFont(const u8 *str, u32 x, u32 y, u32 bgColor, u32 *windowId, u32 fontId) { u16 winId; u8 color[3]; @@ -2900,12 +2917,23 @@ static u8 *AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, color[1] = 1; color[2] = 3; - AddTextPrinterParameterized4(winId, FONT_SMALL, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); + AddTextPrinterParameterized4(winId, fontId, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); *windowId = winId; return (u8 *)(GetWindowAttribute(winId, WINDOW_TILE_DATA)); } +static u8 *AddTextPrinterAndCreateWindowOnHealthbox(const u8 *str, u32 x, u32 y, u32 bgColor, u32 *windowId) +{ + return AddTextPrinterAndCreateWindowOnHealthboxWithFont(str, x, y, bgColor, windowId, FONT_SMALL); +} + +static u8 *AddTextPrinterAndCreateWindowOnHealthboxToFit(const u8 *str, u32 x, u32 y, u32 bgColor, u32 *windowId, u32 width) +{ + u32 fontId = GetFontIdToFit(str, FONT_SMALL, 0, width); + return AddTextPrinterAndCreateWindowOnHealthboxWithFont(str, x, y, bgColor, windowId, fontId); +} + static void RemoveWindowOnHealthbox(u32 windowId) { RemoveWindow(windowId); @@ -3010,6 +3038,7 @@ static const s16 sAbilityPopUpCoordsSingles[MAX_BATTLERS_COUNT][2] = static u8* AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 y, u32 color1, u32 color2, u32 color3, u32 *windowId) { + u32 fontId; u8 color[3] = {color1, color2, color3}; struct WindowTemplate winTemplate = {0}; winTemplate.width = POPUP_WINDOW_WIDTH; @@ -3018,7 +3047,8 @@ static u8* AddTextPrinterAndCreateWindowOnAbilityPopUp(const u8 *str, u32 x, u32 *windowId = AddWindow(&winTemplate); FillWindowPixelBuffer(*windowId, PIXEL_FILL(color1)); - AddTextPrinterParameterized4(*windowId, FONT_SMALL, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); + fontId = GetFontIdToFit(str, FONT_SMALL, 0, 76); + AddTextPrinterParameterized4(*windowId, fontId, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); return (u8 *)(GetWindowAttribute(*windowId, WINDOW_TILE_DATA)); } @@ -3114,6 +3144,7 @@ static void PrintBattlerOnAbilityPopUp(u8 battlerId, u8 spriteId1, u8 spriteId2) static void PrintAbilityOnAbilityPopUp(u32 ability, u8 spriteId1, u8 spriteId2) { + ClearAbilityName(spriteId1, spriteId2); PrintOnAbilityPopUp(gAbilitiesInfo[ability].name, (void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32) + 256, (void*)(OBJ_VRAM0) + (gSprites[spriteId2].oam.tileNum * 32) + 256, @@ -3243,6 +3274,9 @@ void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) if (B_ABILITY_POP_UP == FALSE) return; + if (gBattleScripting.abilityPopupOverwrite != 0) + ability = gBattleScripting.abilityPopupOverwrite; + if (gTestRunnerEnabled) { TestRunner_Battle_RecordAbilityPopUp(battlerId, ability); @@ -3250,9 +3284,6 @@ void CreateAbilityPopUp(u8 battlerId, u32 ability, bool32 isDoubleBattle) return; } - if (gBattleScripting.abilityPopupOverwrite != 0) - ability = gBattleScripting.abilityPopupOverwrite; - if (!gBattleStruct->activeAbilityPopUps) { LoadSpriteSheet(&sSpriteSheet_AbilityPopUp); @@ -3320,7 +3351,6 @@ void UpdateAbilityPopup(u8 battlerId) u8 spriteId2 = gBattleStruct->abilityPopUpSpriteIds[battlerId][1]; u16 ability = (gBattleScripting.abilityPopupOverwrite != 0) ? gBattleScripting.abilityPopupOverwrite : gBattleMons[battlerId].ability; - ClearAbilityName(spriteId1, spriteId2); PrintAbilityOnAbilityPopUp(ability, spriteId1, spriteId2); RestoreOverwrittenPixels((void*)(OBJ_VRAM0) + (gSprites[spriteId1].oam.tileNum * 32)); } diff --git a/src/battle_main.c b/src/battle_main.c index fd652f22c0..a9ccc6e0aa 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -295,6 +295,12 @@ const struct OamData gOamData_BattleSpritePlayerSide = static const s8 sCenterToCornerVecXs[8] ={-32, -16, -16, -32, -32}; +#if B_EXPANDED_TYPE_NAMES == TRUE +#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__)) +#else +#define HANDLE_EXPANDED_TYPE_NAME(_name, ...) _(_name) +#endif + // .generic is large enough that the text for TYPE_ELECTRIC will exceed TEXT_BUFF_ARRAY_COUNT. const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = { @@ -305,6 +311,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 13, .zMove = MOVE_BREAKNECK_BLITZ, .maxMove = MOVE_MAX_STRIKE, + .paletteTMHM = gItemIconPalette_NormalTMHM, //.enhanceItem = ITEM_SILK_SCARF, //.berry = ITEM_CHILAN_BERRY, //.gem = ITEM_NORMAL_GEM, @@ -314,11 +321,12 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = }, [TYPE_FIGHTING] = { - .name = _("Fight"), + .name = HANDLE_EXPANDED_TYPE_NAME("Fight", "Fighting"), .generic = _("a FIGHTING move"), .palette = 13, .zMove = MOVE_ALL_OUT_PUMMELING, .maxMove = MOVE_MAX_KNUCKLE, + .paletteTMHM = gItemIconPalette_FightingTMHM, //.enhanceItem = ITEM_BLACK_BELT, //.berry = ITEM_CHOPLE_BERRY, //.gem = ITEM_FIGHTING_GEM, @@ -335,6 +343,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 14, .zMove = MOVE_SUPERSONIC_SKYSTRIKE, .maxMove = MOVE_MAX_AIRSTREAM, + .paletteTMHM = gItemIconPalette_FlyingTMHM, //.enhanceItem = ITEM_SHARP_BEAK, //.berry = ITEM_COBA_BERRY, //.gem = ITEM_FLYING_GEM, @@ -351,6 +360,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 14, .zMove = MOVE_ACID_DOWNPOUR, .maxMove = MOVE_MAX_OOZE, + .paletteTMHM = gItemIconPalette_PoisonTMHM, //.enhanceItem = ITEM_POISON_BARB, //.berry = ITEM_KEBIA_BERRY, //.gem = ITEM_POISON_GEM, @@ -367,6 +377,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 13, .zMove = MOVE_TECTONIC_RAGE, .maxMove = MOVE_MAX_QUAKE, + .paletteTMHM = gItemIconPalette_GroundTMHM, //.enhanceItem = ITEM_SOFT_SAND, //.berry = ITEM_SHUCA_BERRY, //.gem = ITEM_GROUND_GEM, @@ -383,6 +394,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 13, .zMove = MOVE_CONTINENTAL_CRUSH, .maxMove = MOVE_MAX_ROCKFALL, + .paletteTMHM = gItemIconPalette_RockTMHM, //.enhanceItem = ITEM_HARD_STONE, //.berry = ITEM_CHARTI_BERRY, //.gem = ITEM_ROCK_GEM, @@ -399,6 +411,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 15, .zMove = MOVE_SAVAGE_SPIN_OUT, .maxMove = MOVE_MAX_FLUTTERBY, + .paletteTMHM = gItemIconPalette_BugTMHM, //.enhanceItem = ITEM_SILVER_POWDER, //.berry = ITEM_TANGA_BERRY, //.gem = ITEM_BUG_GEM, @@ -415,6 +428,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 14, .zMove = MOVE_NEVER_ENDING_NIGHTMARE, .maxMove = MOVE_MAX_PHANTASM, + .paletteTMHM = gItemIconPalette_GhostTMHM, //.enhanceItem = ITEM_SPELL_TAG, //.berry = ITEM_KASIB_BERRY, //.gem = ITEM_GHOST_GEM, @@ -431,6 +445,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 13, .zMove = MOVE_CORKSCREW_CRASH, .maxMove = MOVE_MAX_STEELSPIKE, + .paletteTMHM = gItemIconPalette_SteelTMHM, //.enhanceItem = ITEM_METAL_COAT, //.berry = ITEM_BABIRI_BERRY, //.gem = ITEM_STEEL_GEM, @@ -453,6 +468,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 13, .zMove = MOVE_INFERNO_OVERDRIVE, .maxMove = MOVE_MAX_FLARE, + .paletteTMHM = gItemIconPalette_FireTMHM, //.enhanceItem = ITEM_CHARCOAL, //.berry = ITEM_OCCA_BERRY, //.gem = ITEM_FIRE_GEM, @@ -469,6 +485,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 14, .zMove = MOVE_HYDRO_VORTEX, .maxMove = MOVE_MAX_GEYSER, + .paletteTMHM = gItemIconPalette_WaterTMHM, //.enhanceItem = ITEM_MYSTIC_WATER, //.berry = ITEM_PASSHO_BERRY, //.gem = ITEM_WATER_GEM, @@ -485,6 +502,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 15, .zMove = MOVE_BLOOM_DOOM, .maxMove = MOVE_MAX_OVERGROWTH, + .paletteTMHM = gItemIconPalette_GrassTMHM, //.enhanceItem = ITEM_MIRACLE_SEED, //.berry = ITEM_RINDO_BERRY, //.gem = ITEM_GRASS_GEM, @@ -496,11 +514,12 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = }, [TYPE_ELECTRIC] = { - .name = _("Electr"), + .name = HANDLE_EXPANDED_TYPE_NAME("Electr", "Electric"), .generic = _("an ELECTRIC move"), .palette = 13, .zMove = MOVE_GIGAVOLT_HAVOC, .maxMove = MOVE_MAX_LIGHTNING, + .paletteTMHM = gItemIconPalette_ElectricTMHM, //.enhanceItem = ITEM_MAGNET, //.berry = ITEM_WACAN_BERRY, //.gem = ITEM_ELECTRIC_GEM, @@ -512,11 +531,12 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = }, [TYPE_PSYCHIC] = { - .name = _("Psychc"), + .name = HANDLE_EXPANDED_TYPE_NAME("Psychc", "Psychic"), .generic = _("a PSYCHIC move"), .palette = 14, .zMove = MOVE_SHATTERED_PSYCHE, .maxMove = MOVE_MAX_MINDSTORM, + .paletteTMHM = gItemIconPalette_PsychicTMHM, //.enhanceItem = ITEM_TWISTED_SPOON, //.berry = ITEM_PAYAPA_BERRY, //.gem = ITEM_PSYCHIC_GEM, @@ -533,6 +553,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 14, .zMove = MOVE_SUBZERO_SLAMMER, .maxMove = MOVE_MAX_HAILSTORM, + .paletteTMHM = gItemIconPalette_IceTMHM, //.enhanceItem = ITEM_NEVER_MELT_ICE, //.berry = ITEM_YACHE_BERRY, //.gem = ITEM_ICE_GEM, @@ -549,6 +570,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 15, .zMove = MOVE_DEVASTATING_DRAKE, .maxMove = MOVE_MAX_WYRMWIND, + .paletteTMHM = gItemIconPalette_DragonTMHM, //.enhanceItem = ITEM_DRAGON_FANG, //.berry = ITEM_HABAN_BERRY, //.gem = ITEM_DRAGON_GEM, @@ -565,6 +587,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 13, .zMove = MOVE_BLACK_HOLE_ECLIPSE, .maxMove = MOVE_MAX_DARKNESS, + .paletteTMHM = gItemIconPalette_DarkTMHM, //.enhanceItem = ITEM_BLACK_GLASSES, //.berry = ITEM_COLBUR_BERRY, //.gem = ITEM_DARK_GEM, @@ -581,6 +604,7 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = .palette = 14, .zMove = MOVE_TWINKLE_TACKLE, .maxMove = MOVE_MAX_STARFALL, + .paletteTMHM = gItemIconPalette_FairyTMHM, //.enhanceItem = ITEM_FAIRY_FEATHER, //.berry = ITEM_ROSELI_BERRY, //.gem = ITEM_FAIRY_GEM, @@ -590,13 +614,16 @@ const struct TypeInfo gTypesInfo[NUMBER_OF_MON_TYPES] = //.teraShard = ITEM_FAIRY_TERA_SHARD, //.arceusForm = SPECIES_ARCEUS_FAIRY, }, - /* [TYPE_STELLAR] = { - .name = _("Stellar"), - .teraShard = ITEM_STELLAR_TERA_SHARD, + .name = HANDLE_EXPANDED_TYPE_NAME("Stellr", "Stellar"), + .generic = _("a STELLAR move"), + .palette = 15, + .zMove = MOVE_BREAKNECK_BLITZ, + .maxMove = MOVE_MAX_STRIKE, + .paletteTMHM = gItemIconPalette_NormalTMHM, // failsafe + // .teraShard = ITEM_STELLAR_TERA_SHARD, }, - */ }; // extra args are money and ball @@ -2325,6 +2352,11 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer u32 data = partyData[i].gigantamaxFactor; SetMonData(&party[i], MON_DATA_GIGANTAMAX_FACTOR, &data); } + if (partyData[i].teraType > 0) + { + u32 data = partyData[i].teraType; + SetMonData(&party[i], MON_DATA_TERA_TYPE, &data); + } CalculateMonStats(&party[i]); if (B_TRAINER_CLASS_POKE_BALLS >= GEN_7 && ball == -1) @@ -3527,6 +3559,7 @@ void SwitchInClearSetData(u32 battler) // Reset damage to prevent things like red card activating if the switched-in mon is holding it gSpecialStatuses[battler].physicalDmg = 0; gSpecialStatuses[battler].specialDmg = 0; + gBattleStruct->enduredDamage &= ~gBitTable[battler]; // Reset G-Max Chi Strike boosts. gBattleStruct->bonusCritStages[battler] = 0; @@ -3609,7 +3642,6 @@ const u8* FaintClearSetData(u32 battler) gProtectStructs[battler].flinchImmobility = FALSE; gProtectStructs[battler].notFirstStrike = FALSE; gProtectStructs[battler].usedHealBlockedMove = FALSE; - gProtectStructs[battler].usesBouncedMove = FALSE; gProtectStructs[battler].usedGravityPreventedMove = FALSE; gProtectStructs[battler].usedThroatChopPreventedMove = FALSE; gProtectStructs[battler].statRaised = FALSE; @@ -4631,6 +4663,7 @@ static void HandleTurnActionSelectionState(void) gBattleStruct->mega.toEvolve &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(battler))]); gBattleStruct->burst.toBurst &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(battler))]); gBattleStruct->dynamax.toDynamax &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(battler))]); + gBattleStruct->tera.toTera &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(battler))]); gBattleStruct->dynamax.usingMaxMove[BATTLE_PARTNER(GetBattlerPosition(battler))] = FALSE; gBattleStruct->zmove.toBeUsed[BATTLE_PARTNER(GetBattlerPosition(battler))] = MOVE_NONE; BtlController_EmitEndBounceEffect(battler, BUFFER_A); @@ -4720,7 +4753,7 @@ static void HandleTurnActionSelectionState(void) } // Get the chosen move position (and thus the chosen move) and target from the returned buffer. - gBattleStruct->chosenMovePositions[battler] = gBattleResources->bufferB[battler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST | RET_DYNAMAX); + gBattleStruct->chosenMovePositions[battler] = gBattleResources->bufferB[battler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST | RET_DYNAMAX | RET_TERASTAL); gChosenMoveByBattler[battler] = gBattleMons[battler].moves[gBattleStruct->chosenMovePositions[battler]]; gBattleStruct->moveTarget[battler] = gBattleResources->bufferB[battler][3]; @@ -4731,6 +4764,8 @@ static void HandleTurnActionSelectionState(void) gBattleStruct->burst.toBurst |= gBitTable[battler]; else if (gBattleResources->bufferB[battler][2] & RET_DYNAMAX) gBattleStruct->dynamax.toDynamax |= gBitTable[battler]; + else if (gBattleResources->bufferB[battler][2] & RET_TERASTAL) + gBattleStruct->tera.toTera |= gBitTable[battler]; // Max Move check if (ShouldUseMaxMove(battler, gChosenMoveByBattler[battler])) @@ -5348,7 +5383,8 @@ static void PopulateArrayWithBattlers(u8 *battlers) static bool32 TryDoGimmicksBeforeMoves(void) { if (!(gHitMarker & HITMARKER_RUN) - && (gBattleStruct->mega.toEvolve || gBattleStruct->burst.toBurst || gBattleStruct->dynamax.toDynamax)) + && (gBattleStruct->mega.toEvolve || gBattleStruct->burst.toBurst + || gBattleStruct->dynamax.toDynamax || gBattleStruct->tera.toTera)) { u32 i, battler; u8 order[MAX_BATTLERS_COUNT]; @@ -5357,6 +5393,17 @@ static bool32 TryDoGimmicksBeforeMoves(void) SortBattlersBySpeed(order, FALSE); for (i = 0; i < gBattlersCount; i++) { + // Tera Check + if (gBattleStruct->tera.toTera & gBitTable[order[i]]) + { + gBattlerAttacker = order[i]; + gBattleScripting.battler = gBattlerAttacker; + gBattleStruct->tera.toTera &= ~(gBitTable[gBattlerAttacker]); + PrepareBattlerForTera(gBattlerAttacker); + PREPARE_TYPE_BUFFER(gBattleTextBuff1, GetBattlerTeraType(gBattlerAttacker)); + BattleScriptExecute(BattleScript_Terastallization); + return TRUE; + } // Dynamax Check if (gBattleStruct->dynamax.toDynamax & gBitTable[order[i]]) { @@ -6019,7 +6066,9 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) } else if (gMovesInfo[move].effect == EFFECT_REVELATION_DANCE) { - if (gBattleMons[battlerAtk].type1 != TYPE_MYSTERY) + if (IsTerastallized(battlerAtk) && GetBattlerTeraType(battlerAtk) != TYPE_STELLAR) + gBattleStruct->dynamicMoveType = GetBattlerTeraType(battlerAtk); + else if (gBattleMons[battlerAtk].type1 != TYPE_MYSTERY) gBattleStruct->dynamicMoveType = gBattleMons[battlerAtk].type1 | F_DYNAMIC_TYPE_SET; else if (gBattleMons[battlerAtk].type2 != TYPE_MYSTERY) gBattleStruct->dynamicMoveType = gBattleMons[battlerAtk].type2 | F_DYNAMIC_TYPE_SET; @@ -6061,6 +6110,14 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) gBattleStruct->dynamicMoveType = TYPE_NORMAL | F_DYNAMIC_TYPE_SET; } } + else if (gMovesInfo[move].effect == EFFECT_TERA_BLAST && IsTerastallized(battlerAtk)) + { + gBattleStruct->dynamicMoveType = GetBattlerTeraType(battlerAtk) | F_DYNAMIC_TYPE_SET; + } + else if (gMovesInfo[move].effect == EFFECT_TERA_STARSTORM && gBattleMons[battlerAtk].species == SPECIES_TERAPAGOS_STELLAR) + { + gBattleStruct->dynamicMoveType = TYPE_STELLAR | F_DYNAMIC_TYPE_SET; + } attackerAbility = GetBattlerAbility(battlerAtk); @@ -6069,6 +6126,8 @@ void SetTypeBeforeUsingMove(u32 move, u32 battlerAtk) && gMovesInfo[move].effect != EFFECT_WEATHER_BALL && gMovesInfo[move].effect != EFFECT_CHANGE_TYPE_ON_ITEM && gMovesInfo[move].effect != EFFECT_NATURAL_GIFT + && !(gMovesInfo[move].effect == EFFECT_TERA_BLAST && IsTerastallized(battlerAtk)) + && !(gMovesInfo[move].effect == EFFECT_TERA_STARSTORM && gBattleMons[battlerAtk].species == SPECIES_TERAPAGOS_STELLAR) && ((attackerAbility == ABILITY_PIXILATE && (ateType = TYPE_FAIRY)) || (attackerAbility == ABILITY_REFRIGERATE && (ateType = TYPE_ICE)) || (attackerAbility == ABILITY_AERILATE && (ateType = TYPE_FLYING)) diff --git a/src/battle_message.c b/src/battle_message.c index 2efb99ff5f..7b9faea10f 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -724,6 +724,7 @@ static const u8 sText_ASandstormKickedUp[] = _("A sandstorm kicked up!"); static const u8 sText_PkmnsWillPerishIn3Turns[] = _("Both Pokémon will perish\nin three turns!"); static const u8 sText_AbilityRaisedStatDrastically[] = _("{B_DEF_ABILITY} raised {B_DEF_NAME_WITH_PREFIX}'s\n{B_BUFF1} drastically!"); static const u8 sText_AsOneEnters[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} has two Abilities!"); +static const u8 sText_PkmnMadeShellGleam[] = _("{B_DEF_NAME_WITH_PREFIX} made its shell gleam!\nIt's distorting type matchups!"); static const u8 sText_CuriousMedicineEnters[] = _("{B_EFF_NAME_WITH_PREFIX}'s\nstat changes were reset!"); static const u8 sText_CanActFaster[] = _("{B_ATK_NAME_WITH_PREFIX} can act faster,\nthanks to {B_BUFF1}!"); static const u8 sText_MicleBerryActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} boosted the accuracy of its\nnext move using {B_LAST_ITEM}!"); @@ -796,8 +797,8 @@ static const u8 sText_SunlightActivatedAbility[] = _("The harsh sunlight activat static const u8 sText_StatWasHeightened[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_BUFF1} was heightened!"); static const u8 sText_BoosterEnergyActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used its Booster Energy\nto activate {B_SCR_ACTIVE_ABILITY}!"); static const u8 sText_ElectricTerrainActivatedAbility[] = _("The Electric Terrain activated\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_LAST_ABILITY}!"); -static const u8 sText_AbilityWeakenedSurroundingMonsStat[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY}\nweakened the {B_BUFF1} of\lall surrounding Pokémon!\p"); -static const u8 sText_AttackerGainedStrengthFromTheFallen[] = _("{B_ATK_NAME_WITH_PREFIX} gained strength\nfrom the fallen!"); +static const u8 sText_AbilityWeakenedSurroundingMonsStat[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}'s {B_SCR_ACTIVE_ABILITY}\nweakened the {B_BUFF1} of\lall surrounding Pokémon!\p"); +static const u8 sText_AttackerGainedStrengthFromTheFallen[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} gained strength\nfrom the fallen!"); static const u8 sText_PrepareShellTrap[] = _("{B_ATK_NAME_WITH_PREFIX} set a shell trap!"); static const u8 sText_ShellTrapDidntWork[] = _("{B_ATK_NAME_WITH_PREFIX}'s shell trap didn't work!"); static const u8 sText_SharpSteelFloats[] = _("Sharp-pointed steel floats\naround {B_DEF_TEAM2} team!"); @@ -846,11 +847,13 @@ static const u8 sText_ElectroShotCharging[] = _("{B_ATK_NAME_WITH_PREFIX} absorb static const u8 sText_ItemWasUsedUp[] = _("The {B_LAST_ITEM}\nwas used up..."); static const u8 sText_AttackerLostItsType[] = _("{B_ATK_NAME_WITH_PREFIX} lost\nits {B_BUFF1} type!"); static const u8 sText_ShedItsTail[] = _("{B_ATK_NAME_WITH_PREFIX} shed its tail\nto create a decoy!"); +static const u8 sText_PkmnTerastallizedInto[] = _("{B_ATK_NAME_WITH_PREFIX} terastallized\ninto the {B_BUFF1} type!"); static const u8 sText_SupersweetAromaWafts[] = _("A supersweet aroma is wafting from\nthe syrup covering {B_ATK_NAME_WITH_PREFIX}!"); static const u8 sText_TidyingUpComplete[] = _("Tidying up complete!"); const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = { + [STRINGID_PKMNTERASTALLIZEDINTO - BATTLESTRINGS_TABLE_START] = sText_PkmnTerastallizedInto, [STRINGID_TIDYINGUPCOMPLETE - BATTLESTRINGS_TABLE_START] = sText_TidyingUpComplete, [STRINGID_SUPERSWEETAROMAWAFTS - BATTLESTRINGS_TABLE_START] = sText_SupersweetAromaWafts, [STRINGID_SHEDITSTAIL - BATTLESTRINGS_TABLE_START] = sText_ShedItsTail, @@ -893,7 +896,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_SHARPSTEELDMG - BATTLESTRINGS_TABLE_START] = sText_SharpSteelDmg, [STRINGID_SHARPSTEELFLOATS - BATTLESTRINGS_TABLE_START] = sText_SharpSteelFloats, [STRINGID_ATTACKERGAINEDSTRENGTHFROMTHEFALLEN - BATTLESTRINGS_TABLE_START] = sText_AttackerGainedStrengthFromTheFallen, - [STRINGID_ABILITYWEAKENEDFSURROUNDINGMONSSTAT - BATTLESTRINGS_TABLE_START] = sText_AbilityWeakenedSurroundingMonsStat, + [STRINGID_ABILITYWEAKENEDSURROUNDINGMONSSTAT - BATTLESTRINGS_TABLE_START] = sText_AbilityWeakenedSurroundingMonsStat, [STRINGID_ELECTRICTERRAINACTIVATEDABILITY - BATTLESTRINGS_TABLE_START] = sText_ElectricTerrainActivatedAbility, [STRINGID_STATWASHEIGHTENED - BATTLESTRINGS_TABLE_START] = sText_StatWasHeightened, [STRINGID_BOOSTERENERGYACTIVATES - BATTLESTRINGS_TABLE_START] = sText_BoosterEnergyActivates, @@ -962,6 +965,7 @@ const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = [STRINGID_CANACTFASTERTHANKSTO - BATTLESTRINGS_TABLE_START] = sText_CanActFaster, [STRINGID_CURIOUSMEDICINEENTERS - BATTLESTRINGS_TABLE_START] = sText_CuriousMedicineEnters, [STRINGID_ASONEENTERS - BATTLESTRINGS_TABLE_START] = sText_AsOneEnters, + [STRINGID_PKMNMADESHELLGLEAM - BATTLESTRINGS_TABLE_START] = sText_PkmnMadeShellGleam, [STRINGID_ABILITYRAISEDSTATDRASTICALLY - BATTLESTRINGS_TABLE_START] = sText_AbilityRaisedStatDrastically, [STRINGID_PKMNSWILLPERISHIN3TURNS - BATTLESTRINGS_TABLE_START] = sText_PkmnsWillPerishIn3Turns, [STRINGID_ASANDSTORMKICKEDUP - BATTLESTRINGS_TABLE_START] = sText_ASandstormKickedUp, @@ -1682,6 +1686,17 @@ const u16 gMoveWeatherChangeStringIds[] = [B_MSG_STARTED_FOG] = STRINGID_FOGCREPTUP, // Unused, can use for custom moves that set fog }; +const u16 gWeatherEndsStringIds[B_MSG_WEATHER_END_COUNT] = +{ + [B_MSG_WEATHER_END_RAIN] = STRINGID_RAINSTOPPED, + [B_MSG_WEATHER_END_SANDSTORM] = STRINGID_SANDSTORMSUBSIDED, + [B_MSG_WEATHER_END_SUN] = STRINGID_SUNLIGHTFADED, + [B_MSG_WEATHER_END_HAIL] = STRINGID_HAILSTOPPED, + [B_MSG_WEATHER_END_STRONG_WINDS] = STRINGID_STRONGWINDSDISSIPATED, + [B_MSG_WEATHER_END_SNOW] = STRINGID_SNOWSTOPPED, + [B_MSG_WEATHER_END_FOG] = STRINGID_FOGLIFTED, +}; + const u16 gSandStormHailSnowContinuesStringIds[] = { [B_MSG_SANDSTORM] = STRINGID_SANDSTORMRAGES, @@ -3947,6 +3962,14 @@ void BattlePutTextOnWindow(const u8 *text, u8 windowId) printerTemplate.bgColor = textInfo[windowId].bgColor; printerTemplate.shadowColor = textInfo[windowId].shadowColor; + if (B_WIN_MOVE_NAME_1 <= windowId && windowId <= B_WIN_MOVE_NAME_4) + { + // We cannot check the actual width of the window because + // B_WIN_MOVE_NAME_1 and B_WIN_MOVE_NAME_3 are 16 wide for + // Z-move details. + printerTemplate.fontId = GetFontIdToFit(text, printerTemplate.fontId, printerTemplate.letterSpacing, 8 * TILE_WIDTH); + } + if (printerTemplate.x == 0xFF) { u32 width = GetBattleWindowTemplatePixelWidth(gBattleScripting.windowsType, windowId); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index e3f6615832..f8ea34e912 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -286,7 +286,16 @@ static const s32 sExperienceScalingFactors[] = static const u16 sTrappingMoves[NUM_TRAPPING_MOVES] = { - MOVE_BIND, MOVE_WRAP, MOVE_FIRE_SPIN, MOVE_CLAMP, MOVE_WHIRLPOOL, MOVE_SAND_TOMB, MOVE_MAGMA_STORM, MOVE_INFESTATION, MOVE_SNAP_TRAP, + MOVE_BIND, + MOVE_WRAP, + MOVE_FIRE_SPIN, + MOVE_CLAMP, + MOVE_WHIRLPOOL, + MOVE_SAND_TOMB, + MOVE_MAGMA_STORM, + MOVE_INFESTATION, + MOVE_SNAP_TRAP, + MOVE_THUNDER_CAGE }; static const u16 sBadgeFlags[8] = { @@ -321,11 +330,12 @@ static bool8 IsFinalStrikeEffect(u16 move); static void TryUpdateRoundTurnOrder(void); static bool32 ChangeOrderTargetAfterAttacker(void); void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBattler); +static void RemoveAllWeather(void); static void RemoveAllTerrains(void); static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 isIntimidate); static bool8 CanBurnHitThaw(u16 move); static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); -static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount); +static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); @@ -452,7 +462,7 @@ static void Cmd_setatkhptozero(void); static void Cmd_jumpifnexttargetvalid(void); static void Cmd_tryhealhalfhealth(void); static void Cmd_trymirrormove(void); -static void Cmd_setrain(void); +static void Cmd_setfieldweather(void); static void Cmd_setreflect(void); static void Cmd_setseeded(void); static void Cmd_manipulatedamage(void); @@ -476,7 +486,7 @@ static void Cmd_givepaydaymoney(void); static void Cmd_setlightscreen(void); static void Cmd_tryKO(void); static void Cmd_damagetohalftargethp(void); -static void Cmd_setsandstorm(void); +static void Cmd_unused_95(void); static void Cmd_weatherdamage(void); static void Cmd_tryinfatuating(void); static void Cmd_updatestatusicon(void); @@ -514,7 +524,7 @@ static void Cmd_presentdamagecalculation(void); static void Cmd_setsafeguard(void); static void Cmd_magnitudedamagecalculation(void); static void Cmd_jumpifnopursuitswitchdmg(void); -static void Cmd_setsunny(void); +static void Cmd_unused_bb(void); static void Cmd_halvehp(void); static void Cmd_copyfoestats(void); static void Cmd_rapidspinfree(void); @@ -527,7 +537,7 @@ static void Cmd_trydobeatup(void); static void Cmd_setsemiinvulnerablebit(void); static void Cmd_tryfiretwoturnmovenowbyeffect(void); static void Cmd_setminimize(void); -static void Cmd_sethail(void); +static void Cmd_unused_c8(void); static void Cmd_trymemento(void); static void Cmd_setforcedtarget(void); static void Cmd_setcharge(void); @@ -650,7 +660,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_end, //0x3D Cmd_end2, //0x3E Cmd_end3, //0x3F - Cmd_unused5, //0x40 + Cmd_unused5, //0x40 Cmd_call, //0x41 Cmd_setroost, //0x42 Cmd_jumpifabilitypresent, //0x43 @@ -711,7 +721,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_jumpifnexttargetvalid, //0x7A Cmd_tryhealhalfhealth, //0x7B Cmd_trymirrormove, //0x7C - Cmd_setrain, //0x7D + Cmd_setfieldweather, //0x7D Cmd_setreflect, //0x7E Cmd_setseeded, //0x7F Cmd_manipulatedamage, //0x80 @@ -735,7 +745,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_setlightscreen, //0x92 Cmd_tryKO, //0x93 Cmd_damagetohalftargethp, //0x94 - Cmd_setsandstorm, //0x95 + Cmd_unused_95, //0x95 Cmd_weatherdamage, //0x96 Cmd_tryinfatuating, //0x97 Cmd_updatestatusicon, //0x98 @@ -773,7 +783,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_setsafeguard, //0xB8 Cmd_magnitudedamagecalculation, //0xB9 Cmd_jumpifnopursuitswitchdmg, //0xBA - Cmd_setsunny, //0xBB + Cmd_unused_bb, //0xBB Cmd_halvehp, //0xBC Cmd_copyfoestats, //0xBD Cmd_rapidspinfree, //0xBE @@ -786,7 +796,7 @@ void (* const gBattleScriptingCommandsTable[])(void) = Cmd_setsemiinvulnerablebit, //0xC5 Cmd_tryfiretwoturnmovenowbyeffect, //0xC6 Cmd_setminimize, //0xC7 - Cmd_sethail, //0xC8 + Cmd_unused_c8, //0xC8 Cmd_trymemento, //0xC9 Cmd_setforcedtarget, //0xCA Cmd_setcharge, //0xCB @@ -1215,7 +1225,8 @@ bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) && !gDisableStructs[gBattlerAttacker].usedProteanLibero && (gBattleMons[battler].type1 != moveType || gBattleMons[battler].type2 != moveType || (gBattleMons[battler].type3 != moveType && gBattleMons[battler].type3 != TYPE_MYSTERY)) - && move != MOVE_STRUGGLE) + && move != MOVE_STRUGGLE + && !IsTerastallized(battler)) { SET_BATTLER_TYPE(battler, moveType); return TRUE; @@ -1223,6 +1234,19 @@ bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType) return FALSE; } +bool32 ShouldTeraShellDistortTypeMatchups(u32 move, u32 battlerDef) +{ + if (!(gBattleStruct->distortedTypeMatchups & gBitTable[battlerDef]) + && GetBattlerAbility(battlerDef) == ABILITY_TERA_SHELL + && gBattleMons[battlerDef].species == SPECIES_TERAPAGOS_TERASTAL + && !IS_MOVE_STATUS(move) + && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gBattleMons[battlerDef].hp == gBattleMons[battlerDef].maxHP) + return TRUE; + + return FALSE; +} + bool32 IsMoveNotAllowedInSkyBattles(u32 move) { return ((gBattleStruct->isSkyBattle) && (gMovesInfo[gCurrentMove].skyBattleBanned)); @@ -1354,9 +1378,9 @@ static void Cmd_attackcanceler(void) if (gProtectStructs[gBattlerTarget].bounceMove && gMovesInfo[gCurrentMove].magicCoatAffected - && !gProtectStructs[gBattlerAttacker].usesBouncedMove) + && !gBattleStruct->bouncedMoveIsUsed) { - gProtectStructs[gBattlerTarget].usesBouncedMove = TRUE; + gBattleStruct->bouncedMoveIsUsed = TRUE; gBattleCommunication[MULTISTRING_CHOOSER] = 0; // Edge case for bouncing a powder move against a grass type pokemon. SetAtkCancellerForCalledMove(); @@ -1373,18 +1397,33 @@ static void Cmd_attackcanceler(void) } return; } - else if (GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE - && gMovesInfo[gCurrentMove].magicCoatAffected - && !gProtectStructs[gBattlerAttacker].usesBouncedMove) + else if (gMovesInfo[gCurrentMove].magicCoatAffected && !gBattleStruct->bouncedMoveIsUsed) { - gProtectStructs[gBattlerTarget].usesBouncedMove = TRUE; - gBattleCommunication[MULTISTRING_CHOOSER] = 1; - // Edge case for bouncing a powder move against a grass type pokemon. - SetAtkCancellerForCalledMove(); - BattleScriptPushCursor(); - gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; - gBattlerAbility = gBattlerTarget; - return; + u32 battler = gBattlerTarget; + + if (GetBattlerAbility(gBattlerTarget) == ABILITY_MAGIC_BOUNCE) + { + battler = gBattlerTarget; + gBattleStruct->bouncedMoveIsUsed = TRUE; + } + else if (IsDoubleBattle() + && gMovesInfo[gCurrentMove].target == MOVE_TARGET_OPPONENTS_FIELD + && GetBattlerAbility(BATTLE_PARTNER(gBattlerTarget)) == ABILITY_MAGIC_BOUNCE) + { + gBattlerTarget = battler = BATTLE_PARTNER(gBattlerTarget); + gBattleStruct->bouncedMoveIsUsed = TRUE; + } + + if (gBattleStruct->bouncedMoveIsUsed) + { + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + // Edge case for bouncing a powder move against a grass type pokemon. + SetAtkCancellerForCalledMove(); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_MagicCoatBounce; + gBattlerAbility = battler; + return; + } } // Z-moves and Max Moves bypass protection, but deal reduced damage (factored in AccumulateOtherModifiers) @@ -1849,6 +1888,14 @@ static void Cmd_ppreduce(void) gHitMarker &= ~HITMARKER_NO_PPDEDUCT; gBattlescriptCurrInstr = cmd->nextInstr; + + if (ShouldTeraShellDistortTypeMatchups(gCurrentMove, gBattlerTarget)) + { + gBattleStruct->distortedTypeMatchups |= gBitTable[gBattlerTarget]; + gBattlerAbility = gBattlerTarget; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_TeraShellDistortingTypeMatchups; + } } // The chance is 1/N for each stage. @@ -2085,12 +2132,12 @@ END: // of a move that is Super Effective against a Flying-type Pokémon. if (gBattleWeather & B_WEATHER_STRONG_WINDS) { - if ((GetBattlerType(gBattlerTarget, 0) == TYPE_FLYING - && GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 0)) >= UQ_4_12(2.0)) - || (GetBattlerType(gBattlerTarget, 1) == TYPE_FLYING - && GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 1)) >= UQ_4_12(2.0)) - || (GetBattlerType(gBattlerTarget, 2) == TYPE_FLYING - && GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 2)) >= UQ_4_12(2.0))) + if ((GetBattlerType(gBattlerTarget, 0, FALSE) == TYPE_FLYING + && GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 0, FALSE)) >= UQ_4_12(2.0)) + || (GetBattlerType(gBattlerTarget, 1, FALSE) == TYPE_FLYING + && GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 1, FALSE)) >= UQ_4_12(2.0)) + || (GetBattlerType(gBattlerTarget, 2, FALSE) == TYPE_FLYING + && GetTypeModifier(moveType, GetBattlerType(gBattlerTarget, 2, FALSE)) >= UQ_4_12(2.0))) { gBattlerAbility = gBattlerTarget; BattleScriptPushCursor(); @@ -3085,7 +3132,6 @@ void SetMoveEffect(bool32 primary, bool32 certain) } // for synchronize - if (gBattleScripting.moveEffect == MOVE_EFFECT_POISON || gBattleScripting.moveEffect == MOVE_EFFECT_TOXIC || gBattleScripting.moveEffect == MOVE_EFFECT_PARALYSIS @@ -3094,6 +3140,10 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattleStruct->synchronizeMoveEffect = gBattleScripting.moveEffect; gHitMarker |= HITMARKER_SYNCHRONISE_EFFECT; } + + if (gBattleScripting.moveEffect == MOVE_EFFECT_POISON || gBattleScripting.moveEffect == MOVE_EFFECT_TOXIC) + gBattleStruct->poisonPuppeteerConfusion = TRUE; + return; } else if (statusChanged == FALSE) @@ -3803,6 +3853,15 @@ void SetMoveEffect(bool32 primary, bool32 certain) gBattlescriptCurrInstr = BattleScript_EffectPsychicNoise; } break; + case MOVE_EFFECT_TERA_BLAST: + if (IsTerastallized(gEffectBattler) + && GetBattlerTeraType(gEffectBattler) == TYPE_STELLAR + && !NoAliveMonsForEitherParty()) + { + BattleScriptPush(gBattlescriptCurrInstr + 1); + gBattlescriptCurrInstr = BattleScript_LowerAtkSpAtk; + } + break; } } } @@ -4379,7 +4438,15 @@ static void Cmd_getexp(void) gBattleMoveDamage += GetSoftLevelCapExpValue(gPlayerParty[*expMonId].level, gBattleStruct->expShareExpValue);; } - ApplyExperienceMultipliers(&gBattleMoveDamage, *expMonId, gBattlerFainted); + if (EXP_CAP_HARD && gBattleMoveDamage != 0) + { + u32 growthRate = gSpeciesInfo[GetMonData(&gPlayerParty[*expMonId], MON_DATA_SPECIES)].growthRate; + if (gExperienceTables[growthRate][GetCurrentLevelCap()] < gExperienceTables[growthRate][GetMonData(&gPlayerParty[*expMonId], MON_DATA_LEVEL)] + gBattleMoveDamage) + gBattleMoveDamage = gExperienceTables[growthRate][GetCurrentLevelCap()]; + } + + if (!EXP_CAP_HARD || gBattleMoveDamage != 0) // Edge case for hard level caps. Prevents mons from getting 1 exp + ApplyExperienceMultipliers(&gBattleMoveDamage, *expMonId, gBattlerFainted); if (IsTradedMon(&gPlayerParty[*expMonId])) { @@ -5886,9 +5953,10 @@ static void Cmd_moveend(void) return; } // Check if the move used was actually a bounced move. If so, we need to go back to the original attacker and make sure, its move hits all 2 or 3 pokemon. - else if (gProtectStructs[gBattlerAttacker].usesBouncedMove) + else if (gBattleStruct->bouncedMoveIsUsed) { u8 originalBounceTarget = gBattlerAttacker; + gBattleStruct->bouncedMoveIsUsed = FALSE; gBattlerAttacker = gBattleStruct->attackerBeforeBounce; gBattleStruct->targetsDone[gBattlerAttacker] |= gBitTable[originalBounceTarget]; gBattleStruct->targetsDone[originalBounceTarget] = 0; @@ -6014,8 +6082,6 @@ static void Cmd_moveend(void) for (i = 0; i < gBattlersCount; i++) { u32 holdEffect; - if (i == gBattlerAttacker) - continue; holdEffect = GetBattlerHoldEffect(i, TRUE); if (holdEffect == HOLD_EFFECT_EJECT_BUTTON) ejectButtonBattlers |= gBitTable[i]; @@ -6031,7 +6097,7 @@ static void Cmd_moveend(void) { u32 battler = battlers[i]; - if (ejectButtonBattlers & gBitTable[battler]) + if (battler != gBattlerAttacker && ejectButtonBattlers & gBitTable[battler]) { if (TestIfSheerForceAffected(gBattlerAttacker, gCurrentMove)) // Apparently Sheer Force blocks Eject Button, but not Eject Pack continue; @@ -6189,7 +6255,7 @@ static void Cmd_moveend(void) if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker] || (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove - && gProtectStructs[gBattlerAttacker].usesBouncedMove))) + && gBattleStruct->bouncedMoveIsUsed))) { // Dance move succeeds // Set target for other Dancer mons; set bit so that mon cannot activate Dancer off of its own move if (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove) @@ -6268,7 +6334,7 @@ static void Cmd_moveend(void) case MOVEEND_SET_EVOLUTION_TRACKER: // If the Pokémon needs to keep track of move usage for its evolutions, do it if (originallyUsedMove != MOVE_NONE) - TryUpdateEvolutionTracker(EVO_LEVEL_MOVE_TWENTY_TIMES, 1); + TryUpdateEvolutionTracker(EVO_LEVEL_MOVE_TWENTY_TIMES, 1, originallyUsedMove); gBattleScripting.moveendState++; break; case MOVEEND_CLEAR_BITS: // Clear/Set bits for things like using a move for all targets and all hits. @@ -6284,7 +6350,6 @@ static void Cmd_moveend(void) CancelMultiTurnMoves(gBattlerAttacker); // Cancel it gBattleStruct->targetsDone[gBattlerAttacker] = 0; - gProtectStructs[gBattlerAttacker].usesBouncedMove = FALSE; gProtectStructs[gBattlerAttacker].targetAffected = FALSE; gProtectStructs[gBattlerAttacker].shellTrap = FALSE; gBattleStruct->ateBoost[gBattlerAttacker] = 0; @@ -6301,8 +6366,11 @@ static void Cmd_moveend(void) gBattleStruct->hitSwitchTargetFailed = FALSE; gBattleStruct->isAtkCancelerForCalledMove = FALSE; gBattleStruct->swapDamageCategory = FALSE; + gBattleStruct->bouncedMoveIsUsed = FALSE; gBattleStruct->enduredDamage = 0; gBattleStruct->additionalEffectsCounter = 0; + gBattleStruct->poisonPuppeteerConfusion = FALSE; + gBattleStruct->distortedTypeMatchups = 0; gBattleScripting.moveendState++; break; case MOVEEND_COUNT: @@ -7016,6 +7084,8 @@ static void SetDmgHazardsBattlescript(u8 battler, u8 multistringId) gBattlescriptCurrInstr = BattleScript_DmgHazardsOnTarget; else if (gBattlescriptCurrInstr[1] == BS_ATTACKER) gBattlescriptCurrInstr = BattleScript_DmgHazardsOnAttacker; + else if (gBattlescriptCurrInstr[1] == BS_SCRIPTING) + gBattlescriptCurrInstr = BattleScript_DmgHazardsOnBattlerScripting; else gBattlescriptCurrInstr = BattleScript_DmgHazardsOnFaintedBattler; } @@ -8374,6 +8444,30 @@ bool32 CanUseLastResort(u8 battler) return (knownMovesCount >= 2 && usedMovesCount >= knownMovesCount - 1); } +static void RemoveAllWeather(void) +{ + gWishFutureKnock.weatherDuration = 0; + + if (gBattleWeather & B_WEATHER_RAIN) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_RAIN; + else if(gBattleWeather & B_WEATHER_SANDSTORM) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SANDSTORM; + else if(gBattleWeather & B_WEATHER_SUN) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SUN; + else if(gBattleWeather & B_WEATHER_HAIL) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_HAIL; + else if(gBattleWeather & B_WEATHER_STRONG_WINDS) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_STRONG_WINDS; + else if(gBattleWeather & B_WEATHER_SNOW) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SNOW; + else if(gBattleWeather & B_WEATHER_FOG) + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_FOG; + else + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_COUNT; // failsafe + + gBattleWeather = 0; // remove the weather +} + static void RemoveAllTerrains(void) { gFieldTimers.terrainTimer = 0; @@ -9575,20 +9669,6 @@ static void Cmd_various(void) gLastUsedAbility = gBattleMons[battler].ability; break; } - case VARIOUS_TRY_QUASH: - { - VARIOUS_ARGS(const u8 *failInstr); - if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)) // It's true if foe is faster, has a bigger priority, or switches - { - gBattlescriptCurrInstr = cmd->failInstr; // This replaces the current battlescript with the "fail" script. - } - else // If the condition is not true, it means we are faster than the foe, so we can set the quash bit - { - gProtectStructs[gBattlerTarget].quash = TRUE; - gBattlescriptCurrInstr = cmd->nextInstr; // and then we proceed with the rest of our battlescript - } - return; - } case VARIOUS_INVERT_STAT_STAGES: { VARIOUS_ARGS(); @@ -9644,8 +9724,9 @@ static void Cmd_various(void) case VARIOUS_TRY_SOAK: { VARIOUS_ARGS(const u8 *failInstr); - if (GetBattlerType(gBattlerTarget, 0) == gMovesInfo[gCurrentMove].type - && GetBattlerType(gBattlerTarget, 1) == gMovesInfo[gCurrentMove].type) + if ((GetBattlerType(gBattlerTarget, 0, FALSE) == gMovesInfo[gCurrentMove].type + && GetBattlerType(gBattlerTarget, 1, FALSE) == gMovesInfo[gCurrentMove].type) + || IsTerastallized(gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; } @@ -9978,7 +10059,7 @@ static void Cmd_various(void) case VARIOUS_TRY_THIRD_TYPE: { VARIOUS_ARGS(const u8 *failInstr); - if (IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument)) + if (IS_BATTLER_OF_TYPE(battler, gMovesInfo[gCurrentMove].argument) || IsTerastallized(battler)) { gBattlescriptCurrInstr = cmd->failInstr; } @@ -11070,19 +11151,39 @@ static void Cmd_trymirrormove(void) } } -static void Cmd_setrain(void) +static void Cmd_setfieldweather(void) { - CMD_ARGS(); + CMD_ARGS(u8 weather); - if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_RAIN, FALSE)) + u8 weather = cmd->weather; + + if (!TryChangeBattleWeather(gBattlerAttacker, weather, FALSE)) { gMoveResultFlags |= MOVE_RESULT_MISSED; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; + gBattlescriptCurrInstr = cmd->nextInstr; + return; } - else + + switch (weather) { + case ENUM_WEATHER_RAIN: gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_RAIN; + break; + case ENUM_WEATHER_SUN: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SUNLIGHT; + break; + case ENUM_WEATHER_SANDSTORM: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SANDSTORM; + break; + case ENUM_WEATHER_HAIL: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_HAIL; + break; + case ENUM_WEATHER_SNOW: + gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SNOW; + break; } + gBattlescriptCurrInstr = cmd->nextInstr; } @@ -12045,6 +12146,12 @@ static void Cmd_tryconversiontypechange(void) u8 moveChecked = 0; u8 moveType = 0; + if (IsTerastallized(gBattlerAttacker)) + { + gBattlescriptCurrInstr = cmd->failInstr; + return; + } + if (B_UPDATED_CONVERSION >= GEN_6) { // Changes user's type to its first move's type @@ -12279,20 +12386,8 @@ static void Cmd_damagetohalftargethp(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_setsandstorm(void) +static void Cmd_unused_95(void) { - CMD_ARGS(); - - if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_SANDSTORM, FALSE)) - { - gMoveResultFlags |= MOVE_RESULT_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SANDSTORM; - } - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_weatherdamage(void) @@ -12821,6 +12916,14 @@ static void Cmd_settypetorandomresistance(void) { gBattlescriptCurrInstr = cmd->failInstr; } + else if (IsTerastallized(gBattlerAttacker)) + { + gBattlescriptCurrInstr = cmd->failInstr; + } + else if (gLastHitByType[gBattlerAttacker] == TYPE_STELLAR) + { + gBattlescriptCurrInstr = cmd->failInstr; + } else { u32 i, resistTypes = 0; @@ -13490,21 +13593,8 @@ static void Cmd_jumpifnopursuitswitchdmg(void) } } -static void Cmd_setsunny(void) +static void Cmd_unused_bb(void) { - CMD_ARGS(); - - if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_SUN, FALSE)) - { - gMoveResultFlags |= MOVE_RESULT_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SUNLIGHT; - } - - gBattlescriptCurrInstr = cmd->nextInstr; } // Belly Drum, Fillet Away @@ -13821,21 +13911,8 @@ static void Cmd_setminimize(void) gBattlescriptCurrInstr = cmd->nextInstr; } -static void Cmd_sethail(void) +static void Cmd_unused_c8(void) { - CMD_ARGS(); - - if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_HAIL, FALSE)) - { - gMoveResultFlags |= MOVE_RESULT_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_HAIL; - } - - gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_trymemento(void) @@ -14808,7 +14885,7 @@ static void Cmd_settypetoterrain(void) break; } - if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, terrainType)) + if (!IS_BATTLER_OF_TYPE(gBattlerAttacker, terrainType) && !IsTerastallized(gBattlerAttacker)) { SET_BATTLER_TYPE(gBattlerAttacker, terrainType); PREPARE_TYPE_BUFFER(gBattleTextBuff1, terrainType); @@ -15982,6 +16059,7 @@ void ApplyExperienceMultipliers(s32 *expAmount, u8 expGetterMonId, u8 faintedBat value *= sExperienceScalingFactors[(faintedLevel * 2) + 10]; value /= sExperienceScalingFactors[faintedLevel + expGetterLevel + 10]; + *expAmount = value + 1; } } @@ -16183,23 +16261,6 @@ void BS_TryRevertWeatherForm(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_SetSnow(void) -{ - NATIVE_ARGS(); - - if (!TryChangeBattleWeather(gBattlerAttacker, ENUM_WEATHER_SNOW, FALSE)) - { - gMoveResultFlags |= MOVE_RESULT_MISSED; - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_FAILED; - - } - else - { - gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STARTED_SNOW; - } - gBattlescriptCurrInstr = cmd->nextInstr; -} - void BS_HandleMegaEvolution(void) { NATIVE_ARGS(u8 battler, u8 caseId); @@ -16374,14 +16435,18 @@ void BS_TryReflectType(void) { NATIVE_ARGS(const u8 *failInstr); u16 targetBaseSpecies = GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species); - u8 targetType1 = GetBattlerType(gBattlerTarget, 0); - u8 targetType2 = GetBattlerType(gBattlerTarget, 1); - u8 targetType3 = GetBattlerType(gBattlerTarget, 2); + u8 targetType1 = GetBattlerType(gBattlerTarget, 0, FALSE); + u8 targetType2 = GetBattlerType(gBattlerTarget, 1, FALSE); + u8 targetType3 = GetBattlerType(gBattlerTarget, 2, FALSE); if (targetBaseSpecies == SPECIES_ARCEUS || targetBaseSpecies == SPECIES_SILVALLY) { gBattlescriptCurrInstr = cmd->failInstr; } + else if (IsTerastallized(gBattlerAttacker)) + { + gBattlescriptCurrInstr = cmd->failInstr; + } else if (IS_BATTLER_TYPELESS(gBattlerTarget)) { gBattlescriptCurrInstr = cmd->failInstr; @@ -16742,7 +16807,9 @@ void BS_AllySwitchFailChance(void) void BS_SetPhotonGeyserCategory(void) { NATIVE_ARGS(); - gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) == DAMAGE_CATEGORY_PHYSICAL); + if (!(gMovesInfo[gCurrentMove].effect == EFFECT_TERA_BLAST && !IsTerastallized(gBattlerAttacker)) + && !(gMovesInfo[gCurrentMove].effect == EFFECT_TERA_STARSTORM && gBattleMons[gBattlerAttacker].species != SPECIES_TERAPAGOS_STELLAR)) + gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) == DAMAGE_CATEGORY_PHYSICAL); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16755,7 +16822,7 @@ void BS_RunStatChangeItems(void) ItemBattleEffects(ITEMEFFECT_STATS_CHANGED, GetBattlerForBattleScript(cmd->battler), FALSE); } -static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount) +static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount, u16 usedMove) { u32 i; @@ -16780,9 +16847,19 @@ static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount) // We only have 9 bits to use u16 val = min(511, GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]], MON_DATA_EVOLUTION_TRACKER) + upAmount); // Reset progress if you faint for the recoil method. - if (gBattleMons[gBattlerAttacker].hp == 0 && (evolutionMethod == EVO_LEVEL_RECOIL_DAMAGE_MALE || evolutionMethod == EVO_LEVEL_RECOIL_DAMAGE_FEMALE)) - val = 0; - SetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]], MON_DATA_EVOLUTION_TRACKER, &val); + switch (evolutionMethod) + { + case EVO_LEVEL_MOVE_TWENTY_TIMES: + if (evolutions[i].param == usedMove) + SetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]], MON_DATA_EVOLUTION_TRACKER, &val); + break; + case EVO_LEVEL_RECOIL_DAMAGE_MALE: + case EVO_LEVEL_RECOIL_DAMAGE_FEMALE: + if (gBattleMons[gBattlerAttacker].hp == 0) + val = 0; + SetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]], MON_DATA_EVOLUTION_TRACKER, &val); + break; + } return; } } @@ -16792,8 +16869,18 @@ static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount) void BS_TryUpdateRecoilTracker(void) { NATIVE_ARGS(); - TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_MALE, gBattleMoveDamage); - TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_FEMALE, gBattleMoveDamage); + u8 gender = GetMonGender(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]); + + switch(gender) + { + case MON_MALE: + TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_MALE, gBattleMoveDamage, MOVE_NONE); + break; + case MON_FEMALE: + TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_FEMALE, gBattleMoveDamage, MOVE_NONE); + break; + } + gBattlescriptCurrInstr = cmd->nextInstr; } @@ -16829,3 +16916,42 @@ void BS_TryGulpMissile(void) else gBattlescriptCurrInstr = cmd->nextInstr; } + +void BS_TryQuash(void) +{ + NATIVE_ARGS(const u8 *failInstr); + u32 i; + + // It's true if foe is faster, has a bigger priority, or switches + if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)) + { + gBattlescriptCurrInstr = cmd->failInstr; + return; + } + + // If the above condition is not true, it means we are faster than the foe, so we can set the quash bit + gProtectStructs[gBattlerTarget].quash = TRUE; + for (i = 0; i < gBattlersCount; i++) + { + gBattlerByTurnOrder[i] = i; + } + for (i = 0; i < gBattlersCount - 1; i++) + { + s32 j; + for (j = i + 1; j < gBattlersCount; j++) + { + if (!gProtectStructs[i].quash + && !gProtectStructs[j].quash + && GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == -1) + SwapTurnOrder(i, j); + } + } + gBattlescriptCurrInstr = cmd->nextInstr; +} + +void BS_RemoveWeather(void) +{ + NATIVE_ARGS(); + RemoveAllWeather(); + gBattlescriptCurrInstr = cmd->nextInstr; +} diff --git a/src/battle_terastal.c b/src/battle_terastal.c new file mode 100644 index 0000000000..ad83779682 --- /dev/null +++ b/src/battle_terastal.c @@ -0,0 +1,785 @@ +#include "global.h" +#include "battle.h" +#include "battle_anim.h" +#include "battle_controllers.h" +#include "battle_interface.h" +#include "battle_terastal.h" +#include "event_data.h" +#include "item.h" +#include "palette.h" +#include "pokemon.h" +#include "sprite.h" +#include "util.h" +#include "constants/abilities.h" +#include "constants/hold_effects.h" +#include "constants/rgb.h" + +// Sets flags and variables upon a battler's Terastallization. +void PrepareBattlerForTera(u32 battler) +{ + u32 side = GetBattlerSide(battler); + struct Pokemon *party = GetBattlerParty(battler); + u32 index = gBattlerPartyIndexes[battler]; + + // Update TeraData fields. + gBattleStruct->tera.isTerastallized[side] |= gBitTable[index]; + gBattleStruct->tera.alreadyTerastallized[battler] = TRUE; + + // Remove Tera Orb charge. + if (B_FLAG_TERA_ORB_CHARGED != 0 + && (B_FLAG_TERA_ORB_NO_COST == 0 || !FlagGet(B_FLAG_TERA_ORB_NO_COST)) + && side == B_SIDE_PLAYER + && !(gBattleTypeFlags & BATTLE_TYPE_DOUBLE && !IsPartnerMonFromSameTrainer(battler))) + { + FlagClear(B_FLAG_TERA_ORB_CHARGED); + } + + // Show indicator and do palette blend. + UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], &party[index], HEALTHBOX_ALL); + BlendPalette(OBJ_PLTT_ID(battler), 16, 8, GetTeraTypeRGB(GetBattlerTeraType(battler))); + CpuCopy32(gPlttBufferFaded + OBJ_PLTT_ID(battler), gPlttBufferUnfaded + OBJ_PLTT_ID(battler), PLTT_SIZEOF(16)); +} + +// Returns whether a battler can Terastallize. +bool32 CanTerastallize(u32 battler) +{ + u32 holdEffect = GetBattlerHoldEffect(battler, FALSE); + + // Check if Player has Tera Orb and has charge. + if (!CheckBagHasItem(ITEM_TERA_ORB, 1) + || !((B_FLAG_TERA_ORB_NO_COST != 0 && FlagGet(B_FLAG_TERA_ORB_NO_COST)) + || (B_FLAG_TERA_ORB_CHARGED != 0 && FlagGet(B_FLAG_TERA_ORB_CHARGED) + && ((battler == B_POSITION_PLAYER_LEFT || (!(gBattleTypeFlags & BATTLE_TYPE_MULTI) && battler == B_POSITION_PLAYER_RIGHT)))))) + { + return FALSE; + } + + // Check if Trainer has already Terastallized. + if (gBattleStruct->tera.alreadyTerastallized[battler]) + { + return FALSE; + } + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE + && IsPartnerMonFromSameTrainer(battler) + && (gBattleStruct->tera.alreadyTerastallized[BATTLE_PARTNER(battler)] + || (gBattleStruct->tera.toTera & gBitTable[BATTLE_PARTNER(battler)]))) + { + return FALSE; + } + + // Check if battler is holding a Z-Crystal or Mega Stone. + if (holdEffect == HOLD_EFFECT_Z_CRYSTAL || holdEffect == HOLD_EFFECT_MEGA_STONE) + { + return FALSE; + } + + // Every check passed! + return TRUE; +} + +// Returns a battler's Tera type. +u32 GetBattlerTeraType(u32 battler) +{ + struct Pokemon *mon = &GetBattlerParty(battler)[gBattlerPartyIndexes[battler]]; + return GetMonData(mon, MON_DATA_TERA_TYPE); +} + +// Returns whether a battler is terastallized. +bool32 IsTerastallized(u32 battler) +{ + return gBattleStruct->tera.isTerastallized[GetBattlerSide(battler)] & gBitTable[gBattlerPartyIndexes[battler]]; +} + + +// Uses up a type's Stellar boost. +void ExpendTypeStellarBoost(u32 battler, u32 type) +{ + if (type < 32) // avoid OOB access + gBattleStruct->tera.stellarBoostFlags[GetBattlerSide(battler)] |= gBitTable[type]; +} + +// Checks whether a type's Stellar boost has been expended. +bool32 IsTypeStellarBoosted(u32 battler, u32 type) +{ + if (type < 32) // avoid OOB access + return !(gBattleStruct->tera.stellarBoostFlags[GetBattlerSide(battler)] & gBitTable[type]); + else + return FALSE; +} + +// Returns the STAB power multiplier to use when Terastallized. +// Power multipliers from Smogon Research thread. +uq4_12_t GetTeraMultiplier(u32 battler, u32 type) +{ + u32 teraType = GetBattlerTeraType(battler); + bool32 hasAdaptability = (GetBattlerAbility(battler) == ABILITY_ADAPTABILITY); + + // Safety check. + if (!IsTerastallized(battler)) + return UQ_4_12(1.0); + + // Stellar-type checks. + if (teraType == TYPE_STELLAR) + { + bool32 shouldBoost = IsTypeStellarBoosted(battler, type); + if (IS_BATTLER_OF_BASE_TYPE(battler, type)) + { + if (shouldBoost) + return UQ_4_12(2.0); + else + return UQ_4_12(1.5); + } + else if (shouldBoost) + return UQ_4_12(1.2); + else + return UQ_4_12(1.0); + } + // Base and Tera type. + if (type == teraType && IS_BATTLER_OF_BASE_TYPE(battler, type)) + { + if (hasAdaptability) + return UQ_4_12(2.25); + else + return UQ_4_12(2.0); + } + // Base or Tera type only. + else if ((type == teraType && !IS_BATTLER_OF_BASE_TYPE(battler, type)) + || (type != teraType && IS_BATTLER_OF_BASE_TYPE(battler, type))) + { + if (hasAdaptability) + return UQ_4_12(2.0); + else + return UQ_4_12(1.5); + } + // Neither base or Tera type. + else + { + return UQ_4_12(1.0); + } +} + +// Most values pulled from the Tera type icon palette. +const u16 sTeraTypeRGBValues[NUMBER_OF_MON_TYPES] = { + [TYPE_NORMAL] = RGB_WHITE, // custom + [TYPE_FIGHTING] = RGB(26, 8, 14), + [TYPE_FLYING] = RGB(31, 26, 7), + [TYPE_POISON] = RGB(26, 10, 25), // custom + [TYPE_GROUND] = RGB(25, 23, 18), + [TYPE_ROCK] = RGB(18, 16, 8), // custom + [TYPE_BUG] = RGB(18, 24, 6), + [TYPE_GHOST] = RGB(12, 10, 16), + [TYPE_STEEL] = RGB(19, 19, 20), + [TYPE_MYSTERY] = RGB_WHITE, + [TYPE_FIRE] = RGB(31, 20, 11), + [TYPE_WATER] = RGB(10, 18, 27), + [TYPE_GRASS] = RGB(12, 24, 11), + [TYPE_ELECTRIC] = RGB(30, 26, 7), + [TYPE_PSYCHIC] = RGB(31, 14, 15), + [TYPE_ICE] = RGB(14, 26, 25), + [TYPE_DRAGON] = RGB(10, 18, 27), + [TYPE_DARK] = RGB(6, 5, 8), + [TYPE_FAIRY] = RGB(31, 15, 21), + [TYPE_STELLAR] = RGB(10, 18, 27), +}; + +u16 GetTeraTypeRGB(u32 type) +{ + return sTeraTypeRGBValues[type]; +} + +// TERASTAL TRIGGER: +static const u8 ALIGNED(4) sTeraTriggerGfx[] = INCBIN_U8("graphics/battle_interface/tera_trigger.4bpp"); +static const u16 sTeraTriggerPal[] = INCBIN_U16("graphics/battle_interface/tera_trigger.gbapal"); + +static const struct SpriteSheet sSpriteSheet_TeraTrigger = +{ + sTeraTriggerGfx, sizeof(sTeraTriggerGfx), TAG_TERA_TRIGGER_TILE +}; +static const struct SpritePalette sSpritePalette_TeraTrigger = +{ + sTeraTriggerPal, TAG_TERA_TRIGGER_PAL +}; + +static const struct OamData sOamData_TeraTrigger = +{ + .y = 0, + .affineMode = 0, + .objMode = 0, + .mosaic = 0, + .bpp = 0, + .shape = ST_OAM_SQUARE, + .x = 0, + .matrixNum = 0, + .size = 2, + .tileNum = 0, + .priority = 1, + .paletteNum = 0, + .affineParam = 0, +}; + +static const union AnimCmd sSpriteAnim_TeraTriggerOff[] = +{ + ANIMCMD_FRAME(0, 0), + ANIMCMD_END +}; + +static const union AnimCmd sSpriteAnim_TeraTriggerOn[] = +{ + ANIMCMD_FRAME(16, 0), + ANIMCMD_END +}; + +static const union AnimCmd *const sSpriteAnimTable_TeraTrigger[] = +{ + sSpriteAnim_TeraTriggerOff, + sSpriteAnim_TeraTriggerOn, +}; + +static void SpriteCb_TeraTrigger(struct Sprite *sprite); +static const struct SpriteTemplate sSpriteTemplate_TeraTrigger = +{ + .tileTag = TAG_TERA_TRIGGER_TILE, + .paletteTag = TAG_TERA_TRIGGER_PAL, + .oam = &sOamData_TeraTrigger, + .anims = sSpriteAnimTable_TeraTrigger, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraTrigger +}; + +// Tera Evolution Trigger icon functions. +void ChangeTeraTriggerSprite(u8 spriteId, u8 animId) +{ + StartSpriteAnim(&gSprites[spriteId], animId); +} + +#define SINGLES_TERA_TRIGGER_POS_X_OPTIMAL (30) +#define SINGLES_TERA_TRIGGER_POS_X_PRIORITY (31) +#define SINGLES_TERA_TRIGGER_POS_X_SLIDE (15) +#define SINGLES_TERA_TRIGGER_POS_Y_DIFF (-11) + +#define DOUBLES_TERA_TRIGGER_POS_X_OPTIMAL (30) +#define DOUBLES_TERA_TRIGGER_POS_X_PRIORITY (31) +#define DOUBLES_TERA_TRIGGER_POS_X_SLIDE (15) +#define DOUBLES_TERA_TRIGGER_POS_Y_DIFF (-4) + +#define tBattler data[0] +#define tHide data[1] + +void CreateTeraTriggerSprite(u8 battler, u8 palId) +{ + LoadSpritePalette(&sSpritePalette_TeraTrigger); + if (GetSpriteTileStartByTag(TAG_TERA_TRIGGER_TILE) == 0xFFFF) + { + LoadSpriteSheet(&sSpriteSheet_TeraTrigger); + } + if (gBattleStruct->tera.triggerSpriteId == 0xFF) + { + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + gBattleStruct->tera.triggerSpriteId = CreateSprite(&sSpriteTemplate_TeraTrigger, + gSprites[gHealthboxSpriteIds[battler]].x - DOUBLES_TERA_TRIGGER_POS_X_SLIDE, + gSprites[gHealthboxSpriteIds[battler]].y - DOUBLES_TERA_TRIGGER_POS_Y_DIFF, 0); + else + gBattleStruct->tera.triggerSpriteId = CreateSprite(&sSpriteTemplate_TeraTrigger, + gSprites[gHealthboxSpriteIds[battler]].x - SINGLES_TERA_TRIGGER_POS_X_SLIDE, + gSprites[gHealthboxSpriteIds[battler]].y - SINGLES_TERA_TRIGGER_POS_Y_DIFF, 0); + } + gSprites[gBattleStruct->tera.triggerSpriteId].tBattler = battler; + gSprites[gBattleStruct->tera.triggerSpriteId].tHide = FALSE; + + ChangeTeraTriggerSprite(gBattleStruct->tera.triggerSpriteId, palId); +} + +static void SpriteCb_TeraTrigger(struct Sprite *sprite) +{ + s32 xSlide, xPriority, xOptimal; + s32 yDiff; + + if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE) + { + xSlide = DOUBLES_TERA_TRIGGER_POS_X_SLIDE; + xPriority = DOUBLES_TERA_TRIGGER_POS_X_PRIORITY; + xOptimal = DOUBLES_TERA_TRIGGER_POS_X_OPTIMAL; + yDiff = DOUBLES_TERA_TRIGGER_POS_Y_DIFF; + } + else + { + xSlide = SINGLES_TERA_TRIGGER_POS_X_SLIDE; + xPriority = SINGLES_TERA_TRIGGER_POS_X_PRIORITY; + xOptimal = SINGLES_TERA_TRIGGER_POS_X_OPTIMAL; + yDiff = SINGLES_TERA_TRIGGER_POS_Y_DIFF; + } + + if (sprite->tHide) + { + if (sprite->x != gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xSlide) + sprite->x++; + + if (sprite->x >= gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xPriority) + sprite->oam.priority = 2; + else + sprite->oam.priority = 1; + + sprite->y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y - yDiff; + sprite->y2 = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y2 - yDiff; + if (sprite->x == gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xSlide) + DestroyTeraTriggerSprite(); + } + else + { + if (sprite->x != gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xOptimal) + sprite->x--; + + if (sprite->x >= gSprites[gHealthboxSpriteIds[sprite->tBattler]].x - xPriority) + sprite->oam.priority = 2; + else + sprite->oam.priority = 1; + + sprite->y = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y - yDiff; + sprite->y2 = gSprites[gHealthboxSpriteIds[sprite->tBattler]].y2 - yDiff; + } +} + +bool32 IsTeraTriggerSpriteActive(void) +{ + if (GetSpriteTileStartByTag(TAG_TERA_TRIGGER_TILE) == 0xFFFF) + return FALSE; + else if (IndexOfSpritePaletteTag(TAG_TERA_TRIGGER_PAL) != 0xFF) + return TRUE; + else + return FALSE; +} + +void HideTeraTriggerSprite(void) +{ + if (gBattleStruct->tera.triggerSpriteId != 0xFF) + { + ChangeTeraTriggerSprite(gBattleStruct->tera.triggerSpriteId, 0); + gSprites[gBattleStruct->tera.triggerSpriteId].tHide = TRUE; + } +} + +void DestroyTeraTriggerSprite(void) +{ + FreeSpritePaletteByTag(TAG_TERA_TRIGGER_PAL); + FreeSpriteTilesByTag(TAG_TERA_TRIGGER_TILE); + if (gBattleStruct->tera.triggerSpriteId != 0xFF) + DestroySprite(&gSprites[gBattleStruct->tera.triggerSpriteId]); + gBattleStruct->tera.triggerSpriteId = 0xFF; +} + +#undef tBattler +#undef tHide + +// TERA INDICATOR: +static const u16 sTeraIndicatorPal[] = INCBIN_U16("graphics/battle_interface/tera_indicator.gbapal"); +static const u8 ALIGNED(4) sNormalIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/normal_indicator.4bpp"); +static const u8 ALIGNED(4) sFightingIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/fighting_indicator.4bpp"); +static const u8 ALIGNED(4) sFlyingIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/flying_indicator.4bpp"); +static const u8 ALIGNED(4) sPoisonIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/poison_indicator.4bpp"); +static const u8 ALIGNED(4) sGroundIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/ground_indicator.4bpp"); +static const u8 ALIGNED(4) sRockIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/rock_indicator.4bpp"); +static const u8 ALIGNED(4) sBugIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/bug_indicator.4bpp"); +static const u8 ALIGNED(4) sGhostIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/ghost_indicator.4bpp"); +static const u8 ALIGNED(4) sSteelIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/steel_indicator.4bpp"); +static const u8 ALIGNED(4) sFireIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/fire_indicator.4bpp"); +static const u8 ALIGNED(4) sWaterIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/water_indicator.4bpp"); +static const u8 ALIGNED(4) sGrassIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/grass_indicator.4bpp"); +static const u8 ALIGNED(4) sElectricIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/electric_indicator.4bpp"); +static const u8 ALIGNED(4) sPsychicIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/psychic_indicator.4bpp"); +static const u8 ALIGNED(4) sIceIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/ice_indicator.4bpp"); +static const u8 ALIGNED(4) sDragonIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/dragon_indicator.4bpp"); +static const u8 ALIGNED(4) sDarkIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/dark_indicator.4bpp"); +static const u8 ALIGNED(4) sFairyIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/fairy_indicator.4bpp"); +static const u8 ALIGNED(4) sStellarIndicatorGfx[] = INCBIN_U8("graphics/battle_interface/stellar_indicator.4bpp"); + +static void SpriteCb_TeraIndicator(struct Sprite *sprite); +static const s8 sIndicatorPositions[][2] = +{ + [B_POSITION_PLAYER_LEFT] = {53, -9}, + [B_POSITION_OPPONENT_LEFT] = {44, -9}, + [B_POSITION_PLAYER_RIGHT] = {52, -9}, + [B_POSITION_OPPONENT_RIGHT] = {44, -9}, +}; + +static const struct SpritePalette sSpritePalette_TeraIndicator = +{ + sTeraIndicatorPal, TAG_TERA_INDICATOR_PAL +}; + +static const struct OamData sOamData_TeraIndicator = +{ + .shape = SPRITE_SHAPE(16x16), + .size = SPRITE_SIZE(16x16), + .priority = 1, +}; + +static const struct SpriteTemplate sSpriteTemplate_NormalIndicator = +{ + .tileTag = TAG_NORMAL_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_FightingIndicator = +{ + .tileTag = TAG_FIGHTING_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_FlyingIndicator = +{ + .tileTag = TAG_FLYING_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_PoisonIndicator = +{ + .tileTag = TAG_POISON_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_GroundIndicator = +{ + .tileTag = TAG_GROUND_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_RockIndicator = +{ + .tileTag = TAG_ROCK_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_BugIndicator = +{ + .tileTag = TAG_BUG_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_GhostIndicator = +{ + .tileTag = TAG_GHOST_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_SteelIndicator = +{ + .tileTag = TAG_STEEL_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_FireIndicator = +{ + .tileTag = TAG_FIRE_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_WaterIndicator = +{ + .tileTag = TAG_WATER_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_GrassIndicator = +{ + .tileTag = TAG_GRASS_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_ElectricIndicator = +{ + .tileTag = TAG_ELECTRIC_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_PsychicIndicator = +{ + .tileTag = TAG_PSYCHIC_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_IceIndicator = +{ + .tileTag = TAG_ICE_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_DragonIndicator = +{ + .tileTag = TAG_DRAGON_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_DarkIndicator = +{ + .tileTag = TAG_DARK_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_FairyIndicator = +{ + .tileTag = TAG_FAIRY_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteTemplate sSpriteTemplate_StellarIndicator = +{ + .tileTag = TAG_STELLAR_INDICATOR_TILE, + .paletteTag = TAG_TERA_INDICATOR_PAL, + .oam = &sOamData_TeraIndicator, + .anims = gDummySpriteAnimTable, + .images = NULL, + .affineAnims = gDummySpriteAffineAnimTable, + .callback = SpriteCb_TeraIndicator, +}; + +static const struct SpriteSheet sTeraIndicatorSpriteSheets[NUMBER_OF_MON_TYPES + 1] = +{ + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, + {sFightingIndicatorGfx, sizeof(sFightingIndicatorGfx), TAG_FIGHTING_INDICATOR_TILE}, + {sFlyingIndicatorGfx, sizeof(sFlyingIndicatorGfx), TAG_FLYING_INDICATOR_TILE}, + {sPoisonIndicatorGfx, sizeof(sPoisonIndicatorGfx), TAG_POISON_INDICATOR_TILE}, + {sGroundIndicatorGfx, sizeof(sGroundIndicatorGfx), TAG_GROUND_INDICATOR_TILE}, + {sRockIndicatorGfx, sizeof(sRockIndicatorGfx), TAG_ROCK_INDICATOR_TILE}, + {sBugIndicatorGfx, sizeof(sBugIndicatorGfx), TAG_BUG_INDICATOR_TILE}, + {sGhostIndicatorGfx, sizeof(sGhostIndicatorGfx), TAG_GHOST_INDICATOR_TILE}, + {sSteelIndicatorGfx, sizeof(sSteelIndicatorGfx), TAG_STEEL_INDICATOR_TILE}, + {sNormalIndicatorGfx, sizeof(sNormalIndicatorGfx), TAG_NORMAL_INDICATOR_TILE}, // TYPE_MYSTERY + {sFireIndicatorGfx, sizeof(sFireIndicatorGfx), TAG_FIRE_INDICATOR_TILE}, + {sWaterIndicatorGfx, sizeof(sWaterIndicatorGfx), TAG_WATER_INDICATOR_TILE}, + {sGrassIndicatorGfx, sizeof(sGrassIndicatorGfx), TAG_GRASS_INDICATOR_TILE}, + {sElectricIndicatorGfx, sizeof(sElectricIndicatorGfx), TAG_ELECTRIC_INDICATOR_TILE}, + {sPsychicIndicatorGfx, sizeof(sPsychicIndicatorGfx), TAG_PSYCHIC_INDICATOR_TILE}, + {sIceIndicatorGfx, sizeof(sIceIndicatorGfx), TAG_ICE_INDICATOR_TILE}, + {sDragonIndicatorGfx, sizeof(sDragonIndicatorGfx), TAG_DRAGON_INDICATOR_TILE}, + {sDarkIndicatorGfx, sizeof(sDarkIndicatorGfx), TAG_DARK_INDICATOR_TILE}, + {sFairyIndicatorGfx, sizeof(sFairyIndicatorGfx), TAG_FAIRY_INDICATOR_TILE}, + {sStellarIndicatorGfx, sizeof(sStellarIndicatorGfx), TAG_STELLAR_INDICATOR_TILE}, + {0} +}; + +static const struct SpriteTemplate * const sTeraIndicatorSpriteTemplates[NUMBER_OF_MON_TYPES] = +{ + [TYPE_NORMAL] = &sSpriteTemplate_NormalIndicator, + [TYPE_FIGHTING] = &sSpriteTemplate_FightingIndicator, + [TYPE_FLYING] = &sSpriteTemplate_FlyingIndicator, + [TYPE_POISON] = &sSpriteTemplate_PoisonIndicator, + [TYPE_GROUND] = &sSpriteTemplate_GroundIndicator, + [TYPE_ROCK] = &sSpriteTemplate_RockIndicator, + [TYPE_BUG] = &sSpriteTemplate_BugIndicator, + [TYPE_GHOST] = &sSpriteTemplate_GhostIndicator, + [TYPE_STEEL] = &sSpriteTemplate_SteelIndicator, + [TYPE_MYSTERY] = &sSpriteTemplate_NormalIndicator, // just in case + [TYPE_FIRE] = &sSpriteTemplate_FireIndicator, + [TYPE_WATER] = &sSpriteTemplate_WaterIndicator, + [TYPE_GRASS] = &sSpriteTemplate_GrassIndicator, + [TYPE_ELECTRIC] = &sSpriteTemplate_ElectricIndicator, + [TYPE_PSYCHIC] = &sSpriteTemplate_PsychicIndicator, + [TYPE_ICE] = &sSpriteTemplate_IceIndicator, + [TYPE_DRAGON] = &sSpriteTemplate_DragonIndicator, + [TYPE_DARK] = &sSpriteTemplate_DarkIndicator, + [TYPE_FAIRY] = &sSpriteTemplate_FairyIndicator, + [TYPE_STELLAR] = &sSpriteTemplate_StellarIndicator, +}; + +// for sprite data fields +#define tBattler data[0] +#define tType data[1] // Indicator type: tera +#define tPosX data[2] +#define tLevelXDelta data[3] // X position depends whether level has 3, 2 or 1 digit + +// data fields for healthboxMain +// oam.affineParam holds healthboxRight spriteId +#define hMain_TeraIndicatorId data[3] +#define hMain_HealthBarSpriteId data[5] +#define hMain_Battler data[6] +#define hMain_Data7 data[7] + +// data fields for healthboxRight +#define hOther_HealthBoxSpriteId data[5] + +// data fields for healthbar +#define hBar_HealthBoxSpriteId data[5] + +void TeraIndicator_LoadSpriteGfx(void) +{ + LoadSpriteSheets(sTeraIndicatorSpriteSheets); + LoadSpritePalette(&sSpritePalette_TeraIndicator); +} + +bool32 TeraIndicator_ShouldBeInvisible(u32 battler) +{ + return !IsTerastallized(battler); +} + +u8 TeraIndicator_GetSpriteId(u32 healthboxSpriteId) +{ + return gBattleStruct->tera.indicatorSpriteId[gSprites[healthboxSpriteId].hMain_Battler]; +} + +void TeraIndicator_SetVisibilities(u32 healthboxId, bool32 invisible) +{ + u8 spriteId = TeraIndicator_GetSpriteId(healthboxId); + u32 battler = gSprites[healthboxId].hMain_Battler; + + if (invisible == TRUE) + gSprites[spriteId].invisible = TRUE; + else // Try visible. + gSprites[spriteId].invisible = TeraIndicator_ShouldBeInvisible(battler); +} + +void TeraIndicator_UpdateOamPriorities(u32 healthboxId, u32 oamPriority) +{ + u8 spriteId = TeraIndicator_GetSpriteId(healthboxId); + gSprites[spriteId].oam.priority = oamPriority; +} + +void TeraIndicator_UpdateLevel(u32 healthboxId, u32 level) +{ + s16 xDelta = 0; + u8 spriteId = TeraIndicator_GetSpriteId(healthboxId); + + if (level >= 100) + xDelta -= 4; + else if (level < 10) + xDelta += 5; + + gSprites[spriteId].tLevelXDelta = xDelta; +} + +void TeraIndicator_CreateSprite(u32 battler, u32 healthboxSpriteId) +{ + u32 position; + u8 spriteId; + s16 xHealthbox = 0, y = 0; + s32 x = 0; + u32 type = GetBattlerTeraType(battler); + + position = GetBattlerPosition(battler); + GetBattlerHealthboxCoords(battler, &xHealthbox, &y); + + x = sIndicatorPositions[position][0]; + y += sIndicatorPositions[position][1]; + + spriteId = gBattleStruct->tera.indicatorSpriteId[battler] = CreateSpriteAtEnd(sTeraIndicatorSpriteTemplates[type], 0, y, 0); + gSprites[spriteId].tBattler = battler; + gSprites[spriteId].tPosX = x; + gSprites[spriteId].invisible = TRUE; +} + +void TeraIndicator_DestroySprite(u32 healthboxSpriteId) +{ + u8 spriteId = TeraIndicator_GetSpriteId(healthboxSpriteId); + DestroySprite(&gSprites[spriteId]); +} + +void TeraIndicator_UpdateType(u32 battler, u32 healthboxSpriteId) +{ + TeraIndicator_DestroySprite(healthboxSpriteId); + TeraIndicator_CreateSprite(battler, healthboxSpriteId); +} + +static void SpriteCb_TeraIndicator(struct Sprite *sprite) +{ + u32 battler = sprite->tBattler; + + sprite->x = gSprites[gHealthboxSpriteIds[battler]].x + sprite->tPosX + sprite->tLevelXDelta; + sprite->x2 = gSprites[gHealthboxSpriteIds[battler]].x2; + sprite->y2 = gSprites[gHealthboxSpriteIds[battler]].y2; +} + +#undef tBattler +#undef tType +#undef tPosX +#undef tLevelXDelta diff --git a/src/battle_tower.c b/src/battle_tower.c index 354e72ce54..6811cc7408 100644 --- a/src/battle_tower.c +++ b/src/battle_tower.c @@ -699,7 +699,10 @@ static const u8 *const *const sPartnerApprenticeTextTables[NUM_APPRENTICES] = #include "data/battle_frontier/battle_tent.h" #include "data/partner_parties.h" +const struct Trainer gBattlePartners[] = +{ #include "data/battle_partners.h" +}; static void (* const sBattleTowerFuncs[])(void) = { @@ -1368,7 +1371,7 @@ u8 GetFrontierOpponentClass(u16 trainerId) } else if (trainerId > TRAINER_PARTNER(PARTNER_NONE)) { - trainerClass = gBattlePartners[GetTrainerClassFromId(trainerId - TRAINER_PARTNER(PARTNER_NONE))].trainerClass; + trainerClass = gBattlePartners[trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerClass; } else if (trainerId < FRONTIER_TRAINERS_COUNT) { @@ -2681,7 +2684,7 @@ static void SetTowerInterviewData(void) GetBattleTowerTrainerLanguage(&gSaveBlock2Ptr->frontier.towerInterview.opponentLanguage, gTrainerBattleOpponent_A); gSaveBlock2Ptr->frontier.towerInterview.opponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[1]], MON_DATA_SPECIES, NULL); gSaveBlock2Ptr->frontier.towerInterview.playerSpecies = GetMonData(&gPlayerParty[gBattlerPartyIndexes[0]], MON_DATA_SPECIES, NULL); - for (i = 0; i < POKEMON_NAME_LENGTH + 1; i++) + for (i = 0; i < VANILLA_POKEMON_NAME_LENGTH + 1; i++) gSaveBlock2Ptr->frontier.towerInterview.opponentMonNickname[i] = gBattleMons[0].nickname[i]; gSaveBlock2Ptr->frontier.towerBattleOutcome = gBattleOutcome; } diff --git a/src/battle_util.c b/src/battle_util.c index af56f038ec..9c41a96b0e 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -707,7 +707,7 @@ void HandleAction_NothingIsFainted(void) void HandleAction_ActionFinished(void) { - u32 i, j; + u32 i, j, moveType; bool32 afterYouActive = gSpecialStatuses[gBattlerByTurnOrder[gCurrentTurnActionNumber + 1]].afterYou; *(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = gSelectedMonPartyId = PARTY_SIZE; gCurrentTurnActionNumber++; @@ -718,6 +718,16 @@ void HandleAction_ActionFinished(void) | HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT | HITMARKER_CHARGING | HITMARKER_NEVER_SET | HITMARKER_IGNORE_DISGUISE); + // check if Stellar type boost should be used up + GET_MOVE_TYPE(gCurrentMove, moveType); + if (IsTerastallized(gBattlerAttacker) + && GetBattlerTeraType(gBattlerAttacker) == TYPE_STELLAR + && gMovesInfo[gCurrentMove].category != DAMAGE_CATEGORY_STATUS + && IsTypeStellarBoosted(gBattlerAttacker, moveType)) + { + ExpendTypeStellarBoost(gBattlerAttacker, moveType); + } + gCurrentMove = 0; gBattleMoveDamage = 0; gMoveResultFlags = 0; @@ -896,36 +906,36 @@ static const uq4_12_t sPercentToModifier[] = #define X UQ_4_12 #define ______ X(1.0) // Regular effectiveness. +// Type matchup updates. Attacker Defender +#define STL_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_6 ? X(1.0) : X(0.5)) // Ghost/Dark -> Steel +#define PSN_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(2.0)) // Bug -> Poison +#define BUG_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(1.0) : X(2.0)) // Poison -> Bug +#define PSY_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(2.0) : X(0.0)) // Ghost -> Psychic +#define FIR_RS (B_UPDATED_TYPE_MATCHUPS >= GEN_2 ? X(0.5) : X(1.0)) // Ice -> Fire + static const uq4_12_t sTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] = {// Defender --> - // Attacker Normal Fighting Flying Poison Ground Rock Bug Ghost Steel Mystery Fire Water Grass Electric Psychic Ice Dragon Dark Fairy - [TYPE_NORMAL] = {______, ______, ______, ______, ______, X(0.5), ______, X(0.0), X(0.5), ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, - [TYPE_FIGHTING] = {X(2.0), ______, X(0.5), X(0.5), ______, X(2.0), X(0.5), X(0.0), X(2.0), ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), X(0.5)}, - [TYPE_FLYING] = {______, X(2.0), ______, ______, ______, X(0.5), X(2.0), ______, X(0.5), ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______}, - [TYPE_POISON] = {______, ______, ______, X(0.5), X(0.5), X(0.5), ______, X(0.5), X(0.0), ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, X(2.0)}, - [TYPE_GROUND] = {______, ______, X(0.0), X(2.0), ______, X(2.0), X(0.5), ______, X(2.0), ______, X(2.0), ______, X(0.5), X(2.0), ______, ______, ______, ______, ______}, - [TYPE_ROCK] = {______, X(0.5), X(2.0), ______, X(0.5), ______, X(2.0), ______, X(0.5), ______, X(2.0), ______, ______, ______, ______, X(2.0), ______, ______, ______}, - [TYPE_BUG] = {______, X(0.5), X(0.5), X(0.5), ______, ______, ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, X(2.0), ______, ______, X(2.0), X(0.5)}, -#if B_STEEL_RESISTANCES >= GEN_6 - [TYPE_GHOST] = {X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______}, -#else - [TYPE_GHOST] = {X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______}, -#endif - [TYPE_STEEL] = {______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, ______, X(2.0)}, - [TYPE_MYSTERY] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, - [TYPE_FIRE] = {______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(2.0), X(0.5), ______, ______}, - [TYPE_WATER] = {______, ______, ______, ______, X(2.0), X(2.0), ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, ______, X(0.5), ______, ______}, - [TYPE_GRASS] = {______, ______, X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), ______, X(0.5), ______, X(0.5), X(2.0), X(0.5), ______, ______, ______, X(0.5), ______, ______}, - [TYPE_ELECTRIC] = {______, ______, X(2.0), ______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, X(0.5), ______, ______}, - [TYPE_PSYCHIC] = {______, X(2.0), ______, X(2.0), ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, X(0.5), ______, ______, X(0.0), ______}, - [TYPE_ICE] = {______, ______, X(2.0), ______, X(2.0), ______, ______, ______, X(0.5), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(0.5), X(2.0), ______, ______}, - [TYPE_DRAGON] = {______, ______, ______, ______, ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, ______, ______, X(2.0), ______, X(0.0)}, -#if B_STEEL_RESISTANCES >= GEN_6 - [TYPE_DARK] = {______, X(0.5), ______, ______, ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5)}, -#else - [TYPE_DARK] = {______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5)}, -#endif - [TYPE_FAIRY] = {______, X(2.0), ______, X(0.5), ______, ______, ______, ______, X(0.5), ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(2.0), ______}, + // Attacker Normal Fighting Flying Poison Ground Rock Bug Ghost Steel Mystery Fire Water Grass Electric Psychic Ice Dragon Dark Fairy Stellar + [TYPE_NORMAL] = {______, ______, ______, ______, ______, X(0.5), ______, X(0.0), X(0.5), ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, + [TYPE_FIGHTING] = {X(2.0), ______, X(0.5), X(0.5), ______, X(2.0), X(0.5), X(0.0), X(2.0), ______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), X(0.5), ______}, + [TYPE_FLYING] = {______, X(2.0), ______, ______, ______, X(0.5), X(2.0), ______, X(0.5), ______, ______, ______, X(2.0), X(0.5), ______, ______, ______, ______, ______, ______}, + [TYPE_POISON] = {______, ______, ______, X(0.5), X(0.5), X(0.5), BUG_RS, X(0.5), X(0.0), ______, ______, ______, X(2.0), ______, ______, ______, ______, ______, X(2.0), ______}, + [TYPE_GROUND] = {______, ______, X(0.0), X(2.0), ______, X(2.0), X(0.5), ______, X(2.0), ______, X(2.0), ______, X(0.5), X(2.0), ______, ______, ______, ______, ______, ______}, + [TYPE_ROCK] = {______, X(0.5), X(2.0), ______, X(0.5), ______, X(2.0), ______, X(0.5), ______, X(2.0), ______, ______, ______, ______, X(2.0), ______, ______, ______, ______}, + [TYPE_BUG] = {______, X(0.5), X(0.5), PSN_RS, ______, ______, ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, X(2.0), ______, ______, X(2.0), X(0.5), ______}, + [TYPE_GHOST] = {X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, PSY_RS, ______, ______, X(0.5), ______, ______}, + [TYPE_STEEL] = {______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), ______, X(0.5), X(0.5), ______, X(0.5), ______, X(2.0), ______, ______, X(2.0), ______}, + [TYPE_MYSTERY] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, + [TYPE_FIRE] = {______, ______, ______, ______, ______, X(0.5), X(2.0), ______, X(2.0), ______, X(0.5), X(0.5), X(2.0), ______, ______, X(2.0), X(0.5), ______, ______, ______}, + [TYPE_WATER] = {______, ______, ______, ______, X(2.0), X(2.0), ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______}, + [TYPE_GRASS] = {______, ______, X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), ______, X(0.5), ______, X(0.5), X(2.0), X(0.5), ______, ______, ______, X(0.5), ______, ______, ______}, + [TYPE_ELECTRIC] = {______, ______, X(2.0), ______, X(0.0), ______, ______, ______, ______, ______, ______, X(2.0), X(0.5), X(0.5), ______, ______, X(0.5), ______, ______, ______}, + [TYPE_PSYCHIC] = {______, X(2.0), ______, X(2.0), ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, X(0.5), ______, ______, X(0.0), ______, ______}, + [TYPE_ICE] = {______, ______, X(2.0), ______, X(2.0), ______, ______, ______, X(0.5), ______, FIR_RS, X(0.5), X(2.0), ______, ______, X(0.5), X(2.0), ______, ______, ______}, + [TYPE_DRAGON] = {______, ______, ______, ______, ______, ______, ______, ______, X(0.5), ______, ______, ______, ______, ______, ______, ______, X(2.0), ______, X(0.0), ______}, + [TYPE_DARK] = {______, X(0.5), ______, ______, ______, ______, ______, X(2.0), STL_RS, ______, ______, ______, ______, ______, X(2.0), ______, ______, X(0.5), X(0.5), ______}, + [TYPE_FAIRY] = {______, X(2.0), ______, X(0.5), ______, ______, ______, ______, X(0.5), ______, X(0.5), ______, ______, ______, ______, ______, X(2.0), X(2.0), ______, ______}, + [TYPE_STELLAR] = {______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______, ______}, }; #undef ______ @@ -1276,7 +1286,7 @@ static bool32 IsBelchPreventingMove(u32 battler, u32 move) u32 TrySetCantSelectMoveBattleScript(u32 battler) { u32 limitations = 0; - u8 moveId = gBattleResources->bufferB[battler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST | RET_DYNAMAX); + u8 moveId = gBattleResources->bufferB[battler][2] & ~(RET_MEGA_EVOLUTION | RET_ULTRA_BURST | RET_DYNAMAX | RET_TERASTAL); u32 move = gBattleMons[battler].moves[moveId]; u32 holdEffect = GetBattlerHoldEffect(battler, TRUE); u16 *choicedMove = &gBattleStruct->choicedMove[battler]; @@ -3508,10 +3518,7 @@ u8 AtkCanceller_UnableToUseMove(u32 moveType) if (effect != 0) gBattlescriptCurrInstr = BattleScript_PowderMoveNoEffect; } - if (gProtectStructs[gBattlerAttacker].usesBouncedMove) // Edge case for bouncing a powder move against a grass type pokemon. - gBattleStruct->atkCancellerTracker = CANCELLER_END; - else - gBattleStruct->atkCancellerTracker++; + gBattleStruct->atkCancellerTracker++; break; case CANCELLER_POWDER_STATUS: if (gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER) @@ -4608,6 +4615,14 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + case ABILITY_TERAFORM_ZERO: + if (!gSpecialStatuses[battler].switchInAbilityDone + && gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR) + { + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + BattleScriptPushCursorAndCallback(BattleScript_ActivateTeraformZero); + effect++; + } case ABILITY_SCHOOLING: if (gBattleMons[battler].level < 20) break; @@ -4732,6 +4747,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && CountBattlerStatIncreases(BATTLE_PARTNER(battler), FALSE)) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattlerAttacker = battler; for (i = 0; i < NUM_BATTLE_STATS; i++) gBattleMons[battler].statStages[i] = gBattleMons[BATTLE_PARTNER(battler)].statStages[i]; gBattlerTarget = BATTLE_PARTNER(battler); @@ -4748,6 +4764,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && !(gBattleStruct->transformZeroToHero[side] & gBitTable[gBattlerPartyIndexes[battler]])) { gSpecialStatuses[battler].switchInAbilityDone = TRUE; + gBattlerAttacker = battler; gBattleStruct->transformZeroToHero[side] |= gBitTable[gBattlerPartyIndexes[battler]]; BattleScriptPushCursorAndCallback(BattleScript_ZeroToHeroActivates); effect++; @@ -4756,7 +4773,10 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 case ABILITY_HOSPITALITY: partner = BATTLE_PARTNER(battler); - if (!gSpecialStatuses[battler].switchInAbilityDone && IsDoubleBattle() && gBattleMons[partner].hp < gBattleMons[partner].maxHP) + if (!gSpecialStatuses[battler].switchInAbilityDone + && IsDoubleBattle() + && gBattleMons[partner].hp < gBattleMons[partner].maxHP + && IsBattlerAlive(partner)) { gBattlerTarget = partner; gBattlerAttacker = battler; @@ -4766,22 +4786,22 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; - case ABILITY_EMBODY_ASPECT_TEAL: - case ABILITY_EMBODY_ASPECT_HEARTHFLAME: - case ABILITY_EMBODY_ASPECT_WELLSPRING: - case ABILITY_EMBODY_ASPECT_CORNERSTONE: + case ABILITY_EMBODY_ASPECT_TEAL_MASK: + case ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK: + case ABILITY_EMBODY_ASPECT_WELLSPRING_MASK: + case ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK: if (!gSpecialStatuses[battler].switchInAbilityDone) { - u32 stat = STAT_SPATK; + u32 stat; - if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_TEAL) - stat = STAT_SPATK; - else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME) + if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK) stat = STAT_ATK; - else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_WELLSPRING) + else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_WELLSPRING_MASK) stat = STAT_SPDEF; - else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_CORNERSTONE) + else if (gLastUsedAbility == ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK) stat = STAT_DEF; + else //ABILITY_EMBODY_ASPECT_TEAL_MASK + stat = STAT_SPEED; if (CompareStat(battler, stat, MAX_STAT_STAGE, CMP_EQUAL)) break; @@ -4794,6 +4814,18 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + case ABILITY_TERA_SHIFT: + if (!gSpecialStatuses[battler].switchInAbilityDone + && gBattleMons[battler].species == SPECIES_TERAPAGOS_NORMAL + && TryBattleFormChange(battler, FORM_CHANGE_BATTLE_SWITCH)) + { + gBattlerAttacker = battler; + gBattleScripting.abilityPopupOverwrite = gLastUsedAbility = ABILITY_TERA_SHIFT; + gSpecialStatuses[battler].switchInAbilityDone = TRUE; + BattleScriptPushCursorAndCallback(BattleScript_AttackerFormChangeWithStringEnd3); + effect++; + } + break; } break; case ABILITYEFFECT_ENDTURN: // 1 @@ -5349,6 +5381,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 && gMovesInfo[move].power != 0 && TARGET_TURN_DAMAGED && !IS_BATTLER_OF_TYPE(battler, moveType) + && moveType != TYPE_STELLAR && gBattleMons[battler].hp != 0) { SET_BATTLER_TYPE(battler, moveType); @@ -5762,6 +5795,18 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 effect++; } break; + case ABILITY_POISON_PUPPETEER: + if (gBattleMons[gBattlerAttacker].species == SPECIES_PECHARUNT + && gBattleStruct->poisonPuppeteerConfusion == TRUE + && CanBeConfused(gBattlerTarget)) + { + gBattleStruct->poisonPuppeteerConfusion = FALSE; + gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION; + PREPARE_ABILITY_BUFFER(gBattleTextBuff1, gLastUsedAbility); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_AbilityStatusEffect; + effect++; + } } break; case ABILITYEFFECT_MOVE_END_OTHER: // Abilities that activate on *another* battler's moveend: Dancer, Soul-Heart, Receiver, Symbiosis @@ -5783,6 +5828,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32 // Set the target to the original target of the mon that first used a Dance move gBattlerTarget = gBattleScripting.savedBattler & 0x3; + // Edge case for dance moves that hit multiply targets + gHitMarker &= ~HITMARKER_NO_ATTACKSTRING; + // Make sure that the target isn't an ally - if it is, target the original user if (GetBattlerSide(gBattlerTarget) == GetBattlerSide(gBattlerAttacker)) gBattlerTarget = (gBattleScripting.savedBattler & 0xF0) >> 4; @@ -8016,10 +8064,6 @@ u32 GetMoveTarget(u16 move, u8 setTarget) else moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, move); - // Special cases - if (move == MOVE_CURSE && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GHOST)) - moveTarget = MOVE_TARGET_USER; - switch (moveTarget) { case MOVE_TARGET_SELECTED: @@ -8830,6 +8874,10 @@ static inline u32 CalcMoveBasePower(u32 move, u32 battlerAtk, u32 battlerDef, u3 if (RandomPercentage(RNG_FICKLE_BEAM, 30)) basePower *= 2; break; + case EFFECT_TERA_BLAST: + if (IsTerastallized(battlerAtk) && GetBattlerTeraType(battlerAtk) == TYPE_STELLAR) + basePower = 100; + break; case EFFECT_LAST_RESPECTS: basePower += (basePower * min(100, GetBattlerSideFaintCounter(battlerAtk))); break; @@ -9198,6 +9246,19 @@ static inline u32 CalcMoveBasePowerAfterModifiers(u32 move, u32 battlerAtk, u32 modifier = uq4_12_multiply(modifier, UQ_4_12(1.1)); break; } + + // Terastallization boosts weak, non-priority, non-multi hit moves after modifiers to 60 BP. + if (IsTerastallized(battlerAtk) + && (moveType == GetBattlerTeraType(battlerAtk) + || (GetBattlerTeraType(battlerAtk) == TYPE_STELLAR && IsTypeStellarBoosted(battlerAtk, moveType))) + && uq4_12_multiply_by_int_half_down(modifier, basePower) < 60 + && gMovesInfo[move].strikeCount < 2 + && gMovesInfo[move].effect != EFFECT_MULTI_HIT + && gMovesInfo[move].priority == 0) + { + return 60; + } + return uq4_12_multiply_by_int_half_down(modifier, basePower); } @@ -9900,7 +9961,10 @@ static inline s32 DoMoveDamageCalcVars(u32 move, u32 battlerAtk, u32 battlerDef, dmg /= 100; } - DAMAGE_APPLY_MODIFIER(GetSameTypeAttackBonusModifier(battlerAtk, moveType, move, abilityAtk)); + if (IsTerastallized(battlerAtk)) + DAMAGE_APPLY_MODIFIER(GetTeraMultiplier(battlerAtk, moveType)); + else + DAMAGE_APPLY_MODIFIER(GetSameTypeAttackBonusModifier(battlerAtk, moveType, move, abilityAtk)); DAMAGE_APPLY_MODIFIER(typeEffectivenessModifier); DAMAGE_APPLY_MODIFIER(GetBurnOrFrostBiteModifier(battlerAtk, move, abilityAtk)); DAMAGE_APPLY_MODIFIER(GetZMaxMoveAgainstProtectionModifier(battlerDef, move)); @@ -10057,6 +10121,8 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move mod = UQ_4_12(1.0); if (moveType == TYPE_FIRE && gDisableStructs[battlerDef].tarShot) mod = UQ_4_12(2.0); + if (moveType == TYPE_STELLAR && IsTerastallized(battlerDef)) + mod = UQ_4_12(2.0); // B_WEATHER_STRONG_WINDS weakens Super Effective moves against Flying-type Pokémon if (gBattleWeather & B_WEATHER_STRONG_WINDS && WEATHER_HAS_EFFECT) @@ -10065,6 +10131,13 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move mod = UQ_4_12(1.0); } + if (gBattleStruct->distortedTypeMatchups & gBitTable[battlerDef]) + { + mod = UQ_4_12(0.5); + if (recordAbilities) + RecordAbilityBattle(battlerDef, GetBattlerAbility(battlerDef)); + } + *modifier = uq4_12_multiply(*modifier, mod); } @@ -10107,12 +10180,12 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov { u32 illusionSpecies; - MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 0), battlerAtk, recordAbilities); - if (GetBattlerType(battlerDef, 1) != GetBattlerType(battlerDef, 0)) - MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 1), battlerAtk, recordAbilities); - if (GetBattlerType(battlerDef, 2) != TYPE_MYSTERY && GetBattlerType(battlerDef, 2) != GetBattlerType(battlerDef, 1) - && GetBattlerType(battlerDef, 2) != GetBattlerType(battlerDef, 0)) - MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 2), battlerAtk, recordAbilities); + MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 0, FALSE), battlerAtk, recordAbilities); + if (GetBattlerType(battlerDef, 1, FALSE) != GetBattlerType(battlerDef, 0, FALSE)) + MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 1, FALSE), battlerAtk, recordAbilities); + if (GetBattlerType(battlerDef, 2, FALSE) != TYPE_MYSTERY && GetBattlerType(battlerDef, 2, FALSE) != GetBattlerType(battlerDef, 1, FALSE) + && GetBattlerType(battlerDef, 2, FALSE) != GetBattlerType(battlerDef, 0, FALSE)) + MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, GetBattlerType(battlerDef, 2, FALSE), battlerAtk, recordAbilities); if (recordAbilities && (illusionSpecies = GetIllusionMonSpecies(battlerDef))) TryNoticeIllusionInTypeEffectiveness(move, moveType, battlerAtk, battlerDef, modifier, illusionSpecies); @@ -10515,7 +10588,8 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method) targetSpecies = formChanges[i].targetSpecies; break; case FORM_CHANGE_BATTLE_SWITCH: - targetSpecies = formChanges[i].targetSpecies; + if (formChanges[i].param1 == GetBattlerAbility(battler) || formChanges[i].param1 == ABILITY_NONE) + targetSpecies = formChanges[i].targetSpecies; break; case FORM_CHANGE_BATTLE_HP_PERCENT: if (formChanges[i].param1 == GetBattlerAbility(battler)) @@ -10651,8 +10725,8 @@ bool32 TryBattleFormChange(u32 battler, u16 method) bool32 DoBattlersShareType(u32 battler1, u32 battler2) { s32 i; - u8 types1[3] = {GetBattlerType(battler1, 0), GetBattlerType(battler1, 1), GetBattlerType(battler1, 2)}; - u8 types2[3] = {GetBattlerType(battler2, 0), GetBattlerType(battler2, 1), GetBattlerType(battler2, 2)}; + u8 types1[3] = {GetBattlerType(battler1, 0, FALSE), GetBattlerType(battler1, 1, FALSE), GetBattlerType(battler1, 2, FALSE)}; + u8 types2[3] = {GetBattlerType(battler2, 0, FALSE), GetBattlerType(battler2, 1, FALSE), GetBattlerType(battler2, 2, FALSE)}; if (types1[2] == TYPE_MYSTERY) types1[2] = types1[0]; @@ -10681,7 +10755,7 @@ bool32 CanBattlerGetOrLoseItem(u32 battler, u16 itemId) else if (holdEffect == HOLD_EFFECT_Z_CRYSTAL) return FALSE; else if (holdEffect == HOLD_EFFECT_BOOSTER_ENERGY - && (gSpeciesInfo[gBattleMons[gBattlerAttacker].species].isParadoxForm || gSpeciesInfo[gBattleMons[gBattlerTarget].species].isParadoxForm)) + && (gSpeciesInfo[gBattleMons[gBattlerAttacker].species].isParadox || gSpeciesInfo[gBattleMons[gBattlerTarget].species].isParadox)) return FALSE; else return TRUE; @@ -10834,7 +10908,7 @@ static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler) return FALSE; } -// Photon geyser & light that burns the sky +// Photon Geyser, Light That Burns the Sky, Tera Blast u8 GetCategoryBasedOnStats(u32 battler) { u32 attack = gBattleMons[battler].attack; @@ -11145,11 +11219,17 @@ bool32 IsBattlerWeatherAffected(u32 battler, u32 weatherFlags) // Possible return values are defined in battle.h following MOVE_TARGET_SELECTED u32 GetBattlerMoveTargetType(u32 battler, u32 move) { - if (gMovesInfo[move].effect == EFFECT_EXPANDING_FORCE + if (move == MOVE_CURSE + && !IS_BATTLER_OF_TYPE(battler, TYPE_GHOST)) + return MOVE_TARGET_USER; + else if (gMovesInfo[move].effect == EFFECT_EXPANDING_FORCE && IsBattlerTerrainAffected(battler, STATUS_FIELD_PSYCHIC_TERRAIN)) return MOVE_TARGET_BOTH; - else - return gMovesInfo[move].target; + else if (gMovesInfo[move].effect == EFFECT_TERA_STARSTORM + && gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR) + return MOVE_TARGET_BOTH; + + return gMovesInfo[move].target; } bool32 CanTargetBattler(u32 battlerAtk, u32 battlerDef, u16 move) @@ -11392,17 +11472,23 @@ bool8 IsMonBannedFromSkyBattles(u16 species) } } -u8 GetBattlerType(u32 battler, u8 typeIndex) +u8 GetBattlerType(u32 battler, u8 typeIndex, bool32 ignoreTera) { + u32 teraType = GetBattlerTeraType(battler); u16 types[3] = {0}; types[0] = gBattleMons[battler].type1; types[1] = gBattleMons[battler].type2; types[2] = gBattleMons[battler].type3; + // Handle Terastallization + if (IsTerastallized(battler) && teraType != TYPE_STELLAR && !ignoreTera) + return GetBattlerTeraType(battler); + // Handle Roost's Flying-type suppression if (typeIndex == 0 || typeIndex == 1) { - if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST) + if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST + && !IsTerastallized(battler)) { if (types[0] == TYPE_FLYING && types[1] == TYPE_FLYING) return B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY; @@ -11417,6 +11503,8 @@ u8 GetBattlerType(u32 battler, u8 typeIndex) void RemoveBattlerType(u32 battler, u8 type) { u32 i; + if (IsTerastallized(battler)) // don't remove type if Terastallized + return; for (i = 0; i < 3; i++) { if (*(u8 *)(&gBattleMons[battler].type1 + i) == type) diff --git a/src/contest.c b/src/contest.c index f0d0d527ed..be8bb3e92b 100644 --- a/src/contest.c +++ b/src/contest.c @@ -1085,6 +1085,18 @@ static const s8 sContestExcitementTable[CONTEST_CATEGORIES_COUNT][CONTEST_CATEGO } }; +static void CopyNicknameToFit(u8 *dest, u32 contestant) +{ + u8 *end = StringCopy(dest, gContestMons[contestant].nickname); + WrapFontIdToFit(dest, end, FONT_NORMAL, 60); +} + +static void CopyMoveNameToFit(u8 *dest, u32 move) +{ + u8 *end = StringCopy(dest, GetMoveName(move)); + WrapFontIdToFit(dest, end, FONT_NORMAL, 84); +} + static void TaskDummy1(u8 taskId) { } @@ -1636,7 +1648,7 @@ static void Task_ShowMoveSelectScreen(u8 taskId) moveNameBuffer = StringCopy(moveNameBuffer, GetMoveName(move)); FillWindowPixelBuffer(i + MOVE_WINDOWS_START, PIXEL_FILL(0)); - Contest_PrintTextToBg0WindowAt(i + MOVE_WINDOWS_START, moveName, 5, 1, FONT_NARROW); + Contest_PrintTextToBg0WindowAt(i + MOVE_WINDOWS_START, moveName, 5, 1, GetFontIdToFit(moveName, FONT_NARROW, 0, WindowWidthPx(i + MOVE_WINDOWS_START) - 11)); } DrawMoveSelectArrow(eContest.playerMoveChoice); @@ -1899,7 +1911,7 @@ static void Task_DoAppeals(u8 taskId) else { ContestClearGeneralTextWindow(); - StringCopy(gStringVar1, gContestMons[contestant].nickname); + CopyNicknameToFit(gStringVar1, contestant); if (eContestantStatus[contestant].currMove < MOVES_COUNT) StringCopy(gStringVar2, GetMoveName(eContestantStatus[contestant].currMove)); else @@ -2165,7 +2177,7 @@ static void Task_DoAppeals(u8 taskId) || eContestantStatus[contestant].turnSkipped) { ContestClearGeneralTextWindow(); - StringCopy(gStringVar1, gContestMons[contestant].nickname); + CopyNicknameToFit(gStringVar1, contestant); StringExpandPlaceholders(gStringVar4, gText_MonCantAppealNextTurn); Contest_StartTextPrinter(gStringVar4, TRUE); } @@ -2207,7 +2219,7 @@ static void Task_DoAppeals(u8 taskId) { // Started combo ContestClearGeneralTextWindow(); - StringCopy(gStringVar1, gContestMons[contestant].nickname); + CopyNicknameToFit(gStringVar1, contestant); StringExpandPlaceholders(gStringVar4, gText_JudgeLookedAtMonExpectantly); Contest_StartTextPrinter(gStringVar4, TRUE); DoJudgeSpeechBubble(JUDGE_SYMBOL_ONE_EXCLAMATION); @@ -2251,7 +2263,7 @@ static void Task_DoAppeals(u8 taskId) if (eContestantStatus[contestant].repeatedMove) { ContestClearGeneralTextWindow(); - StringCopy(gStringVar1, gContestMons[contestant].nickname); + CopyNicknameToFit(gStringVar1, contestant); StringExpandPlaceholders(gStringVar4, gText_RepeatedAppeal); Contest_StartTextPrinter(gStringVar4, TRUE); gTasks[taskId].tCounter = 0; @@ -2295,7 +2307,7 @@ static void Task_DoAppeals(u8 taskId) if (eContestantStatus[contestant].overrideCategoryExcitementMod) { r3 = 1; - StringCopy(gStringVar3, GetMoveName(eContestantStatus[contestant].currMove)); + CopyMoveNameToFit(gStringVar3, eContestantStatus[contestant].currMove); } else { @@ -2306,7 +2318,7 @@ static void Task_DoAppeals(u8 taskId) r3 = 0; ContestClearGeneralTextWindow(); - StringCopy(gStringVar1, gContestMons[contestant].nickname); + CopyNicknameToFit(gStringVar1, contestant); eContest.applauseLevel += r3; if (eContest.applauseLevel < 0) eContest.applauseLevel = 0; @@ -2428,9 +2440,9 @@ static void Task_DoAppeals(u8 taskId) return; case APPEALSTATE_PRINT_CROWD_WATCHES_MSG: ContestClearGeneralTextWindow(); - StringCopy(gStringVar3, gContestMons[eContestExcitement.freezer].nickname); - StringCopy(gStringVar1, gContestMons[contestant].nickname); - StringCopy(gStringVar2, GetMoveName(eContestantStatus[contestant].currMove)); + CopyNicknameToFit(gStringVar3, eContestExcitement.freezer); + CopyNicknameToFit(gStringVar1, contestant); + CopyMoveNameToFit(gStringVar2, eContestantStatus[contestant].currMove); StringExpandPlaceholders(gStringVar4, gText_CrowdContinuesToWatchMon); Contest_StartTextPrinter(gStringVar4, TRUE); gTasks[taskId].tState = APPEALSTATE_PRINT_MON_MOVE_IGNORED_MSG; @@ -2455,8 +2467,8 @@ static void Task_DoAppeals(u8 taskId) if (eContestantStatus[contestant].hasJudgesAttention) eContestantStatus[contestant].hasJudgesAttention = FALSE; StartStopFlashJudgeAttentionEye(contestant); - StringCopy(gStringVar1, gContestMons[contestant].nickname); - StringCopy(gStringVar2, GetMoveName(eContestantStatus[contestant].currMove)); + CopyNicknameToFit(gStringVar1, contestant); + CopyMoveNameToFit(gStringVar2, eContestantStatus[contestant].currMove); StringExpandPlaceholders(gStringVar4, gText_MonWasTooNervousToMove); Contest_StartTextPrinter(gStringVar4, TRUE); gTasks[taskId].tState = APPEALSTATE_WAIT_TOO_NERVOUS_MSG; @@ -2500,7 +2512,7 @@ static void Task_DoAppeals(u8 taskId) return; case APPEALSTATE_PRINT_SKIP_TURN_MSG: ContestClearGeneralTextWindow(); - StringCopy(gStringVar1, gContestMons[contestant].nickname); + CopyNicknameToFit(gStringVar1, contestant); StringExpandPlaceholders(gStringVar4, gText_MonWasWatchingOthers); Contest_StartTextPrinter(gStringVar4, TRUE); gTasks[taskId].tState = APPEALSTATE_WAIT_SKIP_TURN_MSG; @@ -3133,7 +3145,7 @@ static void PrintContestantMonName(u8 contestant) static void PrintContestantMonNameWithColor(u8 contestant, u8 color) { Contest_CopyStringWithColor(gContestMons[contestant].nickname, color); - Contest_PrintTextToBg0WindowAt(gContestantTurnOrder[contestant], gDisplayedStringBattle, 5, 1, FONT_NARROW); + Contest_PrintTextToBg0WindowAt(gContestantTurnOrder[contestant], gDisplayedStringBattle, 5, 1, GetFontIdToFit(gContestMons[contestant].nickname, FONT_NARROW, 0, 50)); } static u16 CalculateContestantRound1Points(u8 who, u8 contestCategory) @@ -5642,7 +5654,7 @@ bool8 SaveContestWinner(u8 rank) gSaveBlock1Ptr->contestWinners[id].personality = gContestMons[i].personality; gSaveBlock1Ptr->contestWinners[id].species = gContestMons[i].species; gSaveBlock1Ptr->contestWinners[id].trainerId = gContestMons[i].otId; - StringCopy(gSaveBlock1Ptr->contestWinners[id].monName, gContestMons[i].nickname); + StringCopyN(gSaveBlock1Ptr->contestWinners[id].monName, gContestMons[i].nickname, VANILLA_POKEMON_NAME_LENGTH); StringCopy(gSaveBlock1Ptr->contestWinners[id].trainerName, gContestMons[i].trainerName); if(gLinkContestFlags & LINK_CONTEST_FLAG_IS_LINK) gSaveBlock1Ptr->contestWinners[id].contestRank = CONTEST_RANK_LINK; @@ -5661,7 +5673,7 @@ bool8 SaveContestWinner(u8 rank) gCurContestWinner.isShiny = gContestMons[i].isShiny; gCurContestWinner.trainerId = gContestMons[i].otId; gCurContestWinner.species = gContestMons[i].species; - StringCopy(gCurContestWinner.monName, gContestMons[i].nickname); + StringCopyN(gCurContestWinner.monName, gContestMons[i].nickname, VANILLA_POKEMON_NAME_LENGTH); StringCopy(gCurContestWinner.trainerName, gContestMons[i].trainerName); gCurContestWinner.contestCategory = captionId; } diff --git a/src/contest_util.c b/src/contest_util.c index 721be3360a..90af687008 100644 --- a/src/contest_util.c +++ b/src/contest_util.c @@ -130,6 +130,7 @@ static void LoadContestResultsTitleBarTilemaps(void); static u8 GetNumPreliminaryPoints(u8, bool8); static s8 GetNumRound2Points(u8, bool8); static void AddContestTextPrinter(int, u8 *, int); +static void AddContestTextPrinterFitWidth(int, u8 *, int, int); static void AllocContestResults(void); static void FreeContestResults(void); static void LoadAllContestMonIcons(u8, u8); @@ -504,7 +505,7 @@ static void LoadContestMonName(u8 monIndex) str = StringCopy(gDisplayedStringBattle, gText_ColorDarkGray); StringCopy(str, mon->nickname); - AddContestTextPrinter(monIndex, gDisplayedStringBattle, 0); + AddContestTextPrinterFitWidth(monIndex, gDisplayedStringBattle, 0, 49); StringCopy(str, gText_Slash); StringAppend(str, mon->trainerName); AddContestTextPrinter(monIndex, gDisplayedStringBattle, 50); @@ -1916,12 +1917,12 @@ static void FreeContestResults(void) FreeMonSpritesGfx(); } -static void AddContestTextPrinter(int windowId, u8 *str, int x) +static void AddContestTextPrinterFitWidth(int windowId, u8 *str, int x, int widthPx) { struct TextPrinterTemplate textPrinter; textPrinter.currentChar = str; textPrinter.windowId = windowId; - textPrinter.fontId = FONT_NARROW; + textPrinter.fontId = GetFontIdToFit(str, FONT_NARROW, 0, widthPx); textPrinter.x = x; textPrinter.y = 2; textPrinter.currentX = x; @@ -1936,6 +1937,11 @@ static void AddContestTextPrinter(int windowId, u8 *str, int x) PutWindowTilemap(windowId); } +static void AddContestTextPrinter(int windowId, u8 *str, int x) +{ + AddContestTextPrinterFitWidth(windowId, str, x, DISPLAY_WIDTH); +} + void TryEnterContestMon(void) { u8 eligibility = GetContestEntryEligibility(&gPlayerParty[gContestMonPartyIndex]); diff --git a/src/data/abilities.h b/src/data/abilities.h index 8c26934d9a..a65d4e8c24 100644 --- a/src/data/abilities.h +++ b/src/data/abilities.h @@ -1276,6 +1276,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] = .name = _("Fur Coat"), .description = COMPOUND_STRING("Raises Defense."), .aiRating = 7, + .breakable = TRUE, }, [ABILITY_MAGICIAN] = @@ -2472,7 +2473,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] = .breakable = TRUE, }, - [ABILITY_EMBODY_ASPECT_TEAL] = + [ABILITY_EMBODY_ASPECT_TEAL_MASK] = { #if B_EXPANDED_ABILITY_NAMES == TRUE .name = _("Embody Aspect"), @@ -2487,7 +2488,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] = .failsOnImposter = TRUE, }, - [ABILITY_EMBODY_ASPECT_HEARTHFLAME] = + [ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK] = { #if B_EXPANDED_ABILITY_NAMES == TRUE .name = _("Embody Aspect"), @@ -2502,7 +2503,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] = .failsOnImposter = TRUE, }, - [ABILITY_EMBODY_ASPECT_WELLSPRING] = + [ABILITY_EMBODY_ASPECT_WELLSPRING_MASK] = { #if B_EXPANDED_ABILITY_NAMES == TRUE .name = _("Embody Aspect"), @@ -2517,7 +2518,7 @@ const struct Ability gAbilitiesInfo[ABILITIES_COUNT] = .failsOnImposter = TRUE, }, - [ABILITY_EMBODY_ASPECT_CORNERSTONE] = + [ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK] = { #if B_EXPANDED_ABILITY_NAMES == TRUE .name = _("Embody Aspect"), diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 52efcb1212..29acfc4630 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -2230,4 +2230,16 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = .battleTvScore = 0, // TODO: Assign points .encourageEncore = TRUE, }, + + [EFFECT_TERA_BLAST] = + { + .battleScript = BattleScript_EffectPhotonGeyser, + .battleTvScore = 0, // TODO: Assign points + }, + + [EFFECT_TERA_STARSTORM] = + { + .battleScript = BattleScript_EffectPhotonGeyser, + .battleTvScore = 0, // TODO: Assign points + }, }; diff --git a/src/data/battle_partners.h b/src/data/battle_partners.h index 39bb91132f..ae0b753cb3 100644 --- a/src/data/battle_partners.h +++ b/src/data/battle_partners.h @@ -1,20 +1,105 @@ -const struct Trainer gBattlePartners[] = { +// +// DO NOT MODIFY THIS FILE! It is auto-generated from src/data/battle_partners.party +// +// If you want to modify this file set COMPETITIVE_PARTY_SYNTAX to FALSE +// in include/config.h and remove this notice. +// Use sed -i '/^#line/d' 'src/data/battle_partners.h' to remove #line markers. +// + +#line 1 "src/data/battle_partners.party" + +#line 1 [PARTNER_NONE] = { - .party = NULL, +#line 3 .trainerClass = TRAINER_CLASS_PKMN_TRAINER_1, - .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE, - .trainerPic = TRAINER_PIC_HIKER, - .trainerName = _(""), - .items = {}, +#line 4 + .trainerPic = TRAINER_BACK_PIC_BRENDAN, + .encounterMusic_gender = +#line 6 + TRAINER_ENCOUNTER_MUSIC_MALE, + .partySize = 0, + .party = (const struct TrainerMon[]) + { + }, }, - +#line 8 [PARTNER_STEVEN] = { - .party = TRAINER_PARTY(sParty_StevenPartner), - .trainerClass = TRAINER_CLASS_RIVAL, - .encounterMusic_gender = TRAINER_ENCOUNTER_MUSIC_MALE, - .trainerPic = TRAINER_BACK_PIC_STEVEN, +#line 9 .trainerName = _("STEVEN"), +#line 10 + .trainerClass = TRAINER_CLASS_RIVAL, +#line 11 + .trainerPic = TRAINER_BACK_PIC_STEVEN, + .encounterMusic_gender = +#line 13 + TRAINER_ENCOUNTER_MUSIC_MALE, + .partySize = 3, + .party = (const struct TrainerMon[]) + { + { +#line 15 + .species = SPECIES_METANG, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 19 + .ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0), +#line 18 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 17 + .lvl = 42, +#line 16 + .nature = NATURE_BRAVE, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 20 + MOVE_LIGHT_SCREEN, + MOVE_PSYCHIC, + MOVE_REFLECT, + MOVE_METAL_CLAW, + }, + }, + { +#line 25 + .species = SPECIES_SKARMORY, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 29 + .ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252), +#line 28 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 27 + .lvl = 43, +#line 26 + .nature = NATURE_IMPISH, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 30 + MOVE_TOXIC, + MOVE_AERIAL_ACE, + MOVE_PROTECT, + MOVE_STEEL_WING, + }, + }, + { +#line 35 + .species = SPECIES_AGGRON, + .gender = TRAINER_MON_RANDOM_GENDER, +#line 39 + .ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6), +#line 38 + .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), +#line 37 + .lvl = 44, +#line 36 + .nature = NATURE_ADAMANT, + .dynamaxLevel = MAX_DYNAMAX_LEVEL, + .moves = { +#line 40 + MOVE_THUNDER, + MOVE_PROTECT, + MOVE_SOLAR_BEAM, + MOVE_DRAGON_CLAW, + }, + }, + }, }, -}; diff --git a/src/data/battle_partners.party b/src/data/battle_partners.party new file mode 100644 index 0000000000..e1ecfe35fa --- /dev/null +++ b/src/data/battle_partners.party @@ -0,0 +1,43 @@ +=== PARTNER_NONE === +Name: +Class: Pkmn Trainer 1 +Pic: Brendan +Gender: Male +Music: Male + +=== PARTNER_STEVEN === +Name: STEVEN +Class: Rival +Pic: Steven +Gender: Male +Music: Male + +Metang +Brave Nature +Level: 42 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 Atk / 252 Def / 6 SpA +- Light Screen +- Psychic +- Reflect +- Metal Claw + +Skarmory +Impish Nature +Level: 43 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 HP / 6 SpA / 252 SpD +- Toxic +- Aerial Ace +- Protect +- Steel Wing + +Aggron +Adamant Nature +Level: 44 +IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe +EVs: 252 Atk / 252 SpA / 6 SpD +- Thunder +- Protect +- Solar Beam +- Dragon Claw diff --git a/src/data/item_icon_table.h b/src/data/item_icon_table.h index 9d3caea9d9..d4d4a19c58 100644 --- a/src/data/item_icon_table.h +++ b/src/data/item_icon_table.h @@ -621,115 +621,6 @@ const u32 *const gItemIconTable[ITEMS_COUNT + 1][2] = [ITEM_KEE_BERRY] = {gItemIcon_KeeBerry, gItemIconPalette_KeeBerry}, [ITEM_MARANGA_BERRY] = {gItemIcon_MarangaBerry, gItemIconPalette_MarangaBerry}, [ITEM_ENIGMA_BERRY_E_READER] = {gItemIcon_EnigmaBerry, gItemIconPalette_EnigmaBerry}, - // TMs/HMs - [ITEM_TM01] = {gItemIcon_TM, gItemIconPalette_FightingTMHM}, - [ITEM_TM02] = {gItemIcon_TM, gItemIconPalette_DragonTMHM}, - [ITEM_TM03] = {gItemIcon_TM, gItemIconPalette_WaterTMHM}, - [ITEM_TM04] = {gItemIcon_TM, gItemIconPalette_PsychicTMHM}, - [ITEM_TM05] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM06] = {gItemIcon_TM, gItemIconPalette_PoisonTMHM}, - [ITEM_TM07] = {gItemIcon_TM, gItemIconPalette_IceTMHM}, - [ITEM_TM08] = {gItemIcon_TM, gItemIconPalette_FightingTMHM}, - [ITEM_TM09] = {gItemIcon_TM, gItemIconPalette_GrassTMHM}, - [ITEM_TM10] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM11] = {gItemIcon_TM, gItemIconPalette_FireTMHM}, - [ITEM_TM12] = {gItemIcon_TM, gItemIconPalette_DarkTMHM}, - [ITEM_TM13] = {gItemIcon_TM, gItemIconPalette_IceTMHM}, - [ITEM_TM14] = {gItemIcon_TM, gItemIconPalette_IceTMHM}, - [ITEM_TM15] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM16] = {gItemIcon_TM, gItemIconPalette_PsychicTMHM}, - [ITEM_TM17] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM18] = {gItemIcon_TM, gItemIconPalette_WaterTMHM}, - [ITEM_TM19] = {gItemIcon_TM, gItemIconPalette_GrassTMHM}, - [ITEM_TM20] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM21] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM22] = {gItemIcon_TM, gItemIconPalette_GrassTMHM}, - [ITEM_TM23] = {gItemIcon_TM, gItemIconPalette_SteelTMHM}, - [ITEM_TM24] = {gItemIcon_TM, gItemIconPalette_ElectricTMHM}, - [ITEM_TM25] = {gItemIcon_TM, gItemIconPalette_ElectricTMHM}, - [ITEM_TM26] = {gItemIcon_TM, gItemIconPalette_GroundTMHM}, - [ITEM_TM27] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM28] = {gItemIcon_TM, gItemIconPalette_GroundTMHM}, - [ITEM_TM29] = {gItemIcon_TM, gItemIconPalette_PsychicTMHM}, - [ITEM_TM30] = {gItemIcon_TM, gItemIconPalette_GhostTMHM}, - [ITEM_TM31] = {gItemIcon_TM, gItemIconPalette_FightingTMHM}, - [ITEM_TM32] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM33] = {gItemIcon_TM, gItemIconPalette_PsychicTMHM}, - [ITEM_TM34] = {gItemIcon_TM, gItemIconPalette_ElectricTMHM}, - [ITEM_TM35] = {gItemIcon_TM, gItemIconPalette_FireTMHM}, - [ITEM_TM36] = {gItemIcon_TM, gItemIconPalette_PoisonTMHM}, - [ITEM_TM37] = {gItemIcon_TM, gItemIconPalette_RockTMHM}, - [ITEM_TM38] = {gItemIcon_TM, gItemIconPalette_FireTMHM}, - [ITEM_TM39] = {gItemIcon_TM, gItemIconPalette_RockTMHM}, - [ITEM_TM40] = {gItemIcon_TM, gItemIconPalette_FlyingTMHM}, - [ITEM_TM41] = {gItemIcon_TM, gItemIconPalette_DarkTMHM}, - [ITEM_TM42] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM43] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM44] = {gItemIcon_TM, gItemIconPalette_PsychicTMHM}, - [ITEM_TM45] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, - [ITEM_TM46] = {gItemIcon_TM, gItemIconPalette_DarkTMHM}, - [ITEM_TM47] = {gItemIcon_TM, gItemIconPalette_SteelTMHM}, - [ITEM_TM48] = {gItemIcon_TM, gItemIconPalette_PsychicTMHM}, - [ITEM_TM49] = {gItemIcon_TM, gItemIconPalette_DarkTMHM}, - [ITEM_TM50] = {gItemIcon_TM, gItemIconPalette_FireTMHM}, - [ITEM_TM51] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM52] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM53] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM54] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM55] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM56] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM57] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM58] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM59] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM60] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM61] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM62] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM63] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM64] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM65] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM66] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM67] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM68] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM69] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM70] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM71] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM72] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM73] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM74] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM75] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM76] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM77] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM78] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM79] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM80] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM81] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM82] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM83] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM84] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM85] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM86] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM87] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM88] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM89] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM90] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM91] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM92] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM93] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM94] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM95] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM96] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM97] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM98] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM99] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_TM100] = {gItemIcon_TM, gItemIconPalette_NormalTMHM}, // Todo - [ITEM_HM01] = {gItemIcon_HM, gItemIconPalette_NormalTMHM}, - [ITEM_HM02] = {gItemIcon_HM, gItemIconPalette_FlyingTMHM}, - [ITEM_HM03] = {gItemIcon_HM, gItemIconPalette_WaterTMHM}, - [ITEM_HM04] = {gItemIcon_HM, gItemIconPalette_NormalTMHM}, - [ITEM_HM05] = {gItemIcon_HM, gItemIconPalette_NormalTMHM}, - [ITEM_HM06] = {gItemIcon_HM, gItemIconPalette_FightingTMHM}, - [ITEM_HM07] = {gItemIcon_HM, gItemIconPalette_WaterTMHM}, - [ITEM_HM08] = {gItemIcon_HM, gItemIconPalette_WaterTMHM}, // Charms [ITEM_OVAL_CHARM] = {gItemIcon_OvalCharm, gItemIconPalette_OvalCharm}, [ITEM_SHINY_CHARM] = {gItemIcon_ShinyCharm, gItemIconPalette_ShinyCharm}, diff --git a/src/data/items.h b/src/data/items.h index 3a65f8758c..3f2d0e80fa 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -1,5 +1,11 @@ #include "constants/moves.h" +#if I_EXPANDED_ITEM_NAMES == TRUE +#define HANDLE_EXPANDED_ITEM_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__)) +#else +#define HANDLE_EXPANDED_ITEM_NAME(_name, ...) _(_name) +#endif + #if I_USE_EVO_HELD_ITEMS_FROM_BAG == TRUE #define EVO_HELD_ITEM_TYPE ITEM_USE_PARTY_MENU #define EVO_HELD_ITEM_FIELD_FUNC ItemUseOutOfBattle_EvolutionStone @@ -1041,8 +1047,8 @@ const struct Item gItemsInfo[] = [ITEM_PEWTER_CRUNCHIES] = { - .name = _("PewtrCrnches"), - .pluralName = _("PewtrCrnches"), + .name = HANDLE_EXPANDED_ITEM_NAME("PewtrCrnches", "Pewter Crunchies"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("PewtrCrnches", "Pewter Crunchies"), .price = 250, .description = sFullHealDesc, .pocket = POCKET_ITEMS, @@ -1055,7 +1061,7 @@ const struct Item gItemsInfo[] = [ITEM_RAGE_CANDY_BAR] = { - .name = _("RageCandyBar"), + .name = HANDLE_EXPANDED_ITEM_NAME("RageCandyBar", "Rage Candy Bar"), .price = (I_PRICE >= GEN_7) ? 350 : 300, .description = sFullHealDesc, .pocket = POCKET_ITEMS, @@ -1111,7 +1117,7 @@ const struct Item gItemsInfo[] = [ITEM_LUMIOSE_GALETTE] = { - .name = _("LumioseGlete"), + .name = HANDLE_EXPANDED_ITEM_NAME("LumioseGlete", "Lumiose Galette"), .price = (I_PRICE >= GEN_7) ? 350 : 200, .description = sFullHealDesc, .pocket = POCKET_ITEMS, @@ -1124,7 +1130,7 @@ const struct Item gItemsInfo[] = [ITEM_SHALOUR_SABLE] = { - .name = _("ShalourSable"), + .name = HANDLE_EXPANDED_ITEM_NAME("ShalourSable", "Shalour Sable"), .price = (I_PRICE >= GEN_7) ? 350 : 200, .description = sFullHealDesc, .pocket = POCKET_ITEMS, @@ -1275,7 +1281,7 @@ const struct Item gItemsInfo[] = [ITEM_HEALTH_FEATHER] = { - .name = _("HealthFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("HealthFeather", "Health Feather"), .price = (I_PRICE >= GEN_7) ? 300 : 3000, .description = sHealthFeatherDesc, .pocket = POCKET_ITEMS, @@ -1287,7 +1293,7 @@ const struct Item gItemsInfo[] = [ITEM_MUSCLE_FEATHER] = { - .name = _("MuscleFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("MuscleFeather", "Muscle Feather"), .price = (I_PRICE >= GEN_7) ? 300 : 3000, .description = sMuscleFeatherDesc, .pocket = POCKET_ITEMS, @@ -1299,7 +1305,7 @@ const struct Item gItemsInfo[] = [ITEM_RESIST_FEATHER] = { - .name = _("ResistFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("ResistFeather", "Resist Feather"), .price = (I_PRICE >= GEN_7) ? 300 : 3000, .description = sResistFeatherDesc, .pocket = POCKET_ITEMS, @@ -1311,7 +1317,7 @@ const struct Item gItemsInfo[] = [ITEM_GENIUS_FEATHER] = { - .name = _("GeniusFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("GeniusFeather", "Genius Feather"), .price = (I_PRICE >= GEN_7) ? 300 : 3000, .description = sGeniusFeatherDesc, .pocket = POCKET_ITEMS, @@ -1323,7 +1329,7 @@ const struct Item gItemsInfo[] = [ITEM_CLEVER_FEATHER] = { - .name = _("CleverFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("CleverFeather", "Clever Feather"), .price = (I_PRICE >= GEN_7) ? 300 : 3000, .description = sCleverFeatherDesc, .pocket = POCKET_ITEMS, @@ -1335,7 +1341,7 @@ const struct Item gItemsInfo[] = [ITEM_SWIFT_FEATHER] = { - .name = _("SwiftFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("SwiftFeather", "Swift Feather"), .price = (I_PRICE >= GEN_7) ? 300 : 3000, .description = sSwiftFeatherDesc, .pocket = POCKET_ITEMS, @@ -1349,7 +1355,7 @@ const struct Item gItemsInfo[] = [ITEM_ABILITY_CAPSULE] = { - .name = _("AbilityCapsle"), + .name = HANDLE_EXPANDED_ITEM_NAME("AbilityCapsle", "Ability Capsule"), .price = (I_PRICE < GEN_7) ? 1000 : ((I_PRICE < GEN_9) ? 10000 : 100000), .holdEffectParam = 0, .description = COMPOUND_STRING( @@ -1362,8 +1368,8 @@ const struct Item gItemsInfo[] = [ITEM_ABILITY_PATCH] = { - .name = _("AbilityPatch"), - .pluralName = _("AbilityPatches"), + .name = HANDLE_EXPANDED_ITEM_NAME("AbilityPatch", "Ability Patch"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("AbilityPatches", "Ability Patches"), .price = (I_PRICE >= GEN_9) ? 250000 : 20, .holdEffectParam = 0, .description = COMPOUND_STRING( @@ -1712,8 +1718,8 @@ const struct Item gItemsInfo[] = [ITEM_EXP_CANDY_XS] = { - .name = _("Exp.Candy XS"), - .pluralName = _("Exp.Candies XS"), + .name = HANDLE_EXPANDED_ITEM_NAME("Exp.Candy XS", "Exp. Candy XS"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Exp.Candies XS", "Exp. Candies XS"), .price = 20, .holdEffectParam = EXP_100, .description = COMPOUND_STRING( @@ -1729,8 +1735,8 @@ const struct Item gItemsInfo[] = [ITEM_EXP_CANDY_S] = { - .name = _("Exp.Candy S"), - .pluralName = _("Exp.Candies S"), + .name = HANDLE_EXPANDED_ITEM_NAME("Exp.Candy S", "Exp. Candy S"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Exp.Candies S", "Exp. Candies S"), .price = 240, .holdEffectParam = EXP_800, .description = COMPOUND_STRING( @@ -1746,8 +1752,8 @@ const struct Item gItemsInfo[] = [ITEM_EXP_CANDY_M] = { - .name = _("Exp.Candy M"), - .pluralName = _("Exp.Candies M"), + .name = HANDLE_EXPANDED_ITEM_NAME("Exp.Candy M", "Exp. Candy M"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Exp.Candies M", "Exp. Candies M"), .price = 1000, .holdEffectParam = EXP_3000, .description = COMPOUND_STRING( @@ -1763,8 +1769,8 @@ const struct Item gItemsInfo[] = [ITEM_EXP_CANDY_L] = { - .name = _("Exp.Candy L"), - .pluralName = _("Exp.Candies L"), + .name = HANDLE_EXPANDED_ITEM_NAME("Exp.Candy L", "Exp. Candy L"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Exp.Candies L", "Exp. Candies L"), .price = 3000, .holdEffectParam = EXP_10000, .description = COMPOUND_STRING( @@ -1780,8 +1786,8 @@ const struct Item gItemsInfo[] = [ITEM_EXP_CANDY_XL] = { - .name = _("Exp.Candy XL"), - .pluralName = _("Exp.Candies L"), + .name = HANDLE_EXPANDED_ITEM_NAME("Exp.Candy XL", "Exp. Candy XL"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Exp.Candies XL", "Exp. Candies XL"), .price = 10000, .holdEffectParam = EXP_30000, .description = COMPOUND_STRING( @@ -1797,8 +1803,8 @@ const struct Item gItemsInfo[] = [ITEM_DYNAMAX_CANDY] = { - .name = _("DynamaxCandy"), - .pluralName = _("DynamaxCandies"), + .name = HANDLE_EXPANDED_ITEM_NAME("DynamaxCandy", "Dynamax Candy"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("DynamaxCandies", "Dynamax Candies"), .price = 0, .description = COMPOUND_STRING( "Raises the Dynamax\n" @@ -2218,8 +2224,8 @@ const struct Item gItemsInfo[] = [ITEM_MAX_MUSHROOMS] = { - .name = _("MaxMushrooms"), - .pluralName = _("MaxMushrooms"), + .name = HANDLE_EXPANDED_ITEM_NAME("MaxMushrooms", "Max Mushrooms"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("MaxMushrooms", "Max Mushrooms"), .price = 8000, .description = COMPOUND_STRING( "Raises every stat\n" @@ -2250,7 +2256,7 @@ const struct Item gItemsInfo[] = [ITEM_GOLD_BOTTLE_CAP] = { - .name = _("GoldBottlCap"), + .name = HANDLE_EXPANDED_ITEM_NAME("GoldBottlCap", "Gold Bottle Cap"), .price = (I_PRICE >= GEN_9) ? 60000 : 10000, .description = COMPOUND_STRING( "A beautiful bottle\n" @@ -2543,7 +2549,7 @@ const struct Item gItemsInfo[] = [ITEM_PRETTY_FEATHER] = { - .name = _("PrettyFeather"), + .name = HANDLE_EXPANDED_ITEM_NAME("PrettyFeather", "Pretty Feather"), .price = (I_PRICE >= GEN_7) ? 1000 * TREASURE_FACTOR: 200, .description = COMPOUND_STRING( "A beautiful yet\n" @@ -2655,7 +2661,7 @@ const struct Item gItemsInfo[] = [ITEM_STRANGE_SOUVENIR] = { - .name = _("StrngeSouvnr"), + .name = HANDLE_EXPANDED_ITEM_NAME("StrngeSouvnr", "Strange Souvenir"), .price = (I_PRICE >= GEN_7) ? 3000 : 10, .description = COMPOUND_STRING( "An ornament that\n" @@ -2849,7 +2855,7 @@ const struct Item gItemsInfo[] = [ITEM_FOSSILIZED_BIRD] = { - .name = _("FosslzedBird"), + .name = HANDLE_EXPANDED_ITEM_NAME("FosslzedBird", "Fossilized Bird"), .price = 5000, .description = COMPOUND_STRING( "A fossil of an\n" @@ -2863,8 +2869,8 @@ const struct Item gItemsInfo[] = [ITEM_FOSSILIZED_FISH] = { - .name = _("FosslzedFish"), - .pluralName = _("FosslzedFishes"), + .name = HANDLE_EXPANDED_ITEM_NAME("FosslzedFish", "Fossilized Fish"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("FosslzedFishes", "Fossilized Fishes"), .price = 5000, .description = sFossilizedFishDesc, .pocket = POCKET_ITEMS, @@ -2875,7 +2881,7 @@ const struct Item gItemsInfo[] = [ITEM_FOSSILIZED_DRAKE] = { - .name = _("FosslzedDrke"), + .name = HANDLE_EXPANDED_ITEM_NAME("FosslzedDrke", "Fossilized Drake"), .price = 5000, .description = COMPOUND_STRING( "A fossil of an\n" @@ -2889,7 +2895,7 @@ const struct Item gItemsInfo[] = [ITEM_FOSSILIZED_DINO] = { - .name = _("FosslzedDino"), + .name = HANDLE_EXPANDED_ITEM_NAME("FosslzedDino", "Fossilized Dino"), .price = 5000, .description = sFossilizedFishDesc, .pocket = POCKET_ITEMS, @@ -3002,8 +3008,8 @@ const struct Item gItemsInfo[] = [ITEM_SURPRISE_MULCH] = { - .name = _("SurprseMulch"), - .pluralName = _("SurprseMulch"), + .name = HANDLE_EXPANDED_ITEM_NAME("SurprseMulch", "Surprise Mulch"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("SurprseMulch", "Surprise Mulch"), .price = 200, #if OW_BERRY_MULCH_USAGE == TRUE .description = COMPOUND_STRING( @@ -3090,7 +3096,7 @@ const struct Item gItemsInfo[] = [ITEM_YELLOW_APRICORN] = { - .name = _("YellwApricorn"), + .name = HANDLE_EXPANDED_ITEM_NAME("YellwApricorn", "Yellow Apricorn"), .price = (I_PRICE == GEN_4) ? 0 : ((I_PRICE >= GEN_5 && I_PRICE <= GEN_7) ? 20 : 200), .description = COMPOUND_STRING( "A yellow apricorn.\n" @@ -3103,7 +3109,7 @@ const struct Item gItemsInfo[] = [ITEM_GREEN_APRICORN] = { - .name = _("GreenApricorn"), + .name = HANDLE_EXPANDED_ITEM_NAME("GreenApricorn", "Green Apricorn"), .price = (I_PRICE == GEN_4) ? 0 : ((I_PRICE >= GEN_5 && I_PRICE <= GEN_7) ? 20 : 200), .description = COMPOUND_STRING( "A green apricorn.\n" @@ -3129,7 +3135,7 @@ const struct Item gItemsInfo[] = [ITEM_WHITE_APRICORN] = { - .name = _("WhiteApricorn"), + .name = HANDLE_EXPANDED_ITEM_NAME("WhiteApricorn", "White Apricorn"), .price = (I_PRICE == GEN_4) ? 0 : ((I_PRICE >= GEN_5 && I_PRICE <= GEN_7) ? 20 : 200), .description = COMPOUND_STRING( "A white apricorn.\n" @@ -3142,7 +3148,7 @@ const struct Item gItemsInfo[] = [ITEM_BLACK_APRICORN] = { - .name = _("BlackApricorn"), + .name = HANDLE_EXPANDED_ITEM_NAME("BlackApricorn", "Black Apricorn"), .price = (I_PRICE == GEN_4) ? 0 : ((I_PRICE >= GEN_5 && I_PRICE <= GEN_7) ? 20 : 200), .description = COMPOUND_STRING( "A black apricorn.\n" @@ -3155,7 +3161,7 @@ const struct Item gItemsInfo[] = [ITEM_WISHING_PIECE] = { - .name = _("WishingPiece"), + .name = HANDLE_EXPANDED_ITEM_NAME("WishingPiece", "Wishing Piece"), .price = 20, .description = COMPOUND_STRING( "Throw into a\n" @@ -3169,7 +3175,7 @@ const struct Item gItemsInfo[] = [ITEM_GALARICA_TWIG] = { - .name = _("GalaricaTwig"), + .name = HANDLE_EXPANDED_ITEM_NAME("GalaricaTwig", "Galarica Twig"), .price = 20 * TREASURE_FACTOR, .description = COMPOUND_STRING( "A twig from a tree\n" @@ -3571,7 +3577,7 @@ const struct Item gItemsInfo[] = [ITEM_GALARICA_CUFF] = { - .name = _("GalaricaCuff"), + .name = HANDLE_EXPANDED_ITEM_NAME("GalaricaCuff", "Galarica Cuff"), .price = (I_PRICE >= GEN_9) ? 3000 : 6000, .description = COMPOUND_STRING( "A cuff from Galar\n" @@ -3586,8 +3592,8 @@ const struct Item gItemsInfo[] = [ITEM_GALARICA_WREATH] = { - .name = _("GalrcaWreath"), - .pluralName = _("GalrcaWreathes"), + .name = HANDLE_EXPANDED_ITEM_NAME("GalrcaWreath", "Galarica Wreath"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("GalrcaWreathes", "Galarica Wreathes"), .price = (I_PRICE >= GEN_9) ? 3000 : 6000, .description = COMPOUND_STRING( "A wreath made in\n" @@ -3771,7 +3777,7 @@ const struct Item gItemsInfo[] = [ITEM_STRAWBERRY_SWEET] = { - .name = _("StrwbrySweet"), + .name = HANDLE_EXPANDED_ITEM_NAME("StrwbrySweet", "Strawberry Sweet"), .price = 500 * TREASURE_FACTOR, .description = COMPOUND_STRING( "Strawberry-shaped\n" @@ -4329,8 +4335,8 @@ const struct Item gItemsInfo[] = [ITEM_ELECTRIC_MEMORY] = { - .name = _("ElectrcMemory"), - .pluralName = _("ElectrcMemories"), + .name = HANDLE_EXPANDED_ITEM_NAME("ElectrcMemory", "Electric Memory"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("ElectrcMemories", "Electric Memories"), .price = 1000, .holdEffect = HOLD_EFFECT_MEMORY, .holdEffectParam = 0, @@ -4383,8 +4389,8 @@ const struct Item gItemsInfo[] = [ITEM_FIGHTING_MEMORY] = { - .name = _("FightngMemory"), - .pluralName = _("FightngMemories"), + .name = HANDLE_EXPANDED_ITEM_NAME("FightngMemory", "Fighting Memory"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("FightngMemories", "Fighting Memories"), .price = 1000, .holdEffect = HOLD_EFFECT_MEMORY, .holdEffectParam = 0, @@ -4455,8 +4461,8 @@ const struct Item gItemsInfo[] = [ITEM_PSYCHIC_MEMORY] = { - .name = _("PsychicMemory"), - .pluralName = _("PsychicMemories"), + .name = HANDLE_EXPANDED_ITEM_NAME("PsychicMemory", "Psychic Memory"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("PsychicMemories", "Psychic Memories"), .price = 1000, .holdEffect = HOLD_EFFECT_MEMORY, .holdEffectParam = 0, @@ -4599,7 +4605,7 @@ const struct Item gItemsInfo[] = [ITEM_RUSTED_SWORD] = { - .name = _("RustedSword"), + .name = HANDLE_EXPANDED_ITEM_NAME("RustedSword", "Rusted Sword"), .price = 0, .description = COMPOUND_STRING( "A rusty sword. A\n" @@ -4612,7 +4618,7 @@ const struct Item gItemsInfo[] = [ITEM_RUSTED_SHIELD] = { - .name = _("RustedShield"), + .name = HANDLE_EXPANDED_ITEM_NAME("RustedShield", "Rusted Shield"), .price = 0, .description = COMPOUND_STRING( "A rusty shield. A\n" @@ -4672,7 +4678,7 @@ const struct Item gItemsInfo[] = [ITEM_CHARIZARDITE_X] = { - .name = _("CharizarditeX"), + .name = HANDLE_EXPANDED_ITEM_NAME("CharizarditeX", "Charizardite X"), .pluralName = _("Charizardites X"), .price = 0, .holdEffect = HOLD_EFFECT_MEGA_STONE, @@ -4685,7 +4691,7 @@ const struct Item gItemsInfo[] = [ITEM_CHARIZARDITE_Y] = { - .name = _("CharizarditeY"), + .name = HANDLE_EXPANDED_ITEM_NAME("CharizarditeY", "Charizardite Y"), .pluralName = _("Charizardites Y"), .price = 0, .holdEffect = HOLD_EFFECT_MEGA_STONE, @@ -6156,7 +6162,7 @@ const struct Item gItemsInfo[] = [ITEM_ULTRANECROZIUM_Z] = { - .name = _("U-Necrozium Z"), + .name = HANDLE_EXPANDED_ITEM_NAME("U-Necrozium Z", "Ultranecrozium Z"), .price = 0, .holdEffect = HOLD_EFFECT_Z_CRYSTAL, .description = COMPOUND_STRING( @@ -6266,7 +6272,7 @@ const struct Item gItemsInfo[] = [ITEM_DEEP_SEA_SCALE] = { - .name = _("DeepSeaScale"), + .name = HANDLE_EXPANDED_ITEM_NAME("DeepSeaScale", "Deep Sea Scale"), .price = (I_PRICE >= GEN_7) ? 2000 : 200, .holdEffect = HOLD_EFFECT_DEEP_SEA_SCALE, .description = COMPOUND_STRING( @@ -6282,8 +6288,8 @@ const struct Item gItemsInfo[] = [ITEM_DEEP_SEA_TOOTH] = { - .name = _("DeepSeaTooth"), - .pluralName = _("DeepSeaTeeth"), + .name = HANDLE_EXPANDED_ITEM_NAME("DeepSeaTooth", "Deep Sea Tooth"), + .pluralName = _("Deep Sea Teeth"), .price = (I_PRICE >= GEN_7) ? 2000 : 200, .holdEffect = HOLD_EFFECT_DEEP_SEA_TOOTH, .description = COMPOUND_STRING( @@ -6767,8 +6773,8 @@ const struct Item gItemsInfo[] = [ITEM_NEVER_MELT_ICE] = { - .name = _("Never-MeltIce"), - .pluralName = _("Never-MeltIce"), + .name = HANDLE_EXPANDED_ITEM_NAME("Never-MeltIce", "Never-Melt Ice"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Never-MeltIce", "Never-Melt Ice"), .price = (I_PRICE >= GEN_9) ? 3000 : ((I_PRICE >= GEN_7) ? 1000 : 100), .holdEffect = HOLD_EFFECT_ICE_POWER, .holdEffectParam = TYPE_BOOST_PARAM, @@ -7913,8 +7919,8 @@ const struct Item gItemsInfo[] = [ITEM_WEAKNESS_POLICY] = { - .name = _("WeaknssPolicy"), - .pluralName = _("WeaknssPolicies"), + .name = HANDLE_EXPANDED_ITEM_NAME("WeaknssPolicy", "Weakness Policy"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("WeaknssPolicies", "Weakness Policies"), .price = (I_PRICE >= GEN_9) ? 50000 : 1000, .holdEffect = HOLD_EFFECT_WEAKNESS_POLICY, .holdEffectParam = 0, @@ -7946,8 +7952,8 @@ const struct Item gItemsInfo[] = [ITEM_SAFETY_GOGGLES] = { - .name = _("SafetyGoggles"), - .pluralName = _("SafetyGoggles"), + .name = HANDLE_EXPANDED_ITEM_NAME("SafetyGoggles", "Safety Goggles"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("SafetyGoggles", "Safety Goggles"), .price = (I_PRICE >= GEN_9) ? 20000 : ((I_PRICE >= GEN_7) ? 4000 : 1000), .holdEffect = HOLD_EFFECT_SAFETY_GOGGLES, .description = COMPOUND_STRING( @@ -7962,7 +7968,7 @@ const struct Item gItemsInfo[] = [ITEM_ADRENALINE_ORB] = { - .name = _("AdrenalineOrb"), + .name = HANDLE_EXPANDED_ITEM_NAME("AdrenalineOrb", "Adrenaline Orb"), .price = (I_PRICE >= GEN_9) ? 5000 : ((I_PRICE >= GEN_8) ? 4000 : 300), .holdEffect = HOLD_EFFECT_ADRENALINE_ORB, .description = COMPOUND_STRING( @@ -7977,7 +7983,7 @@ const struct Item gItemsInfo[] = [ITEM_TERRAIN_EXTENDER] = { - .name = _("TerainExtendr"), + .name = HANDLE_EXPANDED_ITEM_NAME("TerainExtendr", "Terrain Extender"), .price = (I_PRICE >= GEN_9) ? 15000 : 4000, .holdEffect = HOLD_EFFECT_TERRAIN_EXTENDER, .description = COMPOUND_STRING( @@ -7992,8 +7998,8 @@ const struct Item gItemsInfo[] = [ITEM_PROTECTIVE_PADS] = { - .name = _("ProtectvePads"), - .pluralName = _("ProtectvePads"), + .name = HANDLE_EXPANDED_ITEM_NAME("ProtectvePads", "Protective Pads"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("ProtectvePads", "Protective Pads"), .price = (I_PRICE >= GEN_9) ? 15000 : 4000, .holdEffect = HOLD_EFFECT_PROTECTIVE_PADS, .description = COMPOUND_STRING( @@ -8038,8 +8044,8 @@ const struct Item gItemsInfo[] = [ITEM_HEAVY_DUTY_BOOTS] = { - .name = _("Heavy-DtyBts"), - .pluralName = _("Heavy-DtyBts"), + .name = HANDLE_EXPANDED_ITEM_NAME("Heavy-DtyBts", "Heavy-Duty Boots"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("Heavy-DtyBts", "Heavy-Duty Boots"), .price = (I_PRICE >= GEN_9) ? 20000 : 4000, .holdEffect = HOLD_EFFECT_HEAVY_DUTY_BOOTS, .description = COMPOUND_STRING( @@ -8054,8 +8060,8 @@ const struct Item gItemsInfo[] = [ITEM_BLUNDER_POLICY] = { - .name = _("BlundrPolicy"), - .pluralName = _("BlundrPolicies"), + .name = HANDLE_EXPANDED_ITEM_NAME("BlundrPolicy", "Blunder Policy"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("BlundrPolicies", "Blunder Policies"), .price = (I_PRICE >= GEN_9) ? 30000 : 4000, .holdEffect = HOLD_EFFECT_BLUNDER_POLICY, .description = COMPOUND_STRING( @@ -8085,7 +8091,7 @@ const struct Item gItemsInfo[] = [ITEM_UTILITY_UMBRELLA] = { - .name = _("UtltyUmbrlla"), + .name = HANDLE_EXPANDED_ITEM_NAME("UtltyUmbrlla", "Utility Umbrella"), .price = (I_PRICE >= GEN_9) ? 15000 : 4000, .holdEffect = HOLD_EFFECT_UTILITY_UMBRELLA, .description = COMPOUND_STRING( @@ -10736,7 +10742,7 @@ const struct Item gItemsInfo[] = [ITEM_CATCHING_CHARM] = { - .name = _("CatchngCharm"), + .name = HANDLE_EXPANDED_ITEM_NAME("CatchngCharm", "Catching Charm"), .price = 0, .importance = 1, .description = COMPOUND_STRING( @@ -10766,12 +10772,12 @@ const struct Item gItemsInfo[] = [ITEM_ROTOM_CATALOG] = { - .name = _("RotomCatalog"), + .name = HANDLE_EXPANDED_ITEM_NAME("RotomCatalog", "Rotom Catalog"), .price = 0, .importance = 1, .description = COMPOUND_STRING( "A catalog full of\n" - "deviced liked by\n" + "devices liked by\n" "Rotom."), .pocket = POCKET_KEY_ITEMS, .type = ITEM_USE_PARTY_MENU, @@ -10880,8 +10886,8 @@ const struct Item gItemsInfo[] = [ITEM_REINS_OF_UNITY] = { - .name = _("ReinsOfUnity"), - .pluralName = _("ReinsOfUnity"), + .name = HANDLE_EXPANDED_ITEM_NAME("ReinsOfUnity", "Reins of Unity"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("ReinsOfUnity", "Reins of Unity"), .price = 0, .importance = 1, .description = COMPOUND_STRING( @@ -11679,7 +11685,7 @@ const struct Item gItemsInfo[] = [ITEM_ABILITY_SHIELD] = { - .name = _("AbilityShield"), + .name = HANDLE_EXPANDED_ITEM_NAME("AbilityShield", "Ability Shield"), .price = 20000, .holdEffect = HOLD_EFFECT_ABILITY_SHIELD, .description = COMPOUND_STRING( @@ -11711,7 +11717,7 @@ const struct Item gItemsInfo[] = [ITEM_PUNCHING_GLOVE] = { - .name = _("PunchingGlove"), + .name = HANDLE_EXPANDED_ITEM_NAME("PunchingGlove", "Punching Glove"), .price = 15000, .holdEffect = HOLD_EFFECT_PUNCHING_GLOVE, .description = COMPOUND_STRING( @@ -11757,7 +11763,7 @@ const struct Item gItemsInfo[] = [ITEM_AUSPICIOUS_ARMOR] = { - .name = _("AuspciousArmr"), + .name = HANDLE_EXPANDED_ITEM_NAME("AuspciousArmr", "Auspicious Armor"), .price = 3000, .description = COMPOUND_STRING( "Armor inhabited by\n" @@ -11772,8 +11778,8 @@ const struct Item gItemsInfo[] = [ITEM_BOOSTER_ENERGY] = { - .name = _("BoosterEnergy"), - .pluralName = _("BoosterEnergies"), + .name = HANDLE_EXPANDED_ITEM_NAME("BoosterEnergy", "Booster Energy"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("BoosterEnergies", "Booster Energies"), .price = 0, .holdEffect = HOLD_EFFECT_BOOSTER_ENERGY, .description = COMPOUND_STRING( @@ -11788,7 +11794,7 @@ const struct Item gItemsInfo[] = [ITEM_BIG_BAMBOO_SHOOT] = { - .name = _("BigBmbooShoot"), + .name = HANDLE_EXPANDED_ITEM_NAME("BigBmbooShoot", "Big Bamboo Shoot"), .price = 3000, .description = COMPOUND_STRING( "A large and rare\n" @@ -11802,7 +11808,7 @@ const struct Item gItemsInfo[] = [ITEM_GIMMIGHOUL_COIN] = { - .name = _("GimighoulCoin"), + .name = HANDLE_EXPANDED_ITEM_NAME("GimighoulCoin", "Gimmighoul Coin"), .price = 400, .description = COMPOUND_STRING( "Gimmighoul hoard\n" @@ -11815,7 +11821,7 @@ const struct Item gItemsInfo[] = [ITEM_LEADERS_CREST] = { - .name = _("Leader'sCrest"), + .name = HANDLE_EXPANDED_ITEM_NAME("Leader'sCrest", "Leader's Crest"), .price = 3000, .description = COMPOUND_STRING( "A shard of an old\n" @@ -11828,7 +11834,7 @@ const struct Item gItemsInfo[] = [ITEM_MALICIOUS_ARMOR] = { - .name = _("MaliciousArmr"), + .name = HANDLE_EXPANDED_ITEM_NAME("MaliciousArmr", "Malicious Armor"), .price = 3000, .description = COMPOUND_STRING( "Armor inhabited by\n" @@ -11858,8 +11864,8 @@ const struct Item gItemsInfo[] = [ITEM_SCROLL_OF_DARKNESS] = { - .name = _("ScrllOfDrknss"), - .pluralName = _("ScrllsOfDrknss"), + .name = HANDLE_EXPANDED_ITEM_NAME("ScrllOfDrknss", "Scroll of Darkness"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("ScrllsOfDrknss", "Scrolls of Darkness"), .price = 0, .description = COMPOUND_STRING( "A peculiar scroll\n" @@ -11874,8 +11880,8 @@ const struct Item gItemsInfo[] = [ITEM_SCROLL_OF_WATERS] = { - .name = _("ScrollOfWatrs"), - .pluralName = _("ScrollsOfWatrs"), + .name = HANDLE_EXPANDED_ITEM_NAME("ScrollOfWatrs", "Scroll of Waters"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("ScrollsOfWatrs", "Scrolls of Waters"), .price = 0, .description = COMPOUND_STRING( "A peculiar scroll\n" @@ -11904,7 +11910,7 @@ const struct Item gItemsInfo[] = [ITEM_TINY_BAMBOO_SHOOT] = { - .name = _("TinyBmbooShot"), + .name = HANDLE_EXPANDED_ITEM_NAME("TinyBmbooShot", "Tiny Bamboo Shoot"), .price = 750, .description = COMPOUND_STRING( "A small and rare\n" @@ -11918,7 +11924,7 @@ const struct Item gItemsInfo[] = [ITEM_BUG_TERA_SHARD] = { - .name = _("Bug TeraShard"), + .name = HANDLE_EXPANDED_ITEM_NAME("Bug TeraShard", "Bug Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11928,7 +11934,7 @@ const struct Item gItemsInfo[] = [ITEM_DARK_TERA_SHARD] = { - .name = _("DarkTeraShard"), + .name = HANDLE_EXPANDED_ITEM_NAME("DarkTeraShard", "Dark Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11938,7 +11944,7 @@ const struct Item gItemsInfo[] = [ITEM_DRAGON_TERA_SHARD] = { - .name = _("DragnTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("DragnTeraShrd", "Dragon Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11948,7 +11954,7 @@ const struct Item gItemsInfo[] = [ITEM_ELECTRIC_TERA_SHARD] = { - .name = _("EltrcTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("EltrcTeraShrd", "Electric Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11958,7 +11964,7 @@ const struct Item gItemsInfo[] = [ITEM_FAIRY_TERA_SHARD] = { - .name = _("FairyTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("FairyTeraShrd", "Fairy Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11968,7 +11974,7 @@ const struct Item gItemsInfo[] = [ITEM_FIGHTING_TERA_SHARD] = { - .name = _("FghtngTerShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("FghtngTerShrd", "Fighting Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11978,7 +11984,7 @@ const struct Item gItemsInfo[] = [ITEM_FIRE_TERA_SHARD] = { - .name = _("FireTeraShard"), + .name = HANDLE_EXPANDED_ITEM_NAME("FireTeraShard", "Fire Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11988,7 +11994,7 @@ const struct Item gItemsInfo[] = [ITEM_FLYING_TERA_SHARD] = { - .name = _("FlyngTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("FlyngTeraShrd", "Flying Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -11998,7 +12004,7 @@ const struct Item gItemsInfo[] = [ITEM_GHOST_TERA_SHARD] = { - .name = _("GhostTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("GhostTeraShrd", "Ghost Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12008,7 +12014,7 @@ const struct Item gItemsInfo[] = [ITEM_GRASS_TERA_SHARD] = { - .name = _("GrassTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("GrassTeraShrd", "Grass Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12018,7 +12024,7 @@ const struct Item gItemsInfo[] = [ITEM_GROUND_TERA_SHARD] = { - .name = _("GrondTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("GrondTeraShrd", "Ground Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12028,7 +12034,7 @@ const struct Item gItemsInfo[] = [ITEM_ICE_TERA_SHARD] = { - .name = _("Ice TeraShard"), + .name = HANDLE_EXPANDED_ITEM_NAME("Ice TeraShard", "Ice Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12038,7 +12044,7 @@ const struct Item gItemsInfo[] = [ITEM_NORMAL_TERA_SHARD] = { - .name = _("NormlTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("NormlTeraShrd", "Normal Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12048,7 +12054,7 @@ const struct Item gItemsInfo[] = [ITEM_POISON_TERA_SHARD] = { - .name = _("PoisnTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("PoisnTeraShrd", "Poison Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12058,7 +12064,7 @@ const struct Item gItemsInfo[] = [ITEM_PSYCHIC_TERA_SHARD] = { - .name = _("PschcTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("PschcTeraShrd", "Psychic Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12068,7 +12074,7 @@ const struct Item gItemsInfo[] = [ITEM_ROCK_TERA_SHARD] = { - .name = _("RockTeraShard"), + .name = HANDLE_EXPANDED_ITEM_NAME("RockTeraShard", "Rock Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12078,7 +12084,7 @@ const struct Item gItemsInfo[] = [ITEM_STEEL_TERA_SHARD] = { - .name = _("SteelTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("SteelTeraShrd", "Steel Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12088,7 +12094,7 @@ const struct Item gItemsInfo[] = [ITEM_WATER_TERA_SHARD] = { - .name = _("WaterTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("WaterTeraShrd", "Water Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12098,7 +12104,7 @@ const struct Item gItemsInfo[] = [ITEM_ADAMANT_CRYSTAL] = { - .name = _("AdamantCrystl"), + .name = HANDLE_EXPANDED_ITEM_NAME("AdamantCrystl", "Adamant Crystal"), .price = 0, .description = COMPOUND_STRING( "A large, glowing gem\n" @@ -12126,7 +12132,7 @@ const struct Item gItemsInfo[] = [ITEM_LUSTROUS_GLOBE] = { - .name = _("LustrousGlobe"), + .name = HANDLE_EXPANDED_ITEM_NAME("LustrousGlobe", "Lustrous Globe"), .price = 0, .description = COMPOUND_STRING( "A large, glowing gem\n" @@ -12140,7 +12146,7 @@ const struct Item gItemsInfo[] = [ITEM_BLACK_AUGURITE] = { - .name = _("BlackAugurite"), + .name = HANDLE_EXPANDED_ITEM_NAME("BlackAugurite", "Black Augurite"), .price = 8000, .description = COMPOUND_STRING( "A black stone that\n" @@ -12231,7 +12237,7 @@ const struct Item gItemsInfo[] = [ITEM_UNREMARKABLE_TEACUP] = { - .name = _("UnrmkblTeacup"), + .name = HANDLE_EXPANDED_ITEM_NAME("UnrmkblTeacup", "Unremarkable Teacup"), .price = 1600, .description = COMPOUND_STRING( "A cracked teacup\n" @@ -12246,7 +12252,7 @@ const struct Item gItemsInfo[] = [ITEM_MASTERPIECE_TEACUP] = { - .name = _("MstrpceTeacup"), + .name = HANDLE_EXPANDED_ITEM_NAME("MstrpceTeacup", "Masterpiece Teacup"), .price = 38000, .description = COMPOUND_STRING( "A chipped teacup\n" @@ -12261,7 +12267,7 @@ const struct Item gItemsInfo[] = [ITEM_CORNERSTONE_MASK] = { - .name = _("CornrstneMask"), + .name = HANDLE_EXPANDED_ITEM_NAME("CornrstneMask", "Cornerstone Mask"), .price = 0, .description = COMPOUND_STRING( "Allows Ogerpon to\n" @@ -12274,7 +12280,7 @@ const struct Item gItemsInfo[] = [ITEM_WELLSPRING_MASK] = { - .name = _("WellsprngMask"), + .name = HANDLE_EXPANDED_ITEM_NAME("WellsprngMask", "Wellspring Mask"), .price = 0, .description = COMPOUND_STRING( "Allows Ogerpon to\n" @@ -12287,7 +12293,7 @@ const struct Item gItemsInfo[] = [ITEM_HEARTHFLAME_MASK] = { - .name = _("HrthflameMask"), + .name = HANDLE_EXPANDED_ITEM_NAME("HrthflameMask", "Hearthflame Mask"), .price = 0, .description = COMPOUND_STRING( "Allows Ogerpon to\n" @@ -12378,8 +12384,8 @@ const struct Item gItemsInfo[] = [ITEM_FRESH_START_MOCHI] = { - .name = _("FrshStrtMochi"), - .pluralName = _("FrshStrtMochi"), + .name = HANDLE_EXPANDED_ITEM_NAME("FrshStrtMochi", "Fresh Start Mochi"), + .pluralName = HANDLE_EXPANDED_ITEM_NAME("FrshStrtMochi", "Fresh Start Mochi"), .price = 300, .description = COMPOUND_STRING( "An item that resets\n" @@ -12394,7 +12400,7 @@ const struct Item gItemsInfo[] = [ITEM_GLIMMERING_CHARM] = { - .name = _("GlmmringCharm"), + .name = HANDLE_EXPANDED_ITEM_NAME("GlmmringCharm", "Glimmering Charm"), .price = 0, .importance = 1, .description = COMPOUND_STRING( @@ -12422,7 +12428,7 @@ const struct Item gItemsInfo[] = [ITEM_STELLAR_TERA_SHARD] = { - .name = _("StllrTeraShrd"), + .name = HANDLE_EXPANDED_ITEM_NAME("StllrTeraShrd", "Stellar Tera Shard"), .price = 0, .description = sTeraShardDesc, .pocket = POCKET_ITEMS, @@ -12432,7 +12438,7 @@ const struct Item gItemsInfo[] = [ITEM_JUBILIFE_MUFFIN] = { - .name = _("JublifeMuffin"), + .name = HANDLE_EXPANDED_ITEM_NAME("JublifeMuffin", "Jubilife Muffin"), .price = 250, .description = sFullHealDesc, .pocket = POCKET_ITEMS, @@ -12560,7 +12566,7 @@ const struct Item gItemsInfo[] = [ITEM_AUX_POWERGUARD] = { - .name = _("AuxPowerguard"), + .name = HANDLE_EXPANDED_ITEM_NAME("AuxPowerguard", "Aux Powerguard"), .price = 1200, .holdEffectParam = X_ITEM_STAGES, .description = COMPOUND_STRING( @@ -12581,7 +12587,7 @@ const struct Item gItemsInfo[] = [ITEM_CHOICE_DUMPLING] = { - .name = _("ChoiceDumplng"), + .name = HANDLE_EXPANDED_ITEM_NAME("ChoiceDumplng", "Choice Dumpling"), .price = 1200, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, @@ -12603,7 +12609,7 @@ const struct Item gItemsInfo[] = [ITEM_TWICE_SPICED_RADISH] = { - .name = _("2xSpicedRadsh"), + .name = HANDLE_EXPANDED_ITEM_NAME("2xSpicedRadsh", "Twice-Spiced Radish"), .price = 1600, .description = sQuestionMarksDesc, .pocket = POCKET_ITEMS, diff --git a/src/data/moves_info.h b/src/data/moves_info.h index 10e0c8ef28..dca295f851 100644 --- a/src/data/moves_info.h +++ b/src/data/moves_info.h @@ -132,6 +132,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .metronomeBanned = TRUE, .mirrorMoveBanned = TRUE, .sketchBanned = TRUE, + .assistBanned = TRUE, }, [MOVE_POUND] = @@ -6358,7 +6359,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = [MOVE_WILL_O_WISP] = { - .name = COMPOUND_STRING("Will-o-Wisp"), + .name = COMPOUND_STRING("Will-O-Wisp"), .description = COMPOUND_STRING( "Inflicts a burn on the foe\n" "with intense fire."), @@ -14114,6 +14115,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Whips up a storm of\n" "diamonds. May up Defense."), + .effect = EFFECT_HIT, .power = 100, .type = TYPE_ROCK, .accuracy = 95, @@ -14160,7 +14162,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = [MOVE_HYPERSPACE_HOLE] = { - .name = HANDLE_EXPANDED_MOVE_NAME("HyprspceHole", "Hyprspace Hole"), + .name = HANDLE_EXPANDED_MOVE_NAME("HyprspceHole", "Hyperspace Hole"), .description = sHyperspaceHoleDescription, .effect = EFFECT_HIT, .power = 80, @@ -18440,7 +18442,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "If the user's Terastallized,\n" "it hits with its Tera-type."), - .effect = EFFECT_PLACEHOLDER, // EFFECT_TERA_BLAST, + .effect = EFFECT_TERA_BLAST, .power = 80, .type = TYPE_NORMAL, .accuracy = 100, @@ -18449,6 +18451,10 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .forcePressure = TRUE, + .additionalEffects = ADDITIONAL_EFFECTS({ + .moveEffect = MOVE_EFFECT_TERA_BLAST, + .self = TRUE, + }), }, [MOVE_SILK_TRAP] = @@ -18722,7 +18728,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .name = COMPOUND_STRING("Mortal Spin"), .description = COMPOUND_STRING( "Erases trap moves and Leech\n" - "Seed. Poisons adjecent foes."), + "Seed. Poisons adjacent foes."), .effect = EFFECT_HIT, .power = 30, .type = TYPE_POISON, @@ -19559,12 +19565,12 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] = .description = COMPOUND_STRING( "Damages all opponents if user is\n" "Stellar form Terapagos."), - .effect = EFFECT_PLACEHOLDER, //EFFECT_TERA_STARSTORM + .effect = EFFECT_TERA_STARSTORM, .power = 120, - .type = TYPE_NORMAL, // Stellar type if used by Terapagos-Stellar + .type = TYPE_NORMAL, .accuracy = 100, .pp = 5, - .target = MOVE_TARGET_SELECTED, // MOVE_TARGET_BOTH if used by Terapagos-Stellar + .target = MOVE_TARGET_SELECTED, .priority = 0, .category = DAMAGE_CATEGORY_SPECIAL, .assistBanned = TRUE, diff --git a/src/data/partner_parties.h b/src/data/partner_parties.h index 1b071ec28e..8b13789179 100644 --- a/src/data/partner_parties.h +++ b/src/data/partner_parties.h @@ -1,26 +1 @@ -static const struct TrainerMon sParty_StevenPartner[] = { - { - .species = SPECIES_METANG, - .lvl = 42, - .nature = NATURE_BRAVE, - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), - .ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0), - .moves = {MOVE_LIGHT_SCREEN, MOVE_PSYCHIC, MOVE_REFLECT, MOVE_METAL_CLAW}, - }, - { - .species = SPECIES_SKARMORY, - .lvl = 43, - .nature = NATURE_IMPISH, - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), - .ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252), - .moves = {MOVE_TOXIC, MOVE_AERIAL_ACE, MOVE_PROTECT, MOVE_STEEL_WING}, - }, - { - .species = SPECIES_AGGRON, - .lvl = 44, - .nature = NATURE_ADAMANT, - .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), - .ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6), - .moves = {MOVE_THUNDER, MOVE_PROTECT, MOVE_SOLAR_BEAM, MOVE_DRAGON_CLAW}, - } -}; + diff --git a/src/data/pokemon/form_change_tables.h b/src/data/pokemon/form_change_tables.h index 5edd6f42b5..f8edc496de 100644 --- a/src/data/pokemon/form_change_tables.h +++ b/src/data/pokemon/form_change_tables.h @@ -1268,7 +1268,7 @@ static const struct FormChange sOgerponFormChangeTable[] = { #if P_FAMILY_TERAPAGOS static const struct FormChange sTerapagosFormChangeTable[] = { - {FORM_CHANGE_BEGIN_BATTLE, SPECIES_TERAPAGOS_TERASTAL}, //needs to be tied to the ability + {FORM_CHANGE_BATTLE_SWITCH, SPECIES_TERAPAGOS_TERASTAL, ABILITY_TERA_SHIFT}, #if P_TERA_FORMS //{FORM_CHANGE_TERASTALLIZATION, SPECIES_TERAPAGOS_STELLAR}, #endif diff --git a/src/data/pokemon/form_species_tables.h b/src/data/pokemon/form_species_tables.h index 9ae2c3ebdb..af35503fe3 100644 --- a/src/data/pokemon/form_species_tables.h +++ b/src/data/pokemon/form_species_tables.h @@ -2169,7 +2169,7 @@ static const u16 sOgerponFormSpeciesIdTable[] = { static const u16 sTerapagosFormSpeciesIdTable[] = { SPECIES_TERAPAGOS_NORMAL, SPECIES_TERAPAGOS_TERASTAL, -#if P_TERA_FORMS +#if P_TERA_FORMS SPECIES_TERAPAGOS_STELLAR, #endif FORM_SPECIES_END, diff --git a/src/data/pokemon/species_info.h b/src/data/pokemon/species_info.h index ff0a9329e4..f528a451bf 100644 --- a/src/data/pokemon/species_info.h +++ b/src/data/pokemon/species_info.h @@ -60,6 +60,12 @@ #define FLIP 0 #define NO_FLIP 1 +#if POKEMON_NAME_LENGTH >= 12 +#define HANDLE_EXPANDED_SPECIES_NAME(_name, ...) _(DEFAULT(_name, __VA_ARGS__)) +#else +#define HANDLE_EXPANDED_SPECIES_NAME(_name, ...) _(_name) +#endif + const struct SpeciesInfo gSpeciesInfo[] = { [SPECIES_NONE] = diff --git a/src/data/pokemon/species_info/gen_1_families.h b/src/data/pokemon/species_info/gen_1_families.h index 0c8e06d5ff..1b56e48d24 100644 --- a/src/data/pokemon/species_info/gen_1_families.h +++ b/src/data/pokemon/species_info/gen_1_families.h @@ -15687,6 +15687,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = FOOTPRINT(Mewtwo) FOLLOWER(Mewtwo, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Mewtwo, gShinyFollowerPalette_Mewtwo) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMewtwoLevelUpLearnset, .teachableLearnset = sMewtwoTeachableLearnset, .formSpeciesIdTable = sMewtwoFormSpeciesIdTable, @@ -15744,6 +15745,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = FOOTPRINT(Mewtwo) .isLegendary = TRUE, .isMegaEvolution = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMewtwoLevelUpLearnset, .teachableLearnset = sMewtwoTeachableLearnset, .formSpeciesIdTable = sMewtwoFormSpeciesIdTable, @@ -15801,6 +15803,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = FOOTPRINT(Mewtwo) .isLegendary = TRUE, .isMegaEvolution = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMewtwoLevelUpLearnset, .teachableLearnset = sMewtwoTeachableLearnset, .formSpeciesIdTable = sMewtwoFormSpeciesIdTable, @@ -15869,6 +15872,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] = FOOTPRINT(Mew) FOLLOWER(Mew, SIZE_32x32, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_Mew, gShinyFollowerPalette_Mew) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMewLevelUpLearnset, .teachableLearnset = sMewTeachableLearnset, }, diff --git a/src/data/pokemon/species_info/gen_2_families.h b/src/data/pokemon/species_info/gen_2_families.h index ba0f855cf1..9dd22b4b00 100644 --- a/src/data/pokemon/species_info/gen_2_families.h +++ b/src/data/pokemon/species_info/gen_2_families.h @@ -3463,7 +3463,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), .abilities = { ABILITY_SERENE_GRACE, ABILITY_RUN_AWAY, ABILITY_RATTLED }, .bodyColor = BODY_COLOR_YELLOW, - .speciesName = _("Dudunsprce"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Dudunsprce", "Dudunsparce"), .cryId = CRY_DUDUNSPARCE, .natDexNum = NATIONAL_DEX_DUDUNSPARCE, .categoryName = _("Land Snake"), @@ -3516,7 +3516,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD), .abilities = { ABILITY_SERENE_GRACE, ABILITY_RUN_AWAY, ABILITY_RATTLED }, .bodyColor = BODY_COLOR_YELLOW, - .speciesName = _("Dudunsprce"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Dudunsprce", "Dudunsparce"), .cryId = CRY_DUDUNSPARCE, .natDexNum = NATIONAL_DEX_DUDUNSPARCE, .categoryName = _("Land Snake"), @@ -6432,6 +6432,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = FOOTPRINT(Lugia) FOLLOWER(Lugia, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_Lugia, gShinyFollowerPalette_Lugia) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sLugiaLevelUpLearnset, .teachableLearnset = sLugiaTeachableLearnset, }, @@ -6497,6 +6498,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = FOOTPRINT(HoOh) FOLLOWER(HoOh, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_HoOh, gShinyFollowerPalette_HoOh) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sHoOhLevelUpLearnset, .teachableLearnset = sHoOhTeachableLearnset, }, @@ -6562,6 +6564,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = FOOTPRINT(Celebi) FOLLOWER(Celebi, SIZE_32x32, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_Celebi, gShinyFollowerPalette_Celebi) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sCelebiLevelUpLearnset, .teachableLearnset = sCelebiTeachableLearnset, }, @@ -6569,4 +6572,4 @@ const struct SpeciesInfo gSpeciesInfoGen2[] = #ifdef __INTELLISENSE__ }; -#endif \ No newline at end of file +#endif diff --git a/src/data/pokemon/species_info/gen_3_families.h b/src/data/pokemon/species_info/gen_3_families.h index 2a135e963a..0736ade25c 100644 --- a/src/data/pokemon/species_info/gen_3_families.h +++ b/src/data/pokemon/species_info/gen_3_families.h @@ -9482,6 +9482,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Kyogre) FOLLOWER(Kyogre, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_Kyogre, gShinyFollowerPalette_Kyogre) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKyogreLevelUpLearnset, .teachableLearnset = sKyogreTeachableLearnset, .formSpeciesIdTable = sKyogreFormSpeciesIdTable, @@ -9538,6 +9539,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Kyogre) .isLegendary = TRUE, .isPrimalReversion = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKyogreLevelUpLearnset, .teachableLearnset = sKyogreTeachableLearnset, .formSpeciesIdTable = sKyogreFormSpeciesIdTable, @@ -9603,6 +9605,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Groudon) FOLLOWER(Groudon, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Groudon, gShinyFollowerPalette_Groudon) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sGroudonLevelUpLearnset, .teachableLearnset = sGroudonTeachableLearnset, .formSpeciesIdTable = sGroudonFormSpeciesIdTable, @@ -9660,6 +9663,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Groudon) .isLegendary = TRUE, .isPrimalReversion = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sGroudonLevelUpLearnset, .teachableLearnset = sGroudonTeachableLearnset, .formSpeciesIdTable = sGroudonFormSpeciesIdTable, @@ -9728,6 +9732,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Rayquaza) FOLLOWER(Rayquaza, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_Rayquaza, gShinyFollowerPalette_Rayquaza) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sRayquazaLevelUpLearnset, .teachableLearnset = sRayquazaTeachableLearnset, .formSpeciesIdTable = sRayquazaFormSpeciesIdTable, @@ -9787,6 +9792,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Rayquaza) .isLegendary = TRUE, .isMegaEvolution = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sRayquazaLevelUpLearnset, .teachableLearnset = sRayquazaTeachableLearnset, .formSpeciesIdTable = sRayquazaFormSpeciesIdTable, @@ -9855,6 +9861,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Jirachi) FOLLOWER(Jirachi, SIZE_32x32, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_Jirachi, gShinyFollowerPalette_Jirachi) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sJirachiLevelUpLearnset, .teachableLearnset = sJirachiTeachableLearnset, }, @@ -9917,6 +9924,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Deoxys) FOLLOWER(DeoxysNormal, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_DeoxysNormal, gShinyFollowerPalette_DeoxysNormal) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDeoxysNormalLevelUpLearnset, .teachableLearnset = sDeoxysNormalTeachableLearnset, .formSpeciesIdTable = sDeoxysFormSpeciesIdTable, @@ -9970,6 +9978,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Deoxys) FOLLOWER(DeoxysAttack, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_DeoxysAttack, gShinyFollowerPalette_DeoxysAttack) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDeoxysAttackLevelUpLearnset, .teachableLearnset = sDeoxysAttackTeachableLearnset, .formSpeciesIdTable = sDeoxysFormSpeciesIdTable, @@ -10023,6 +10032,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Deoxys) FOLLOWER(DeoxysDefense, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_DeoxysDefense, gShinyFollowerPalette_DeoxysDefense) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDeoxysDefenseLevelUpLearnset, .teachableLearnset = sDeoxysDefenseTeachableLearnset, .formSpeciesIdTable = sDeoxysFormSpeciesIdTable, @@ -10076,6 +10086,7 @@ const struct SpeciesInfo gSpeciesInfoGen3[] = FOOTPRINT(Deoxys) FOLLOWER(DeoxysSpeed, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_DeoxysSpeed, gShinyFollowerPalette_DeoxysSpeed) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDeoxysSpeedLevelUpLearnset, .teachableLearnset = sDeoxysSpeedTeachableLearnset, .formSpeciesIdTable = sDeoxysFormSpeciesIdTable, diff --git a/src/data/pokemon/species_info/gen_4_families.h b/src/data/pokemon/species_info/gen_4_families.h index 1ef95962cb..5734be800a 100644 --- a/src/data/pokemon/species_info/gen_4_families.h +++ b/src/data/pokemon/species_info/gen_4_families.h @@ -4865,6 +4865,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Dialga) FOLLOWER(Dialga, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Dialga, gShinyFollowerPalette_Dialga) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDialgaLevelUpLearnset, .teachableLearnset = sDialgaTeachableLearnset, .formSpeciesIdTable = sDialgaFormSpeciesIdTable, @@ -4922,6 +4923,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = //FOLLOWER(DialgaOrigin, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_DialgaOrigin, gShinyFollowerPalette_DialgaOrigin) FOLLOWER(DialgaOrigin, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_DialgaOrigin) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDialgaLevelUpLearnset, .teachableLearnset = sDialgaTeachableLearnset, .formSpeciesIdTable = sDialgaFormSpeciesIdTable, @@ -4988,6 +4990,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Palkia) FOLLOWER(Palkia, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Palkia, gShinyFollowerPalette_Palkia) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sPalkiaLevelUpLearnset, .teachableLearnset = sPalkiaTeachableLearnset, .formSpeciesIdTable = sPalkiaFormSpeciesIdTable, @@ -5045,6 +5048,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = //FOLLOWER(PalkiaOrigin, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_PalkiaOrigin, gShinyFollowerPalette_PalkiaOrigin) FOLLOWER(PalkiaOrigin, SIZE_64x64, SHADOW_SIZE_M, TRACKS_NONE, gFollowerPalette_PalkiaOrigin) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sPalkiaLevelUpLearnset, .teachableLearnset = sPalkiaTeachableLearnset, .formSpeciesIdTable = sPalkiaFormSpeciesIdTable, @@ -5235,6 +5239,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Giratina) FOLLOWER(GiratinaAltered, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_GiratinaAltered, gShinyFollowerPalette_GiratinaAltered) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sGiratinaLevelUpLearnset, .teachableLearnset = sGiratinaTeachableLearnset, .formSpeciesIdTable = sGiratinaFormSpeciesIdTable, @@ -5293,6 +5298,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = //FOLLOWER(GiratinaOrigin, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_GiratinaOrigin, gShinyFollowerPalette_GiratinaOrigin) FOLLOWER(GiratinaOrigin, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_GiratinaOrigin) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sGiratinaLevelUpLearnset, .teachableLearnset = sGiratinaTeachableLearnset, .formSpeciesIdTable = sGiratinaFormSpeciesIdTable, @@ -5421,6 +5427,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Phione) FOLLOWER(Phione, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Phione, gShinyFollowerPalette_Phione) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sPhioneLevelUpLearnset, .teachableLearnset = sPhioneTeachableLearnset, }, @@ -5482,6 +5489,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Manaphy) FOLLOWER(Manaphy, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Manaphy, gShinyFollowerPalette_Manaphy) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sManaphyLevelUpLearnset, .teachableLearnset = sManaphyTeachableLearnset, }, @@ -5546,6 +5554,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Darkrai) FOLLOWER(Darkrai, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Darkrai, gShinyFollowerPalette_Darkrai) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDarkraiLevelUpLearnset, .teachableLearnset = sDarkraiTeachableLearnset, }, @@ -5612,6 +5621,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = FOOTPRINT(Shaymin) FOLLOWER(ShayminLand, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_ShayminLand, gShinyFollowerPalette_ShayminLand) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sShayminLandLevelUpLearnset, .teachableLearnset = sShayminLandTeachableLearnset, .formSpeciesIdTable = sShayminFormSpeciesIdTable, @@ -5674,6 +5684,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = .iconPalIndex = 1, FOOTPRINT(Shaymin) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sShayminSkyLevelUpLearnset, .teachableLearnset = sShayminSkyTeachableLearnset, .formSpeciesIdTable = sShayminFormSpeciesIdTable, @@ -5748,6 +5759,7 @@ const struct SpeciesInfo gSpeciesInfoGen4[] = .formSpeciesIdTable = sArceusFormSpeciesIdTable, \ .formChangeTable = sArceusFormChangeTable, \ .isMythical = TRUE, \ + .isFrontierBanned = TRUE, \ } [SPECIES_ARCEUS_NORMAL] = ARCEUS_SPECIES_INFO(TYPE_NORMAL, Normal, 1), diff --git a/src/data/pokemon/species_info/gen_5_families.h b/src/data/pokemon/species_info/gen_5_families.h index e2efda8364..17c8fada05 100644 --- a/src/data/pokemon/species_info/gen_5_families.h +++ b/src/data/pokemon/species_info/gen_5_families.h @@ -54,6 +54,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Victini) FOLLOWER(Victini, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Victini, gShinyFollowerPalette_Victini) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sVictiniLevelUpLearnset, .teachableLearnset = sVictiniTeachableLearnset, }, @@ -3526,7 +3527,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_2), .abilities = { ABILITY_SWIFT_SWIM, ABILITY_ADAPTABILITY, ABILITY_MOLD_BREAKER }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("Bsculegion"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Bsculegion", "Basculegion"), .cryId = CRY_BASCULEGION, .natDexNum = NATIONAL_DEX_BASCULEGION, .categoryName = _("Big Fish"), @@ -3582,7 +3583,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_2), .abilities = { ABILITY_SWIFT_SWIM, ABILITY_ADAPTABILITY, ABILITY_MOLD_BREAKER }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("Bsculegion"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Bsculegion", "Basculegion"), .cryId = CRY_BASCULEGION, .natDexNum = NATIONAL_DEX_BASCULEGION, .categoryName = _("Big Fish"), @@ -9925,6 +9926,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Reshiram) FOLLOWER(Reshiram, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Reshiram, gShinyFollowerPalette_Reshiram) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sReshiramLevelUpLearnset, .teachableLearnset = sReshiramTeachableLearnset, }, @@ -9981,6 +9983,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Zekrom) FOLLOWER(Zekrom, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Zekrom, gShinyFollowerPalette_Zekrom) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZekromLevelUpLearnset, .teachableLearnset = sZekromTeachableLearnset, }, @@ -10154,6 +10157,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Kyurem) FOLLOWER(Kyurem, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Kyurem, gShinyFollowerPalette_Kyurem) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKyuremLevelUpLearnset, .teachableLearnset = sKyuremTeachableLearnset, .formSpeciesIdTable = sKyuremFormSpeciesIdTable, @@ -10217,6 +10221,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Kyurem) .isLegendary = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKyuremWhiteLevelUpLearnset, .teachableLearnset = sKyuremTeachableLearnset, .formSpeciesIdTable = sKyuremFormSpeciesIdTable, @@ -10279,6 +10284,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Kyurem) .isLegendary = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKyuremBlackLevelUpLearnset, .teachableLearnset = sKyuremTeachableLearnset, .formSpeciesIdTable = sKyuremFormSpeciesIdTable, @@ -10337,6 +10343,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Keldeo) FOLLOWER(KeldeoOrdinary, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_KeldeoOrdinary, gShinyFollowerPalette_KeldeoOrdinary) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKeldeoLevelUpLearnset, .teachableLearnset = sKeldeoTeachableLearnset, .formSpeciesIdTable = sKeldeoFormSpeciesIdTable, @@ -10393,6 +10400,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .iconPalIndex = 0, FOOTPRINT(Keldeo) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKeldeoLevelUpLearnset, .teachableLearnset = sKeldeoTeachableLearnset, .formSpeciesIdTable = sKeldeoFormSpeciesIdTable, @@ -10457,6 +10465,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Meloetta) FOLLOWER(MeloettaAria, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_MeloettaAria, gShinyFollowerPalette_MeloettaAria) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMeloettaLevelUpLearnset, .teachableLearnset = sMeloettaTeachableLearnset, .formSpeciesIdTable = sMeloettaFormSpeciesIdTable, @@ -10518,6 +10527,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = FOOTPRINT(Meloetta) FOLLOWER(MeloettaPirouette, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_MeloettaPirouette, gShinyFollowerPalette_MeloettaPirouette) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMeloettaLevelUpLearnset, .teachableLearnset = sMeloettaTeachableLearnset, .formSpeciesIdTable = sMeloettaFormSpeciesIdTable, @@ -10578,6 +10588,7 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = .formSpeciesIdTable = sGenesectFormSpeciesIdTable, \ .formChangeTable = sGenesectFormChangeTable, \ .isMythical = TRUE, \ + .isFrontierBanned = TRUE, \ } [SPECIES_GENESECT] = GENESECT_SPECIES_INFO(Genesect), @@ -10589,4 +10600,4 @@ const struct SpeciesInfo gSpeciesInfoGen5[] = #ifdef __INTELLISENSE__ }; -#endif \ No newline at end of file +#endif diff --git a/src/data/pokemon/species_info/gen_6_families.h b/src/data/pokemon/species_info/gen_6_families.h index 9b75b2f55a..a642c78399 100644 --- a/src/data/pokemon/species_info/gen_6_families.h +++ b/src/data/pokemon/species_info/gen_6_families.h @@ -780,7 +780,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_FLAME_BODY, ABILITY_NONE, ABILITY_GALE_WINGS }, .bodyColor = BODY_COLOR_RED, - .speciesName = _("Flechinder"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Flechinder", "Fletchinder"), .cryId = CRY_FLETCHINDER, .natDexNum = NATIONAL_DEX_FLETCHINDER, .categoryName = _("Ember"), @@ -4752,6 +4752,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = //FOLLOWER(XerneasNeutral, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_XerneasNeutral, gShinyFollowerPalette_XerneasNeutral) FOLLOWER(XerneasNeutral, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sXerneasLevelUpLearnset, .teachableLearnset = sXerneasTeachableLearnset, .formSpeciesIdTable = sXerneasFormSpeciesIdTable, @@ -4804,6 +4805,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Xerneas) FOLLOWER(XerneasNeutral, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_XerneasNeutral, gShinyFollowerPalette_XerneasNeutral) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sXerneasLevelUpLearnset, .teachableLearnset = sXerneasTeachableLearnset, .formSpeciesIdTable = sXerneasFormSpeciesIdTable, @@ -4863,6 +4865,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Yveltal) FOLLOWER(Yveltal, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Yveltal, gShinyFollowerPalette_Yveltal) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sYveltalLevelUpLearnset, .teachableLearnset = sYveltalTeachableLearnset, }, @@ -4916,6 +4919,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Zygarde) FOLLOWER(Zygarde50, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Zygarde50, gShinyFollowerPalette_Zygarde50) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZygardeLevelUpLearnset, .teachableLearnset = sZygardeTeachableLearnset, .formSpeciesIdTable = sZygardeFormSpeciesIdTable, @@ -4968,6 +4972,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Zygarde) FOLLOWER(Zygarde50, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Zygarde50, gShinyFollowerPalette_Zygarde50) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZygardeLevelUpLearnset, .teachableLearnset = sZygardeTeachableLearnset, .formSpeciesIdTable = sZygardeFormSpeciesIdTable, @@ -5020,6 +5025,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Zygarde) //FOLLOWER(Zygarde10, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Zygarde10, gShinyFollowerPalette_Zygarde10) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZygardeLevelUpLearnset, .teachableLearnset = sZygardeTeachableLearnset, .formSpeciesIdTable = sZygardeFormSpeciesIdTable, @@ -5073,6 +5079,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Zygarde) //FOLLOWER(Zygarde10, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Zygarde10, gShinyFollowerPalette_Zygarde10) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZygardeLevelUpLearnset, .teachableLearnset = sZygardeTeachableLearnset, .formSpeciesIdTable = sZygardeFormSpeciesIdTable, @@ -5130,6 +5137,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Zygarde) //FOLLOWER(ZygardeComplete, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_ZygardeComplete, gShinyFollowerPalette_ZygardeComplete) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZygardeLevelUpLearnset, .teachableLearnset = sZygardeTeachableLearnset, .formSpeciesIdTable = sZygardeFormSpeciesIdTable, @@ -5189,6 +5197,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Diancie) FOLLOWER(Diancie, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Diancie, gShinyFollowerPalette_Diancie) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDiancieLevelUpLearnset, .teachableLearnset = sDiancieTeachableLearnset, .formSpeciesIdTable = sDiancieFormSpeciesIdTable, @@ -5247,6 +5256,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Diancie) .isMythical = TRUE, .isMegaEvolution = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sDiancieLevelUpLearnset, .teachableLearnset = sDiancieTeachableLearnset, .formSpeciesIdTable = sDiancieFormSpeciesIdTable, @@ -5307,6 +5317,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Hoopa) FOLLOWER(HoopaConfined, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_HoopaConfined, gShinyFollowerPalette_HoopaConfined) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sHoopaConfinedLevelUpLearnset, .teachableLearnset = sHoopaConfinedTeachableLearnset, .formSpeciesIdTable = sHoopaFormSpeciesIdTable, @@ -5364,6 +5375,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Hoopa) FOLLOWER(HoopaUnbound, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_HoopaUnbound, gShinyFollowerPalette_HoopaUnbound) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sHoopaUnboundLevelUpLearnset, .teachableLearnset = sHoopaUnboundTeachableLearnset, .formSpeciesIdTable = sHoopaFormSpeciesIdTable, @@ -5422,6 +5434,7 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = FOOTPRINT(Volcanion) FOLLOWER(Volcanion, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Volcanion, gShinyFollowerPalette_Volcanion) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sVolcanionLevelUpLearnset, .teachableLearnset = sVolcanionTeachableLearnset, }, @@ -5429,4 +5442,4 @@ const struct SpeciesInfo gSpeciesInfoGen6[] = #ifdef __INTELLISENSE__ }; -#endif \ No newline at end of file +#endif diff --git a/src/data/pokemon/species_info/gen_7_families.h b/src/data/pokemon/species_info/gen_7_families.h index aa11a2e56d..5ccc40b3ea 100644 --- a/src/data/pokemon/species_info/gen_7_families.h +++ b/src/data/pokemon/species_info/gen_7_families.h @@ -1172,7 +1172,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_3), .abilities = { ABILITY_HYPER_CUTTER, ABILITY_IRON_FIST, ABILITY_ANGER_POINT }, .bodyColor = BODY_COLOR_WHITE, - .speciesName = _("Crabminabl"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Crabminabl", "Crabominable"), .cryId = CRY_CRABOMINABLE, .natDexNum = NATIONAL_DEX_CRABOMINABLE, .categoryName = _("Woolly Crab"), @@ -1791,7 +1791,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPicYOffset = 0, .frontAnimFrames = sAnims_LycanrocMidnight, .frontAnimId = ANIM_SHRINK_GROW_VIBRATE_SLOW, - .backPic = gMonBackPic_LycanrocMidday, + .backPic = gMonBackPic_LycanrocMidnight, .backPicSize = MON_COORDS_SIZE(64, 56), .backPicYOffset = 7, .backAnimId = BACK_ANIM_SHRINK_GROW_VIBRATE, @@ -1845,9 +1845,9 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .frontPicYOffset = 6, .frontAnimFrames = sAnims_LycanrocDusk, .frontAnimId = ANIM_V_SHAKE, - .backPic = gMonBackPic_LycanrocMidday, + .backPic = gMonBackPic_LycanrocDusk, .backPicSize = MON_COORDS_SIZE(64, 56), - .backPicYOffset = 5, + .backPicYOffset = 6, .backAnimId = BACK_ANIM_V_SHAKE, .palette = gMonPalette_LycanrocDusk, .shinyPalette = gMonShinyPalette_LycanrocDusk, @@ -4835,6 +4835,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOLLOWER(Cosmog, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Cosmog, gShinyFollowerPalette_Cosmog) .isLegendary = TRUE, .tmIlliterate = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sCosmogLevelUpLearnset, .teachableLearnset = sCosmogTeachableLearnset, .evolutions = EVOLUTION({EVO_LEVEL, 43, SPECIES_COSMOEM}), @@ -4893,6 +4894,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOLLOWER(Cosmoem, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Cosmoem, gShinyFollowerPalette_Cosmoem) .isLegendary = TRUE, .tmIlliterate = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sCosmoemLevelUpLearnset, .teachableLearnset = sCosmoemTeachableLearnset, .evolutions = EVOLUTION({EVO_LEVEL_DAY, 53, SPECIES_SOLGALEO}, @@ -4949,6 +4951,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Solgaleo) FOLLOWER(Solgaleo, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Solgaleo, gShinyFollowerPalette_Solgaleo) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sSolgaleoLevelUpLearnset, .teachableLearnset = sSolgaleoTeachableLearnset, }, @@ -5004,6 +5007,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Lunala) FOLLOWER(Lunala, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Lunala, gShinyFollowerPalette_Lunala) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sLunalaLevelUpLearnset, .teachableLearnset = sLunalaTeachableLearnset, }, @@ -5460,6 +5464,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Necrozma) FOLLOWER(Necrozma, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Necrozma, gShinyFollowerPalette_Necrozma) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sNecrozmaLevelUpLearnset, .teachableLearnset = sNecrozmaTeachableLearnset, .formSpeciesIdTable = sNecrozmaFormSpeciesIdTable, @@ -5518,6 +5523,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOLLOWER(NecrozmaDuskMane, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_NecrozmaDuskMane, gShinyFollowerPalette_NecrozmaDuskMane) .isLegendary = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sNecrozmaLevelUpLearnset, .teachableLearnset = sNecrozmaTeachableLearnset, .formSpeciesIdTable = sNecrozmaFormSpeciesIdTable, @@ -5577,6 +5583,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOLLOWER(NecrozmaDawnWings, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_NecrozmaDawnWings, gShinyFollowerPalette_NecrozmaDawnWings) .isLegendary = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sNecrozmaLevelUpLearnset, .teachableLearnset = sNecrozmaTeachableLearnset, .formSpeciesIdTable = sNecrozmaFormSpeciesIdTable, @@ -5639,6 +5646,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .isLegendary = TRUE, .isUltraBurst = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sNecrozmaLevelUpLearnset, .teachableLearnset = sNecrozmaTeachableLearnset, .formSpeciesIdTable = sNecrozmaFormSpeciesIdTable, @@ -5698,6 +5706,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Magearna) FOLLOWER(Magearna, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Magearna, gShinyFollowerPalette_Magearna) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMagearnaLevelUpLearnset, .teachableLearnset = sMagearnaTeachableLearnset, .formSpeciesIdTable = sMagearnaFormSpeciesIdTable, @@ -5751,6 +5760,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .iconPalIndex = 0, FOOTPRINT(Magearna) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMagearnaLevelUpLearnset, .teachableLearnset = sMagearnaTeachableLearnset, .formSpeciesIdTable = sMagearnaFormSpeciesIdTable, @@ -5810,6 +5820,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Marshadow) FOLLOWER(Marshadow, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Marshadow, gShinyFollowerPalette_Marshadow) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMarshadowLevelUpLearnset, .teachableLearnset = sMarshadowTeachableLearnset, }, @@ -6003,7 +6014,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = .abilities = { ABILITY_BEAST_BOOST, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_WHITE, .noFlip = TRUE, - .speciesName = _("Blacephaln"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Blacephaln", "Blacephalon"), .cryId = CRY_BLACEPHALON, .natDexNum = NATIONAL_DEX_BLACEPHALON, .categoryName = _("Fireworks"), @@ -6088,6 +6099,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Zeraora) FOLLOWER(Zeraora, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Zeraora, gShinyFollowerPalette_Zeraora) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZeraoraLevelUpLearnset, .teachableLearnset = sZeraoraTeachableLearnset, }, @@ -6143,6 +6155,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Meltan) FOLLOWER(Meltan, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Meltan, gShinyFollowerPalette_Meltan) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMeltanLevelUpLearnset, .teachableLearnset = sMeltanTeachableLearnset, }, @@ -6196,6 +6209,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Melmetal) FOLLOWER(Melmetal, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT, gFollowerPalette_Melmetal, gShinyFollowerPalette_Melmetal) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMelmetalLevelUpLearnset, .teachableLearnset = sMelmetalTeachableLearnset, .formSpeciesIdTable = sMelmetalFormSpeciesIdTable, @@ -6253,6 +6267,7 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = FOOTPRINT(Melmetal) .isMythical = TRUE, .isGigantamax = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMelmetalLevelUpLearnset, .teachableLearnset = sMelmetalTeachableLearnset, .formSpeciesIdTable = sMelmetalFormSpeciesIdTable, @@ -6263,4 +6278,4 @@ const struct SpeciesInfo gSpeciesInfoGen7[] = #ifdef __INTELLISENSE__ }; -#endif \ No newline at end of file +#endif diff --git a/src/data/pokemon/species_info/gen_8_families.h b/src/data/pokemon/species_info/gen_8_families.h index 119b5b9da2..f697565e8d 100644 --- a/src/data/pokemon/species_info/gen_8_families.h +++ b/src/data/pokemon/species_info/gen_8_families.h @@ -849,7 +849,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_KEEN_EYE, ABILITY_UNNERVE, ABILITY_BIG_PECKS }, .bodyColor = BODY_COLOR_BLUE, - .speciesName = _("Corvisquir"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Corvisquir", "Corvisquire"), .cryId = CRY_CORVISQUIRE, .natDexNum = NATIONAL_DEX_CORVISQUIRE, .categoryName = _("Raven"), @@ -904,7 +904,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_PRESSURE, ABILITY_UNNERVE, ABILITY_MIRROR_ARMOR }, .bodyColor = BODY_COLOR_PURPLE, - .speciesName = _("Corviknigh"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Corviknigh", "Corviknight"), .cryId = CRY_CORVIKNIGHT, .natDexNum = NATIONAL_DEX_CORVIKNIGHT, .categoryName = _("Raven"), @@ -2840,7 +2840,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_2), .abilities = { ABILITY_SWIFT_SWIM, ABILITY_NONE, ABILITY_PROPELLER_TAIL }, .bodyColor = BODY_COLOR_BROWN, - .speciesName = _("Barraskewd"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Barraskewd", "Barraskewda"), .cryId = CRY_BARRASKEWDA, .natDexNum = NATIONAL_DEX_BARRASKEWDA, .categoryName = _("Skewer"), @@ -3221,7 +3221,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_BUG), .abilities = { ABILITY_FLASH_FIRE, ABILITY_WHITE_SMOKE, ABILITY_FLAME_BODY }, .bodyColor = BODY_COLOR_RED, - .speciesName = _("Centiskorc"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Centiskorc", "Centiskorch"), .cryId = CRY_CENTISKORCH, .natDexNum = NATIONAL_DEX_CENTISKORCH, .categoryName = _("Radiator"), @@ -3554,7 +3554,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MINERAL, EGG_GROUP_AMORPHOUS), .abilities = { ABILITY_WEAK_ARMOR, ABILITY_NONE, ABILITY_CURSED_BODY }, .bodyColor = BODY_COLOR_PURPLE, - .speciesName = _("Polteageis"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Polteageis", "Polteageist"), .cryId = CRY_POLTEAGEIST, .natDexNum = NATIONAL_DEX_POLTEAGEIST, .categoryName = _("Black Tea"), @@ -3608,7 +3608,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MINERAL, EGG_GROUP_AMORPHOUS), .abilities = { ABILITY_WEAK_ARMOR, ABILITY_NONE, ABILITY_CURSED_BODY }, .bodyColor = BODY_COLOR_PURPLE, - .speciesName = _("Polteageis"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Polteageis", "Polteageist"), .cryId = CRY_POLTEAGEIST, .natDexNum = NATIONAL_DEX_POLTEAGEIST, .categoryName = _("Black Tea"), @@ -4548,7 +4548,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MINERAL), .abilities = { ABILITY_POWER_SPOT, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GRAY, - .speciesName = _("Stonjourne"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Stonjourne", "Stonjourner"), .cryId = CRY_STONJOURNER, .natDexNum = NATIONAL_DEX_STONJOURNER, .categoryName = _("Big Rock"), @@ -5686,6 +5686,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOOTPRINT(Zacian) FOLLOWER(ZacianHeroOfManyBattles, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZacianLevelUpLearnset, .teachableLearnset = sZacianTeachableLearnset, .formSpeciesIdTable = sZacianFormSpeciesIdTable, @@ -5742,6 +5743,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOOTPRINT(Zacian) FOLLOWER(ZacianCrownedSword, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZacianLevelUpLearnset, .teachableLearnset = sZacianTeachableLearnset, .formSpeciesIdTable = sZacianFormSpeciesIdTable, @@ -5799,6 +5801,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .iconPalIndex = 2, FOOTPRINT(Zamazenta) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZamazentaLevelUpLearnset, .teachableLearnset = sZamazentaTeachableLearnset, .formSpeciesIdTable = sZamazentaFormSpeciesIdTable, @@ -5855,6 +5858,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOOTPRINT(Zamazenta) FOLLOWER(ZamazentaCrownedShield, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZamazentaLevelUpLearnset, .teachableLearnset = sZamazentaTeachableLearnset, .formSpeciesIdTable = sZamazentaFormSpeciesIdTable, @@ -5914,6 +5918,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOOTPRINT(Eternatus) FOLLOWER(Eternatus, SIZE_64x64, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sEternatusLevelUpLearnset, .teachableLearnset = sEternatusTeachableLearnset, .formSpeciesIdTable = sEternatusFormSpeciesIdTable, @@ -5969,6 +5974,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .iconPalIndex = 0, FOOTPRINT(Eternatus) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sEternatusLevelUpLearnset, .teachableLearnset = sEternatusTeachableLearnset, .formSpeciesIdTable = sEternatusFormSpeciesIdTable, @@ -6311,6 +6317,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOOTPRINT(Zarude) FOLLOWER(Zarude, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZarudeLevelUpLearnset, .teachableLearnset = sZarudeTeachableLearnset, .formSpeciesIdTable = sZarudeFormSpeciesIdTable, @@ -6364,6 +6371,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = .iconPalIndex = 1, FOOTPRINT(Zarude) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sZarudeLevelUpLearnset, .teachableLearnset = sZarudeTeachableLearnset, .formSpeciesIdTable = sZarudeFormSpeciesIdTable, @@ -6646,6 +6654,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOOTPRINT(Calyrex) FOLLOWER(Calyrex, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sCalyrexLevelUpLearnset, .teachableLearnset = sCalyrexTeachableLearnset, .formSpeciesIdTable = sCalyrexFormSpeciesIdTable, @@ -6703,6 +6712,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOLLOWER(CalyrexIceRider, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sCalyrexIceRiderLevelUpLearnset, .teachableLearnset = sCalyrexIceRiderTeachableLearnset, .formSpeciesIdTable = sCalyrexFormSpeciesIdTable, @@ -6759,6 +6769,7 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = FOLLOWER(CalyrexShadowRider, SIZE_32x32, SHADOW_SIZE_M, TRACKS_FOOT) .isLegendary = TRUE, .cannotBeTraded = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sCalyrexShadowRiderLevelUpLearnset, .teachableLearnset = sCalyrexShadowRiderTeachableLearnset, .formSpeciesIdTable = sCalyrexFormSpeciesIdTable, @@ -6881,4 +6892,4 @@ const struct SpeciesInfo gSpeciesInfoGen8[] = #ifdef __INTELLISENSE__ }; -#endif \ No newline at end of file +#endif diff --git a/src/data/pokemon/species_info/gen_9_families.h b/src/data/pokemon/species_info/gen_9_families.h index 304f0560a2..33097c3ef6 100644 --- a/src/data/pokemon/species_info/gen_9_families.h +++ b/src/data/pokemon/species_info/gen_9_families.h @@ -129,7 +129,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FIELD, EGG_GROUP_GRASS), .abilities = { ABILITY_OVERGROW, ABILITY_NONE, ABILITY_PROTEAN }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("Meowscarad"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Meowscarad", "Meowscarada"), .cryId = CRY_MEOWSCARADA, .natDexNum = NATIONAL_DEX_MEOWSCARADA, .categoryName = _("Magician"), @@ -1466,7 +1466,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_INTIMIDATE, ABILITY_HUSTLE, ABILITY_GUTS }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("Sqawkabily"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Sqawkabily", "Squawkabilly"), .cryId = CRY_SQUAWKABILLY, .natDexNum = NATIONAL_DEX_SQUAWKABILLY, .categoryName = _("Parrot"), @@ -1519,7 +1519,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_INTIMIDATE, ABILITY_HUSTLE, ABILITY_GUTS }, .bodyColor = BODY_COLOR_BLUE, - .speciesName = _("Sqawkabily"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Sqawkabily", "Squawkabilly"), .cryId = CRY_SQUAWKABILLY, .natDexNum = NATIONAL_DEX_SQUAWKABILLY, .categoryName = _("Parrot"), @@ -1572,7 +1572,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_INTIMIDATE, ABILITY_HUSTLE, ABILITY_SHEER_FORCE }, .bodyColor = BODY_COLOR_YELLOW, - .speciesName = _("Sqawkabily"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Sqawkabily", "Squawkabilly"), .cryId = CRY_SQUAWKABILLY, .natDexNum = NATIONAL_DEX_SQUAWKABILLY, .categoryName = _("Parrot"), @@ -1625,7 +1625,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_FLYING), .abilities = { ABILITY_INTIMIDATE, ABILITY_HUSTLE, ABILITY_SHEER_FORCE }, .bodyColor = BODY_COLOR_WHITE, - .speciesName = _("Sqawkabily"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Sqawkabily", "Squawkabilly"), .cryId = CRY_SQUAWKABILLY, .natDexNum = NATIONAL_DEX_SQUAWKABILLY, .categoryName = _("Parrot"), @@ -2161,7 +2161,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_WATER_1, EGG_GROUP_FLYING), .abilities = { ABILITY_WIND_POWER, ABILITY_VOLT_ABSORB, ABILITY_COMPETITIVE }, .bodyColor = BODY_COLOR_YELLOW, - .speciesName = _("Kilowatrel"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Kilowatrel", "Kilowattrel"), .cryId = CRY_KILOWATTREL, .natDexNum = NATIONAL_DEX_KILOWATTREL, .categoryName = _("Frigatebird"), @@ -2482,7 +2482,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_GRASS), .abilities = { ABILITY_WIND_RIDER, ABILITY_NONE, ABILITY_INFILTRATOR }, .bodyColor = BODY_COLOR_BROWN, - .speciesName = _("Brmblghast"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Brmblghast", "Brambleghast"), .cryId = CRY_BRAMBLEGHAST, .natDexNum = NATIONAL_DEX_BRAMBLEGHAST, .categoryName = _("Tumbleweed"), @@ -4390,7 +4390,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_GreatTusk, .iconPalIndex = 0, //FOOTPRINT(GreatTusk) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sGreatTuskLevelUpLearnset, .teachableLearnset = sGreatTuskTeachableLearnset, }, @@ -4416,7 +4416,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_PINK, - .speciesName = _("ScreamTail"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("ScreamTail", "Scream Tail"), .cryId = CRY_SCREAM_TAIL, .natDexNum = NATIONAL_DEX_SCREAM_TAIL, .categoryName = _("Paradox"), @@ -4445,7 +4445,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_ScreamTail, .iconPalIndex = 0, //FOOTPRINT(ScreamTail) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sScreamTailLevelUpLearnset, .teachableLearnset = sScreamTailTeachableLearnset, }, @@ -4471,7 +4471,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_WHITE, - .speciesName = _("BruteBonet"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("BruteBonet", "Brute Bonnet"), .cryId = CRY_BRUTE_BONNET, .natDexNum = NATIONAL_DEX_BRUTE_BONNET, .categoryName = _("Paradox"), @@ -4500,7 +4500,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_BruteBonnet, .iconPalIndex = 1, //FOOTPRINT(BruteBonnet) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sBruteBonnetLevelUpLearnset, .teachableLearnset = sBruteBonnetTeachableLearnset, }, @@ -4528,7 +4528,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GRAY, - .speciesName = _("FluttrMane"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("FluttrMane", "Flutter Mane"), .cryId = CRY_FLUTTER_MANE, .natDexNum = NATIONAL_DEX_FLUTTER_MANE, .categoryName = _("Paradox"), @@ -4558,7 +4558,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_FlutterMane, .iconPalIndex = 2, //FOOTPRINT(FlutterMane) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sFlutterManeLevelUpLearnset, .teachableLearnset = sFlutterManeTeachableLearnset, }, @@ -4584,7 +4584,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_WHITE, - .speciesName = _("SlithrWing"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("SlithrWing", "Slither Wing"), .cryId = CRY_SLITHER_WING, .natDexNum = NATIONAL_DEX_SLITHER_WING, .categoryName = _("Paradox"), @@ -4612,7 +4612,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_SlitherWing, .iconPalIndex = 1, //FOOTPRINT(SlitherWing) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sSlitherWingLevelUpLearnset, .teachableLearnset = sSlitherWingTeachableLearnset, }, @@ -4638,7 +4638,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GRAY, - .speciesName = _("SndyShocks"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("SndyShocks", "Sandy Shocks"), .cryId = CRY_SANDY_SHOCKS, .natDexNum = NATIONAL_DEX_SANDY_SHOCKS, .categoryName = _("Paradox"), @@ -4667,7 +4667,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_SandyShocks, .iconPalIndex = 0, //FOOTPRINT(SandyShocks) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sSandyShocksLevelUpLearnset, .teachableLearnset = sSandyShocksTeachableLearnset, }, @@ -4693,7 +4693,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GRAY, - .speciesName = _("IronTreads"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronTreads", "Iron Treads"), .cryId = CRY_IRON_TREADS, .natDexNum = NATIONAL_DEX_IRON_TREADS, .categoryName = _("Paradox"), @@ -4722,7 +4722,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronTreads, .iconPalIndex = 1, //FOOTPRINT(IronTreads) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronTreadsLevelUpLearnset, .teachableLearnset = sIronTreadsTeachableLearnset, }, @@ -4748,7 +4748,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_RED, - .speciesName = _("IronBundle"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronBundle", "Iron Bundle"), .cryId = CRY_IRON_BUNDLE, .natDexNum = NATIONAL_DEX_IRON_BUNDLE, .categoryName = _("Paradox"), @@ -4777,7 +4777,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronBundle, .iconPalIndex = 0, //FOOTPRINT(IronBundle) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronBundleLevelUpLearnset, .teachableLearnset = sIronBundleTeachableLearnset, }, @@ -4832,7 +4832,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronHands, .iconPalIndex = 0, //FOOTPRINT(IronHands) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronHandsLevelUpLearnset, .teachableLearnset = sIronHandsTeachableLearnset, }, @@ -4858,7 +4858,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_BLUE, - .speciesName = _("IronJuguls"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronJuguls", "Iron Jugulis"), .cryId = CRY_IRON_JUGULIS, .natDexNum = NATIONAL_DEX_IRON_JUGULIS, .categoryName = _("Paradox"), @@ -4888,7 +4888,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronJugulis, .iconPalIndex = 0, //FOOTPRINT(IronJugulis) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronJugulisLevelUpLearnset, .teachableLearnset = sIronJugulisTeachableLearnset, }, @@ -4944,7 +4944,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronMoth, .iconPalIndex = 3, //FOOTPRINT(IronMoth) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronMothLevelUpLearnset, .teachableLearnset = sIronMothTeachableLearnset, }, @@ -4970,7 +4970,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("IronThorns"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronThorns", "Iron Thorns"), .cryId = CRY_IRON_THORNS, .natDexNum = NATIONAL_DEX_IRON_THORNS, .categoryName = _("Paradox"), @@ -4999,7 +4999,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronThorns, .iconPalIndex = 1, //FOOTPRINT(IronThorns) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronThornsLevelUpLearnset, .teachableLearnset = sIronThornsTeachableLearnset, }, @@ -5568,7 +5568,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_BLUE, - .speciesName = _("RoarngMoon"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("RoarngMoon", "Roaring Moon"), .cryId = CRY_ROARING_MOON, .natDexNum = NATIONAL_DEX_ROARING_MOON, .categoryName = _("Paradox"), @@ -5598,7 +5598,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_RoaringMoon, .iconPalIndex = 0, //FOOTPRINT(RoaringMoon) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sRoaringMoonLevelUpLearnset, .teachableLearnset = sRoaringMoonTeachableLearnset, }, @@ -5624,7 +5624,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_WHITE, - .speciesName = _("IronVliant"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronVliant", "Iron Valiant"), .cryId = CRY_IRON_VALIANT, .natDexNum = NATIONAL_DEX_IRON_VALIANT, .categoryName = _("Paradox"), @@ -5652,7 +5652,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronValiant, .iconPalIndex = 1, //FOOTPRINT(IronValiant) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronValiantLevelUpLearnset, .teachableLearnset = sIronValiantTeachableLearnset, }, @@ -5708,6 +5708,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconPalIndex = 0, //FOOTPRINT(Koraidon) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sKoraidonLevelUpLearnset, .teachableLearnset = sKoraidonTeachableLearnset, }, @@ -5763,6 +5764,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconPalIndex = 2, //FOOTPRINT(Miraidon) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sMiraidonLevelUpLearnset, .teachableLearnset = sMiraidonTeachableLearnset, }, @@ -5788,7 +5790,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_BLUE, - .speciesName = _("WalkngWake"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("WalkngWake", "Walking Wake"), .cryId = CRY_WALKING_WAKE, .natDexNum = NATIONAL_DEX_WALKING_WAKE, .categoryName = _("Paradox"), @@ -5816,7 +5818,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_WalkingWake, .iconPalIndex = 2, //FOOTPRINT(WalkingWake) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sWalkingWakeLevelUpLearnset, .teachableLearnset = sWalkingWakeTeachableLearnset, }, @@ -5842,7 +5844,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("IronLeaves"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronLeaves", "Iron Leaves"), .cryId = CRY_IRON_LEAVES, .natDexNum = NATIONAL_DEX_IRON_LEAVES, .categoryName = _("Paradox"), @@ -5870,7 +5872,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronLeaves, .iconPalIndex = 1, //FOOTPRINT(IronLeaves) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronLeavesLevelUpLearnset, .teachableLearnset = sIronLeavesTeachableLearnset, }, @@ -5896,7 +5898,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MINERAL, EGG_GROUP_AMORPHOUS), .abilities = { ABILITY_HOSPITALITY, ABILITY_NONE, ABILITY_HEATPROOF }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("Ptchageist"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Ptchageist", "Poltchageist"), .cryId = CRY_POLTCHAGEIST, .natDexNum = NATIONAL_DEX_POLTCHAGEIST, .categoryName = _("Matcha"), @@ -5949,7 +5951,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_MINERAL, EGG_GROUP_AMORPHOUS), .abilities = { ABILITY_HOSPITALITY, ABILITY_NONE, ABILITY_HEATPROOF }, .bodyColor = BODY_COLOR_GREEN, - .speciesName = _("Ptchageist"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Ptchageist", "Poltchageist"), .cryId = CRY_POLTCHAGEIST, .natDexNum = NATIONAL_DEX_POLTCHAGEIST, .categoryName = _("Matcha"), @@ -6220,7 +6222,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_TOXIC_CHAIN, ABILITY_NONE, ABILITY_TECHNICIAN }, .bodyColor = BODY_COLOR_BLACK, - .speciesName = _("Fezndipiti"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("Fezndipiti", "Fezandipiti"), .cryId = CRY_FEZANDIPITI, .natDexNum = NATIONAL_DEX_FEZANDIPITI, .categoryName = _("Retainer"), @@ -6312,10 +6314,10 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = [SPECIES_OGERPON_HEARTHFLAME_MASK] = OGERPON_SPECIES_INFO(HearthflameMask, TYPE_FIRE, ABILITY_MOLD_BREAKER, BODY_COLOR_RED, 0), [SPECIES_OGERPON_CORNERSTONE_MASK] = OGERPON_SPECIES_INFO(CornerstoneMask, TYPE_ROCK, ABILITY_STURDY, BODY_COLOR_GRAY, 0), #if P_TERA_FORMS - [SPECIES_OGERPON_TEAL_MASK_TERA] = OGERPON_SPECIES_INFO(TealMask, TYPE_GRASS, ABILITY_EMBODY_ASPECT_TEAL, BODY_COLOR_GREEN, 1), - [SPECIES_OGERPON_WELLSPRING_MASK_TERA] = OGERPON_SPECIES_INFO(WellspringMask, TYPE_WATER, ABILITY_EMBODY_ASPECT_WELLSPRING, BODY_COLOR_BLUE, 0), - [SPECIES_OGERPON_HEARTHFLAME_MASK_TERA] = OGERPON_SPECIES_INFO(HearthflameMask, TYPE_FIRE, ABILITY_EMBODY_ASPECT_HEARTHFLAME, BODY_COLOR_RED, 0), - [SPECIES_OGERPON_CORNERSTONE_MASK_TERA] = OGERPON_SPECIES_INFO(CornerstoneMask, TYPE_ROCK, ABILITY_EMBODY_ASPECT_CORNERSTONE, BODY_COLOR_GRAY, 0), + [SPECIES_OGERPON_TEAL_MASK_TERA] = OGERPON_SPECIES_INFO(TealMask, TYPE_GRASS, ABILITY_EMBODY_ASPECT_TEAL_MASK, BODY_COLOR_GREEN, 1), + [SPECIES_OGERPON_WELLSPRING_MASK_TERA] = OGERPON_SPECIES_INFO(WellspringMask, TYPE_WATER, ABILITY_EMBODY_ASPECT_WELLSPRING_MASK, BODY_COLOR_BLUE, 0), + [SPECIES_OGERPON_HEARTHFLAME_MASK_TERA] = OGERPON_SPECIES_INFO(HearthflameMask, TYPE_FIRE, ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK, BODY_COLOR_RED, 0), + [SPECIES_OGERPON_CORNERSTONE_MASK_TERA] = OGERPON_SPECIES_INFO(CornerstoneMask, TYPE_ROCK, ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK, BODY_COLOR_GRAY, 0), #endif //P_TERA_FORMS #endif //P_FAMILY_OGERPON @@ -6340,7 +6342,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_BROWN, - .speciesName = _("GouginFire"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("GouginFire", "Gouging Fire"), .cryId = CRY_GOUGING_FIRE, .natDexNum = NATIONAL_DEX_GOUGING_FIRE, .categoryName = _("Paradox"), @@ -6369,7 +6371,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_GougingFire, .iconPalIndex = 5, //FOOTPRINT(GougingFire) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sGougingFireLevelUpLearnset, .teachableLearnset = sGougingFireTeachableLearnset, }, @@ -6395,7 +6397,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_PROTOSYNTHESIS, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_YELLOW, - .speciesName = _("RagingBolt"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("RagingBolt", "Raging Bolt"), .cryId = CRY_RAGING_BOLT, .natDexNum = NATIONAL_DEX_RAGING_BOLT, .categoryName = _("Paradox"), @@ -6424,7 +6426,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_RagingBolt, .iconPalIndex = 2, //FOOTPRINT(RagingBolt) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sRagingBoltLevelUpLearnset, .teachableLearnset = sRagingBoltTeachableLearnset, }, @@ -6450,7 +6452,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .eggGroups = MON_EGG_GROUPS(EGG_GROUP_NO_EGGS_DISCOVERED), .abilities = { ABILITY_QUARK_DRIVE, ABILITY_NONE, ABILITY_NONE }, .bodyColor = BODY_COLOR_GRAY, - .speciesName = _("IronBouldr"), + .speciesName = HANDLE_EXPANDED_SPECIES_NAME("IronBouldr", "Iron Boulder"), .cryId = CRY_IRON_BOULDER, .natDexNum = NATIONAL_DEX_IRON_BOULDER, .categoryName = _("Paradox"), @@ -6478,7 +6480,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronBoulder, .iconPalIndex = 5, //FOOTPRINT(IronBoulder) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronBoulderLevelUpLearnset, .teachableLearnset = sIronBoulderTeachableLearnset, }, @@ -6533,7 +6535,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconSprite = gMonIcon_IronCrown, .iconPalIndex = 3, //FOOTPRINT(IronCrown) - .isParadoxForm = TRUE, + .isParadox = TRUE, .levelUpLearnset = sIronCrownLevelUpLearnset, .teachableLearnset = sIronCrownTeachableLearnset, }, @@ -6589,6 +6591,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconPalIndex = 0, //FOOTPRINT(Terapagos) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sTerapagosLevelUpLearnset, .teachableLearnset = sTerapagosTeachableLearnset, .formSpeciesIdTable = sTerapagosFormSpeciesIdTable, @@ -6645,6 +6648,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconPalIndex = 0, //FOOTPRINT(Terapagos) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sTerapagosLevelUpLearnset, .teachableLearnset = sTerapagosTeachableLearnset, .formSpeciesIdTable = sTerapagosFormSpeciesIdTable, @@ -6700,6 +6704,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconPalIndex = 0, //FOOTPRINT(Terapagos) .isLegendary = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sTerapagosLevelUpLearnset, .teachableLearnset = sTerapagosTeachableLearnset, .formSpeciesIdTable = sTerapagosFormSpeciesIdTable, @@ -6757,6 +6762,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] = .iconPalIndex = 0, //FOOTPRINT(Pecharunt) .isMythical = TRUE, + .isFrontierBanned = TRUE, .levelUpLearnset = sPecharuntLevelUpLearnset, .teachableLearnset = sPecharuntTeachableLearnset, }, diff --git a/src/daycare.c b/src/daycare.c index b3131772be..2df37dfbac 100644 --- a/src/daycare.c +++ b/src/daycare.c @@ -96,11 +96,11 @@ static const u8 *const sCompatibilityMessages[] = static const u8 sJapaneseEggNickname[] = _("タマゴ"); // "tamago" ("egg" in Japanese) -u8 *GetMonNickname2(struct Pokemon *mon, u8 *dest) +u8 *GetMonNicknameVanilla(struct Pokemon *mon, u8 *dest) { u8 nickname[POKEMON_NAME_BUFFER_SIZE]; GetMonData(mon, MON_DATA_NICKNAME, nickname); - return StringCopy_Nickname(dest, nickname); + return StringCopyN(dest, nickname, VANILLA_POKEMON_NAME_LENGTH); } u8 *GetBoxMonNickname(struct BoxPokemon *mon, u8 *dest) @@ -218,7 +218,7 @@ static void StorePokemonInDaycare(struct Pokemon *mon, struct DaycareMon *daycar u8 mailId; StringCopy(daycareMon->mail.otName, gSaveBlock2Ptr->playerName); - GetMonNickname2(mon, daycareMon->mail.monName); + GetMonNicknameVanilla(mon, daycareMon->mail.monName); StripExtCtrlCodes(daycareMon->mail.monName); daycareMon->mail.gameLanguage = GAME_LANGUAGE; daycareMon->mail.monLanguage = GetMonData(mon, MON_DATA_LANGUAGE); @@ -418,7 +418,7 @@ static void ClearDaycareMonMail(struct DaycareMail *mail) for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) mail->otName[i] = 0; - for (i = 0; i < POKEMON_NAME_LENGTH + 1; i++) + for (i = 0; i < VANILLA_POKEMON_NAME_LENGTH + 1; i++) mail->monName[i] = 0; ClearMail(&mail->message); diff --git a/src/debug.c b/src/debug.c index ea3ffbabb8..92972c289e 100644 --- a/src/debug.c +++ b/src/debug.c @@ -1344,36 +1344,16 @@ static void Debug_InitDebugBattleData(void) sDebugBattleData->aiFlags[i] = FALSE; } -static void Debug_RefreshListMenu(u8 taskId) +static void Debug_GenerateListMenuNames(u32 totalItems) { - u16 i; const u8 sColor_Red[] = _("{COLOR RED}"); const u8 sColor_Green[] = _("{COLOR GREEN}"); - u8 totalItems = 0, flagResult = 0; + u32 i, flagResult = 0; u8 const *name = NULL; - if (sDebugMenuListData->listId == 0) - { - gMultiuseListMenuTemplate = sDebugMenu_ListTemplate_FlagsVars; - totalItems = gMultiuseListMenuTemplate.totalItems; - } - else if (sDebugMenuListData->listId == 1 && sDebugBattleData->submenu <= 1) - { - gMultiuseListMenuTemplate = sDebugMenu_ListTemplate_Battle_1; - totalItems = gMultiuseListMenuTemplate.totalItems; - } - else if (sDebugMenuListData->listId == 1 && sDebugBattleData->submenu > 1) - { - gMultiuseListMenuTemplate = sDebugMenu_ListTemplate_Battle_2; - totalItems = 7; - } - - // Failsafe to prevent memory corruption - totalItems = min(totalItems, DEBUG_MAX_MENU_ITEMS); // Copy item names for all entries but the last (which is Cancel) - for(i = 0; i < totalItems; i++) + for (i = 0; i < totalItems; i++) { - if (sDebugMenuListData->listId == 1 && sDebugBattleData->submenu > 1) { u16 species; @@ -1429,6 +1409,31 @@ static void Debug_RefreshListMenu(u8 taskId) sDebugMenuListData->listItems[i].name = &sDebugMenuListData->itemNames[i][0]; sDebugMenuListData->listItems[i].id = i; } +} + +static void Debug_RefreshListMenu(u8 taskId) +{ + u8 totalItems = 0; + + if (sDebugMenuListData->listId == 0) + { + gMultiuseListMenuTemplate = sDebugMenu_ListTemplate_FlagsVars; + totalItems = gMultiuseListMenuTemplate.totalItems; + } + else if (sDebugMenuListData->listId == 1 && sDebugBattleData->submenu <= 1) + { + gMultiuseListMenuTemplate = sDebugMenu_ListTemplate_Battle_1; + totalItems = gMultiuseListMenuTemplate.totalItems; + } + else if (sDebugMenuListData->listId == 1 && sDebugBattleData->submenu > 1) + { + gMultiuseListMenuTemplate = sDebugMenu_ListTemplate_Battle_2; + totalItems = 7; + } + + // Failsafe to prevent memory corruption + totalItems = min(totalItems, DEBUG_MAX_MENU_ITEMS); + Debug_GenerateListMenuNames(totalItems); // Set list menu data gMultiuseListMenuTemplate.items = sDebugMenuListData->listItems; @@ -1595,7 +1600,8 @@ static void DebugTask_HandleMenuInput_FlagsVars(u8 taskId) else { func(taskId); - Debug_RedrawListMenu(taskId); + Debug_GenerateListMenuNames(gMultiuseListMenuTemplate.totalItems); + RedrawListMenu(gTasks[taskId].tMenuTaskId); } // Remove TRUE/FALSE window for functions that haven't been assigned flags @@ -4096,7 +4102,7 @@ static void DebugAction_PCBag_Fill_PCBoxes_Fast(u8 taskId) //Credit: Sierraffini StringCopy(speciesName, GetSpeciesName(species)); SetBoxMonData(&boxMon, MON_DATA_NICKNAME, &speciesName); SetBoxMonData(&boxMon, MON_DATA_SPECIES, &species); - GiveBoxMonInitialMoveset_Fast(&boxMon); + GiveBoxMonInitialMoveset(&boxMon); gPokemonStoragePtr->boxes[boxId][boxPosition] = boxMon; } } diff --git a/src/egg_hatch.c b/src/egg_hatch.c index 588563d5d2..beb6ba40c4 100644 --- a/src/egg_hatch.c +++ b/src/egg_hatch.c @@ -36,6 +36,7 @@ #include "data.h" #include "battle.h" // to get rid of later #include "constants/rgb.h" +#include "party_menu.h" #define GFXTAG_EGG 12345 #define GFXTAG_EGG_SHARD 23456 @@ -375,7 +376,7 @@ static void AddHatchedMonToParty(u8 id) GetSetPokedexFlag(species, FLAG_SET_SEEN); GetSetPokedexFlag(species, FLAG_SET_CAUGHT); - GetMonNickname2(mon, gStringVar1); + GetMonNickname(mon, gStringVar1); // A met level of 0 is interpreted on the summary screen as "hatched at" metLevel = 0; @@ -648,7 +649,7 @@ static void CB2_EggHatch(void) break; case 5: // "{mon} hatched from egg" message/fanfare - GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar1); + GetMonNickname(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_HatchedFromEgg); EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 3, TEXT_SKIP_DRAW); PlayFanfare(MUS_EVOLVED); @@ -666,7 +667,7 @@ static void CB2_EggHatch(void) break; case 8: // Ready the nickname prompt - GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar1); + GetMonNickname(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_NicknameHatchPrompt); EggHatchPrintMessage(sEggHatchData->windowId, gStringVar4, 0, 2, 1); sEggHatchData->state++; @@ -685,7 +686,7 @@ static void CB2_EggHatch(void) switch (Menu_ProcessInputNoWrapClearOnChoose()) { case 0: // Yes - GetMonNickname2(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar3); + GetMonNickname(&gPlayerParty[sEggHatchData->eggPartyId], gStringVar3); species = GetMonData(&gPlayerParty[sEggHatchData->eggPartyId], MON_DATA_SPECIES); gender = GetMonGender(&gPlayerParty[sEggHatchData->eggPartyId]); personality = GetMonData(&gPlayerParty[sEggHatchData->eggPartyId], MON_DATA_PERSONALITY, 0); diff --git a/src/fonts.c b/src/fonts.c index 72de054b73..92600fcf7e 100644 --- a/src/fonts.c +++ b/src/fonts.c @@ -180,6 +180,114 @@ ALIGNED(4) const u8 gFontNormalLatinGlyphWidths[] = { 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, }; +ALIGNED(4) const u16 gFontNarrowerLatinGlyphs[] = INCBIN_U16("graphics/fonts/narrower.latfont"); +ALIGNED(4) const u8 gFontNarrowerLatinGlyphWidths[] = { + 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, + 8, 4, 4, 4, 5, 5, 4, 4, 3, 4, 4, 4, 4, 4, 4, 3, + 4, 4, 4, 4, 4, 6, 4, 4, 4, 5, 4, 5, 8, 6, 6, 3, + 3, 3, 3, 3, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 5, 4, 8, 8, 8, 7, 8, 8, 4, 4, 6, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, + 3, 3, 3, 3, 3, 3, 3, 5, 3, 7, 7, 7, 7, 0, 0, 3, + 4, 5, 6, 7, 4, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 3, 5, 3, + 5, 5, 5, 3, 3, 5, 5, 6, 3, 6, 6, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 4, 4, 4, 4, 4, + 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, 4, + 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8, + 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 10, 10, 10, 10, 8, 8, 10, 8, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, +}; + +ALIGNED(4) const u16 gFontSmallNarrowerLatinGlyphs[] = INCBIN_U16("graphics/fonts/small_narrower.latfont"); +ALIGNED(4) const u8 gFontSmallNarrowerLatinGlyphWidths[] = { + 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 4, + 5, 4, 4, 4, 5, 4, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, + 4, 4, 4, 4, 4, 6, 4, 4, 4, 5, 4, 4, 7, 5, 6, 3, + 3, 3, 3, 3, 8, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 4, 3, 7, 7, 7, 8, 8, 8, 8, 4, 5, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, + 3, 3, 3, 3, 3, 3, 3, 5, 3, 8, 8, 8, 8, 0, 0, 3, + 4, 5, 6, 7, 4, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 3, 4, 4, + 5, 5, 5, 3, 3, 5, 5, 5, 4, 5, 5, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 3, 4, + 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, + 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 7, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, +}; + +ALIGNED(4) const u16 gFontShortNarrowLatinGlyphs[] = INCBIN_U16("graphics/fonts/short_narrow.latfont"); +ALIGNED(4) const u8 gFontShortNarrowLatinGlyphWidths[] = { + 3, 5, 5, 5, 5, 5, 5, 5, 5, 4, 3, 4, 4, 5, 5, 5, + 8, 5, 5, 5, 5, 6, 5, 5, 3, 5, 5, 5, 5, 5, 4, 3, + 4, 4, 5, 5, 5, 8, 5, 5, 5, 5, 6, 6, 9, 6, 6, 3, + 3, 3, 3, 3, 10, 8, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 6, 6, 6, 8, 8, 8, 8, 8, 8, 4, 6, 8, 5, 5, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 3, 6, + 3, 3, 3, 3, 3, 3, 3, 6, 3, 12, 12, 12, 12, 0, 0, 3, + 4, 5, 6, 7, 8, 8, 8, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, + 6, 6, 6, 3, 3, 6, 6, 8, 5, 9, 6, 5, 5, 5, 5, 5, + 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, + 5, 5, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, + 4, 6, 5, 5, 5, 5, 5, 5, 4, 5, 5, 6, 4, 5, 5, 8, + 5, 5, 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 12, 12, 12, 12, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, +}; + ALIGNED(4) const u16 gFontSmallJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/small.hwjpnfont"); ALIGNED(4) const u16 gFontNormalJapaneseGlyphs[] = INCBIN_U16("graphics/fonts/normal.hwjpnfont"); diff --git a/src/frontier_util.c b/src/frontier_util.c index 7f9b37b957..ca8c76a0fd 100644 --- a/src/frontier_util.c +++ b/src/frontier_util.c @@ -623,20 +623,6 @@ static const u8 sFrontierBrainObjEventGfx[NUM_FRONTIER_FACILITIES][2] = [FRONTIER_FACILITY_PYRAMID] = {OBJ_EVENT_GFX_BRANDON, FALSE}, }; -const u16 gFrontierBannedSpecies[] = -{ - SPECIES_MEW, SPECIES_MEWTWO, - SPECIES_HO_OH, SPECIES_LUGIA, SPECIES_CELEBI, - SPECIES_KYOGRE, SPECIES_GROUDON, SPECIES_RAYQUAZA, SPECIES_JIRACHI, SPECIES_DEOXYS, - SPECIES_DIALGA, SPECIES_PALKIA, SPECIES_GIRATINA, SPECIES_MANAPHY, SPECIES_PHIONE, SPECIES_DARKRAI, SPECIES_SHAYMIN, SPECIES_ARCEUS, - SPECIES_VICTINI, SPECIES_RESHIRAM, SPECIES_ZEKROM, SPECIES_KYUREM, SPECIES_KELDEO, SPECIES_MELOETTA, SPECIES_GENESECT, - SPECIES_XERNEAS, SPECIES_YVELTAL, SPECIES_ZYGARDE, SPECIES_DIANCIE, SPECIES_HOOPA, SPECIES_VOLCANION, - SPECIES_COSMOG, SPECIES_COSMOEM, SPECIES_SOLGALEO, SPECIES_LUNALA, SPECIES_NECROZMA, SPECIES_MAGEARNA, SPECIES_MARSHADOW, SPECIES_ZERAORA, SPECIES_MELTAN, SPECIES_MELMETAL, - SPECIES_ZACIAN, SPECIES_ZAMAZENTA, SPECIES_ETERNATUS, SPECIES_CALYREX, SPECIES_ZARUDE, - SPECIES_KORAIDON, SPECIES_MIRAIDON, - 0xFFFF -}; - static const u8 *const sRecordsWindowChallengeTexts[][2] = { [RANKING_HALL_TOWER_SINGLES] = {gText_BattleTower2, gText_FacilitySingle}, @@ -1899,26 +1885,20 @@ static void CheckBattleTypeFlag(void) #define SPECIES_PER_LINE 3 -static u8 AppendCaughtBannedMonSpeciesName(u16 species, u8 count, s32 numBannedMonsCaught) +static void AppendCaughtBannedMonSpeciesName(u16 species, u8 count, s32 numBannedMonsCaught) { - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) + if (numBannedMonsCaught == count) + StringAppend(gStringVar1, gText_SpaceAndSpace); + else if (numBannedMonsCaught > count) + StringAppend(gStringVar1, gText_CommaSpace); + if ((count % SPECIES_PER_LINE) == 0) { - count++; - if (numBannedMonsCaught == count) - StringAppend(gStringVar1, gText_SpaceAndSpace); - else if (numBannedMonsCaught > count) - StringAppend(gStringVar1, gText_CommaSpace); - if ((count % SPECIES_PER_LINE) == 0) - { - if (count == SPECIES_PER_LINE) - StringAppend(gStringVar1, gText_NewLine); - else - StringAppend(gStringVar1, gText_LineBreak); - } - StringAppend(gStringVar1, GetSpeciesName(species)); + if (count == SPECIES_PER_LINE) + StringAppend(gStringVar1, gText_NewLine); + else + StringAppend(gStringVar1, gText_LineBreak); } - - return count; + StringAppend(gStringVar1, GetSpeciesName(species)); } static void AppendIfValid(u16 species, u16 heldItem, u16 hp, u8 lvlMode, u8 monLevel, u16 *speciesArray, u16 *itemsArray, u8 *count) @@ -1927,13 +1907,7 @@ static void AppendIfValid(u16 species, u16 heldItem, u16 hp, u8 lvlMode, u8 monL if (species == SPECIES_EGG || species == SPECIES_NONE) return; - - for (i = 0; gFrontierBannedSpecies[i] != 0xFFFF - && gFrontierBannedSpecies[i] != GET_BASE_SPECIES_ID(species) - && IsSpeciesEnabled(gFrontierBannedSpecies[i]); i++) - ; - - if (gFrontierBannedSpecies[i] != 0xFFFF) + if (gSpeciesInfo[species].isFrontierBanned) return; if (lvlMode == FRONTIER_LVL_50 && monLevel > FRONTIER_MAX_LEVEL_50) return; @@ -2019,28 +1993,41 @@ static void CheckPartyIneligibility(void) if (numEligibleMons < toChoose) { - s32 i; - s32 caughtBannedMons = 0; - s32 species = gFrontierBannedSpecies[0]; - for (i = 0; species != 0xFFFF; i++, species = gFrontierBannedSpecies[i]) + u32 i; + u32 baseSpecies = 0; + u32 totalCaughtBanned = 0; + u32 caughtBanned[100] = {0}; + + for (i = 0; i < NUM_SPECIES; i++) { - if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT)) - caughtBannedMons++; + if (totalCaughtBanned >= ARRAY_COUNT(caughtBanned)) + break; + baseSpecies = GET_BASE_SPECIES_ID(i); + if (baseSpecies == i) + { + if (gSpeciesInfo[baseSpecies].isFrontierBanned) + { + if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(baseSpecies), FLAG_GET_CAUGHT)) + { + caughtBanned[totalCaughtBanned] = baseSpecies; + totalCaughtBanned++; + } + } + } } gStringVar1[0] = EOS; gSpecialVar_0x8004 = TRUE; - count = 0; - for (i = 0; gFrontierBannedSpecies[i] != 0xFFFF; i++) - count = AppendCaughtBannedMonSpeciesName(gFrontierBannedSpecies[i], count, caughtBannedMons); + for (i = 0; i < totalCaughtBanned; i++) + AppendCaughtBannedMonSpeciesName(caughtBanned[i], i+1, totalCaughtBanned); - if (count == 0) + if (totalCaughtBanned == 0) { StringAppend(gStringVar1, gText_Space2); StringAppend(gStringVar1, gText_Are); } else { - if (count % SPECIES_PER_LINE == SPECIES_PER_LINE - 1) + if (totalCaughtBanned % SPECIES_PER_LINE == SPECIES_PER_LINE - 1) StringAppend(gStringVar1, gText_LineBreak); else StringAppend(gStringVar1, gText_Space2); diff --git a/src/hall_of_fame.c b/src/hall_of_fame.c index 80689c264e..1c3b00f2ef 100644 --- a/src/hall_of_fame.c +++ b/src/hall_of_fame.c @@ -1167,11 +1167,15 @@ static void HallOfFame_PrintMonInfo(struct HallofFameMon* currMon, u8 unused1, u } else { - width = GetStringRightAlignXOffset(FONT_NORMAL, text, 0x80); - AddTextPrinterParameterized3(0, FONT_NORMAL, width, 1, sMonInfoTextColors, TEXT_SKIP_DRAW, text); + u32 fontId = GetFontIdToFit(text, FONT_NORMAL, 0, 66); + width = GetStringRightAlignXOffset(fontId, text, 0x80); + AddTextPrinterParameterized3(0, fontId, width, 1, sMonInfoTextColors, TEXT_SKIP_DRAW, text); text[0] = CHAR_SLASH; - stringPtr = StringCopy(text + 1, GetSpeciesName(currMon->species)); + text[1] = EXT_CTRL_CODE_BEGIN; + text[2] = EXT_CTRL_CODE_FONT; + text[3] = fontId; + stringPtr = StringCopy(text + 4, GetSpeciesName(currMon->species)); if (currMon->species != SPECIES_NIDORAN_M && currMon->species != SPECIES_NIDORAN_F) { diff --git a/src/item.c b/src/item.c index c9318ee4a7..4e903b4883 100644 --- a/src/item.c +++ b/src/item.c @@ -81,24 +81,28 @@ void SetBagItemsPointers(void) gBagPockets[BERRIES_POCKET].capacity = BAG_BERRIES_COUNT; } -void CopyItemName(u16 itemId, u8 *dst) +u8 *CopyItemName(u16 itemId, u8 *dst) { - StringCopy(dst, ItemId_GetName(itemId)); + return StringCopy(dst, ItemId_GetName(itemId)); } const u8 sText_s[] =_("s"); -void CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity) +u8 *CopyItemNameHandlePlural(u16 itemId, u8 *dst, u32 quantity) { - u8 *end = StringCopy(dst, ItemId_GetName(itemId)) - 1; - - if (quantity < 2) - return; - - if (DoesItemHavePluralName(itemId)) - StringCopy(dst, ItemId_GetPluralName(itemId)); + if (quantity == 1) + { + return StringCopy(dst, ItemId_GetName(itemId)); + } + else if (DoesItemHavePluralName(itemId)) + { + return StringCopy(dst, ItemId_GetPluralName(itemId)); + } else - StringAppend(end, sText_s); + { + u8 *end = StringCopy(dst, ItemId_GetName(itemId)); + return StringCopy(end, sText_s); + } } bool8 IsBagPocketNonEmpty(u8 pocket) diff --git a/src/item_icon.c b/src/item_icon.c index fd6f041695..45775f6674 100644 --- a/src/item_icon.c +++ b/src/item_icon.c @@ -5,6 +5,8 @@ #include "malloc.h" #include "sprite.h" #include "constants/items.h" +#include "item.h" +#include "battle_main.h" // EWRAM vars EWRAM_DATA u8 *gItemIconDecompressionBuffer = NULL; @@ -163,6 +165,12 @@ const void *GetItemIconPicOrPalette(u16 itemId, u8 which) itemId = ITEMS_COUNT; // Use last icon, the "return to field" arrow else if (itemId >= ITEMS_COUNT) itemId = 0; + else if (itemId >= ITEM_TM01 && itemId <= ITEM_HM08 && which) + return gTypesInfo[gMovesInfo[gItemsInfo[itemId].secondaryId].type].paletteTMHM; + else if (itemId >= ITEM_TM01 && itemId < ITEM_HM01) + return gItemIcon_TM; + else if (itemId >= ITEM_HM01 && itemId <= ITEM_HM08) + return gItemIcon_HM; return gItemIconTable[itemId][which]; } diff --git a/src/item_menu.c b/src/item_menu.c index 569712cfe6..ad9fc6f4bc 100755 --- a/src/item_menu.c +++ b/src/item_menu.c @@ -109,7 +109,7 @@ struct ListBuffer1 { }; struct ListBuffer2 { - u8 name[MAX_POCKET_ITEMS][ITEM_NAME_LENGTH + 10]; + u8 name[MAX_POCKET_ITEMS][max(ITEM_NAME_LENGTH, MOVE_NAME_LENGTH) + 15]; }; struct TempWallyBag { @@ -905,10 +905,12 @@ static void LoadBagItemListBuffers(u8 pocketId) static void GetItemName(u8 *dest, u16 itemId) { + u8 *end; switch (gBagPosition.pocket) { case TMHM_POCKET: - StringCopy(gStringVar2, GetMoveName(ItemIdToBattleMoveId(itemId))); + end = StringCopy(gStringVar2, GetMoveName(ItemIdToBattleMoveId(itemId))); + PrependFontIdToFit(gStringVar2, end, FONT_NARROW, 73); if (itemId >= ITEM_HM01) { // Get HM number @@ -924,11 +926,13 @@ static void GetItemName(u8 *dest, u16 itemId) break; case BERRIES_POCKET: ConvertIntToDecimalStringN(gStringVar1, itemId - FIRST_BERRY_INDEX + 1, STR_CONV_MODE_LEADING_ZEROS, 2); - CopyItemName(itemId, gStringVar2); + end = CopyItemName(itemId, gStringVar2); + PrependFontIdToFit(gStringVar2, end, FONT_NARROW, 73); StringExpandPlaceholders(dest, gText_NumberItem_TMBerry); break; default: - CopyItemName(itemId, dest); + end = CopyItemName(itemId, dest); + PrependFontIdToFit(dest, end, FONT_NARROW, 88); break; } } @@ -1667,7 +1671,8 @@ static void OpenContextMenu(u8 taskId) } else { - CopyItemName(gSpecialVar_ItemId, gStringVar1); + u8 *end = CopyItemName(gSpecialVar_ItemId, gStringVar1); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(WIN_DESCRIPTION) - 10 - 6); StringExpandPlaceholders(gStringVar4, gText_Var1IsSelected); FillWindowPixelBuffer(WIN_DESCRIPTION, PIXEL_FILL(0)); BagMenu_Print(WIN_DESCRIPTION, FONT_NORMAL, gStringVar4, 3, 1, 0, 0, 0, COLORID_NORMAL); @@ -1833,7 +1838,8 @@ static void ItemMenu_Toss(u8 taskId) } else { - CopyItemName(gSpecialVar_ItemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSpecialVar_ItemId, gStringVar1, 2); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(WIN_DESCRIPTION) - 10 - 6); StringExpandPlaceholders(gStringVar4, gText_TossHowManyVar1s); FillWindowPixelBuffer(WIN_DESCRIPTION, PIXEL_FILL(0)); BagMenu_Print(WIN_DESCRIPTION, FONT_NORMAL, gStringVar4, 3, 1, 0, 0, 0, COLORID_NORMAL); @@ -1846,7 +1852,8 @@ static void AskTossItems(u8 taskId) { s16 *data = gTasks[taskId].data; - CopyItemName(gSpecialVar_ItemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSpecialVar_ItemId, gStringVar1, tItemCount); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(WIN_DESCRIPTION) - 10 - 6); ConvertIntToDecimalStringN(gStringVar2, tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_ITEM_DIGITS); StringExpandPlaceholders(gStringVar4, gText_ConfirmTossItems); FillWindowPixelBuffer(WIN_DESCRIPTION, PIXEL_FILL(0)); @@ -1889,7 +1896,8 @@ static void ConfirmToss(u8 taskId) { s16 *data = gTasks[taskId].data; - CopyItemName(gSpecialVar_ItemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSpecialVar_ItemId, gStringVar1, tItemCount); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(WIN_DESCRIPTION) - 10 - 6); ConvertIntToDecimalStringN(gStringVar2, tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_ITEM_DIGITS); StringExpandPlaceholders(gStringVar4, gText_ThrewAwayVar2Var1s); FillWindowPixelBuffer(WIN_DESCRIPTION, PIXEL_FILL(0)); @@ -2226,7 +2234,8 @@ static void Task_ItemContext_Deposit(u8 taskId) } else { - CopyItemName(gSpecialVar_ItemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSpecialVar_ItemId, gStringVar1, 2); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(WIN_DESCRIPTION) - 10 - 6); StringExpandPlaceholders(gStringVar4, gText_DepositHowManyVar1); FillWindowPixelBuffer(WIN_DESCRIPTION, PIXEL_FILL(0)); BagMenu_Print(WIN_DESCRIPTION, FONT_NORMAL, gStringVar4, 3, 1, 0, 0, 0, COLORID_NORMAL); @@ -2273,7 +2282,8 @@ static void TryDepositItem(u8 taskId) else if (AddPCItem(gSpecialVar_ItemId, tItemCount) == TRUE) { // Successfully deposited - CopyItemName(gSpecialVar_ItemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSpecialVar_ItemId, gStringVar1, tItemCount); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(WIN_DESCRIPTION) - 10 - 6); ConvertIntToDecimalStringN(gStringVar2, tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_ITEM_DIGITS); StringExpandPlaceholders(gStringVar4, gText_DepositedVar2Var1s); BagMenu_Print(WIN_DESCRIPTION, FONT_NORMAL, gStringVar4, 3, 1, 0, 0, 0, COLORID_NORMAL); diff --git a/src/list_menu.c b/src/list_menu.c index e83f325161..aa65683edd 100644 --- a/src/list_menu.c +++ b/src/list_menu.c @@ -600,11 +600,14 @@ static void ListMenuPrint(struct ListMenu *list, const u8 *str, u8 x, u8 y) u8 colors[3]; if (gListMenuOverride.enabled) { + u32 fontId = gListMenuOverride.fontId; + if (list->template.textNarrowWidth) + fontId = GetFontIdToFit(str, fontId, gListMenuOverride.lettersSpacing, list->template.textNarrowWidth); colors[0] = gListMenuOverride.fillValue; colors[1] = gListMenuOverride.cursorPal; colors[2] = gListMenuOverride.cursorShadowPal; AddTextPrinterParameterized4(list->template.windowId, - gListMenuOverride.fontId, + fontId, x, y, gListMenuOverride.lettersSpacing, 0, colors, TEXT_SKIP_DRAW, str); @@ -613,11 +616,14 @@ static void ListMenuPrint(struct ListMenu *list, const u8 *str, u8 x, u8 y) } else { + u32 fontId = list->template.fontId; + if (list->template.textNarrowWidth) + fontId = GetFontIdToFit(str, fontId, list->template.lettersSpacing, list->template.textNarrowWidth); colors[0] = list->template.fillValue; colors[1] = list->template.cursorPal; colors[2] = list->template.cursorShadowPal; AddTextPrinterParameterized4(list->template.windowId, - list->template.fontId, + fontId, x, y, list->template.lettersSpacing, 0, colors, TEXT_SKIP_DRAW, str); diff --git a/src/menu_specialized.c b/src/menu_specialized.c index fcb65d9ae7..a80a227a4b 100644 --- a/src/menu_specialized.c +++ b/src/menu_specialized.c @@ -186,7 +186,8 @@ static const struct ListMenuTemplate sMoveRelearnerMovesListTemplate = .itemVerticalPadding = 0, .scrollMultiple = LIST_NO_MULTIPLE_SCROLL, .fontId = FONT_NORMAL, - .cursorKind = CURSOR_BLACK_ARROW + .cursorKind = CURSOR_BLACK_ARROW, + .textNarrowWidth = 68, }; //-------------- diff --git a/src/naming_screen.c b/src/naming_screen.c index 91d490dd0d..c4f3bd0418 100644 --- a/src/naming_screen.c +++ b/src/naming_screen.c @@ -1710,10 +1710,11 @@ static void DrawNormalTextEntryBox(void) static void DrawMonTextEntryBox(void) { - u8 buffer[32]; + u8 buffer[64]; - StringCopy(buffer, GetSpeciesName(sNamingScreen->monSpecies)); - StringAppendN(buffer, sNamingScreen->template->title, 15); + u8 *end = StringCopy(buffer, GetSpeciesName(sNamingScreen->monSpecies)); + WrapFontIdToFit(buffer, end, FONT_NORMAL, 128 - 64); + StringAppendN(end, sNamingScreen->template->title, 15); FillWindowPixelBuffer(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX], PIXEL_FILL(1)); AddTextPrinterParameterized(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX], FONT_NORMAL, buffer, 8, 1, 0, 0); PutWindowTilemap(sNamingScreen->windows[WIN_TEXT_ENTRY_BOX]); diff --git a/src/party_menu.c b/src/party_menu.c index 69e78b08fe..adb1caa45f 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -2436,6 +2436,11 @@ static void DisplayPartyPokemonBarDetail(u8 windowId, const u8 *str, u8 color, c AddTextPrinterParameterized3(windowId, FONT_SMALL, align[0], align[1], sFontColorTable[color], 0, str); } +static void DisplayPartyPokemonBarDetailToFit(u8 windowId, const u8 *str, u8 color, const u8 *align, u32 width) +{ + AddTextPrinterParameterized3(windowId, GetFontIdToFit(str, FONT_SMALL, 0, width), align[0], align[1], sFontColorTable[color], 0, str); +} + static void DisplayPartyPokemonNickname(struct Pokemon *mon, struct PartyMenuBox *menuBox, u8 c) { u8 nickname[POKEMON_NAME_LENGTH + 1]; @@ -2445,7 +2450,7 @@ static void DisplayPartyPokemonNickname(struct Pokemon *mon, struct PartyMenuBox if (c == 1) menuBox->infoRects->blitFunc(menuBox->windowId, menuBox->infoRects->dimensions[0] >> 3, menuBox->infoRects->dimensions[1] >> 3, menuBox->infoRects->dimensions[2] >> 3, menuBox->infoRects->dimensions[3] >> 3, FALSE); GetMonNickname(mon, nickname); - DisplayPartyPokemonBarDetail(menuBox->windowId, nickname, 0, menuBox->infoRects->dimensions); + DisplayPartyPokemonBarDetailToFit(menuBox->windowId, nickname, 0, menuBox->infoRects->dimensions, 50); } } @@ -4603,7 +4608,8 @@ void ItemUseCB_BattleScript(u8 taskId, TaskFunc task) gBattleStruct->itemPartyIndex[gBattlerInMenuId] = GetPartyIdFromBattleSlot(gPartyMenu.slotId); gPartyMenuUseExitCallback = TRUE; PlaySE(SE_SELECT); - RemoveBagItem(gSpecialVar_ItemId, 1); + if (!IsItemFlute(gSpecialVar_ItemId)) + RemoveBagItem(gSpecialVar_ItemId, 1); ScheduleBgCopyTilemapToVram(2); gTasks[taskId].func = task; } @@ -6929,8 +6935,7 @@ static u8 GetPartySlotEntryStatus(s8 slot) static bool8 GetBattleEntryEligibility(struct Pokemon *mon) { - u16 i = 0; - u16 species; + u32 species; if (GetMonData(mon, MON_DATA_IS_EGG) || GetMonData(mon, MON_DATA_LEVEL) > GetBattleEntryLevelCap() @@ -6951,11 +6956,8 @@ static bool8 GetBattleEntryEligibility(struct Pokemon *mon) return TRUE; default: // Battle Frontier species = GetMonData(mon, MON_DATA_SPECIES); - for (; gFrontierBannedSpecies[i] != 0xFFFF; i++) - { - if (gFrontierBannedSpecies[i] == GET_BASE_SPECIES_ID(species)) - return FALSE; - } + if (gSpeciesInfo[species].isFrontierBanned) + return FALSE; return TRUE; } } diff --git a/src/player_pc.c b/src/player_pc.c index a10cb2ac2b..3dd5fcc36f 100644 --- a/src/player_pc.c +++ b/src/player_pc.c @@ -293,6 +293,7 @@ static const struct ListMenuTemplate sListMenuTemplate_ItemStorage = .scrollMultiple = LIST_NO_MULTIPLE_SCROLL, .fontId = FONT_NARROW, .cursorKind = CURSOR_BLACK_ARROW, + .textNarrowWidth = 74, }; static const struct WindowTemplate sWindowTemplates_ItemStorage[ITEMPC_WIN_COUNT] = @@ -1349,6 +1350,7 @@ static void ItemStorage_PrintItemQuantity(u8 windowId, u16 value, u32 mode, u8 x // Start an item Withdraw/Toss static void ItemStorage_DoItemAction(u8 taskId) { + u8 *end; s16 *data = gTasks[taskId].data; u16 pos = gPlayerPCItemPageInfo.cursorPos + gPlayerPCItemPageInfo.itemsAbove; ItemStorage_RemoveScrollIndicator(); @@ -1364,7 +1366,8 @@ static void ItemStorage_DoItemAction(u8 taskId) } // Withdrawing multiple items, show "how many" message - CopyItemName(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1); + end = CopyItemNameHandlePlural(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1, 2); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(ITEMPC_WIN_MESSAGE) - 6); ItemStorage_PrintMessage(ItemStorage_GetMessage(MSG_HOW_MANY_TO_WITHDRAW)); } else @@ -1377,7 +1380,8 @@ static void ItemStorage_DoItemAction(u8 taskId) } // Tossing multiple items, show "how many" message - CopyItemName(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1); + end = CopyItemNameHandlePlural(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1, 2); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(ITEMPC_WIN_MESSAGE) - 6); ItemStorage_PrintMessage(ItemStorage_GetMessage(MSG_HOW_MANY_TO_TOSS)); } @@ -1426,7 +1430,8 @@ static void ItemStorage_DoItemWithdraw(u8 taskId) if (AddBagItem(gSaveBlock1Ptr->pcItems[pos].itemId, tQuantity) == TRUE) { // Item withdrawn - CopyItemName(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1, tQuantity); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(ITEMPC_WIN_MESSAGE) - 6); ConvertIntToDecimalStringN(gStringVar2, tQuantity, STR_CONV_MODE_LEFT_ALIGN, 3); ItemStorage_PrintMessage(ItemStorage_GetMessage(MSG_WITHDREW_ITEM)); gTasks[taskId].func = ItemStorage_HandleRemoveItem; @@ -1448,7 +1453,8 @@ static void ItemStorage_DoItemToss(u8 taskId) if (!ItemId_GetImportance(gSaveBlock1Ptr->pcItems[pos].itemId)) { // Show toss confirmation prompt - CopyItemName(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1); + u8 *end = CopyItemNameHandlePlural(gSaveBlock1Ptr->pcItems[pos].itemId, gStringVar1, tQuantity); + WrapFontIdToFit(gStringVar1, end, FONT_NORMAL, WindowWidthPx(ITEMPC_WIN_MESSAGE) - 6); ConvertIntToDecimalStringN(gStringVar2, tQuantity, STR_CONV_MODE_LEFT_ALIGN, 3); ItemStorage_PrintMessage(ItemStorage_GetMessage(MSG_OKAY_TO_THROW_AWAY)); CreateYesNoMenuWithCallbacks(taskId, &sWindowTemplates_ItemStorage[ITEMPC_WIN_YESNO], 1, 0, 1, 0x214, 0xE, &ItemTossYesNoFuncs); diff --git a/src/pokedex.c b/src/pokedex.c index 02738980dd..7c39b2502c 100644 --- a/src/pokedex.c +++ b/src/pokedex.c @@ -2337,13 +2337,16 @@ static void CreatePokedexList(u8 dexMode, u8 order) } } -static void PrintMonDexNumAndName(u8 windowId, u8 fontId, const u8 *str, u8 left, u8 top) +static void PrintMonDexNum(u8 windowId, u8 fontId, const u8 *str, u8 left, u8 top) { - u8 color[3]; + static const u8 color[3] = { TEXT_COLOR_TRANSPARENT, TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_LIGHT_GRAY }; + AddTextPrinterParameterized4(windowId, fontId, left * 8, (top * 8) + 1, 0, 0, color, TEXT_SKIP_DRAW, str); +} - color[0] = TEXT_COLOR_TRANSPARENT; - color[1] = TEXT_DYNAMIC_COLOR_6; - color[2] = TEXT_COLOR_LIGHT_GRAY; +static void PrintMonName(u8 windowId, u8 fontId, const u8 *str, u8 left, u8 top) +{ + static const u8 color[3] = { TEXT_COLOR_TRANSPARENT, TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_LIGHT_GRAY }; + fontId = GetFontIdToFit(str, fontId, 0, 50); AddTextPrinterParameterized4(windowId, fontId, left * 8, (top * 8) + 1, 0, 0, color, TEXT_SKIP_DRAW, str); } @@ -2453,7 +2456,7 @@ static void CreateMonDexNum(u16 entryNum, u8 left, u8 top, u16 unused) text[offset++] = CHAR_0 + ((dexNum % 1000) % 100) / 10; text[offset++] = CHAR_0 + ((dexNum % 1000) % 100) % 10; text[offset++] = EOS; - PrintMonDexNumAndName(0, FONT_NARROW, text, left, top); + PrintMonDexNum(0, FONT_NARROW, text, left, top); } static void CreateCaughtBall(bool16 owned, u8 x, u8 y, u16 unused) @@ -2473,7 +2476,7 @@ static u8 CreateMonName(u16 num, u8 left, u8 top) str = GetSpeciesName(num); else str = sText_TenDashes; - PrintMonDexNumAndName(0, FONT_NARROW, str, left, top); + PrintMonName(0, FONT_NARROW, str, left, top); return StringLength(str); } @@ -4671,7 +4674,7 @@ static void UNUSED UnusedPrintNum(u8 windowId, u16 num, u8 left, u8 top) static u8 PrintCryScreenSpeciesName(u8 windowId, u16 num, u8 left, u8 top) { - u8 str[POKEMON_NAME_LENGTH + 1]; + u8 str[POKEMON_NAME_BUFFER_SIZE]; u8 i; for (i = 0; i < ARRAY_COUNT(str); i++) @@ -4682,6 +4685,7 @@ static u8 PrintCryScreenSpeciesName(u8 windowId, u16 num, u8 left, u8 top) default: for (i = 0; GetSpeciesName(num)[i] != EOS && i < POKEMON_NAME_LENGTH; i++) str[i] = GetSpeciesName(num)[i]; + WrapFontIdToFit(str, str + i, FONT_NORMAL, 60); break; case 0: for (i = 0; i < 5; i++) @@ -5004,13 +5008,16 @@ static u8 LoadSearchMenu(void) return CreateTask(Task_LoadSearchMenu, 0); } +static void PrintSearchTextToFit(const u8 *str, u32 x, u32 y, u32 width) +{ + static const u8 color[3] = { TEXT_COLOR_TRANSPARENT, TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_DARK_GRAY }; + u32 fontId = GetFontIdToFit(str, FONT_NORMAL, 0, width); + AddTextPrinterParameterized4(0, fontId, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); +} + static void PrintSearchText(const u8 *str, u32 x, u32 y) { - u8 color[3]; - - color[0] = TEXT_COLOR_TRANSPARENT; - color[1] = TEXT_DYNAMIC_COLOR_6; - color[2] = TEXT_COLOR_DARK_GRAY; + static const u8 color[3] = { TEXT_COLOR_TRANSPARENT, TEXT_DYNAMIC_COLOR_6, TEXT_COLOR_DARK_GRAY }; AddTextPrinterParameterized4(0, FONT_NORMAL, x, y, 0, 0, color, TEXT_SKIP_DRAW, str); } @@ -5630,10 +5637,10 @@ static void PrintSelectedSearchParameters(u8 taskId) PrintSearchText(sDexSearchColorOptions[searchParamId].title, 0x2D, 0x21); searchParamId = gTasks[taskId].tCursorPos_TypeLeft + gTasks[taskId].tScrollOffset_TypeLeft; - PrintSearchText(sDexSearchTypeOptions[searchParamId].title, 0x2D, 0x31); + PrintSearchTextToFit(sDexSearchTypeOptions[searchParamId].title, 0x2D, 0x31, 38); searchParamId = gTasks[taskId].tCursorPos_TypeRight + gTasks[taskId].tScrollOffset_TypeRight; - PrintSearchText(sDexSearchTypeOptions[searchParamId].title, 0x5D, 0x31); + PrintSearchTextToFit(sDexSearchTypeOptions[searchParamId].title, 0x5D, 0x31, 38); searchParamId = gTasks[taskId].tCursorPos_Order + gTasks[taskId].tScrollOffset_Order; PrintSearchText(sDexOrderOptions[searchParamId].title, 0x2D, 0x41); diff --git a/src/pokedex_plus_hgss.c b/src/pokedex_plus_hgss.c index 78b97303a4..45b7800564 100644 --- a/src/pokedex_plus_hgss.c +++ b/src/pokedex_plus_hgss.c @@ -386,7 +386,7 @@ struct PokemonStats u8 eggGroup1; u8 eggGroup2; u8 eggCycles; - u8 expYield; + u16 expYield; u8 friendship; u16 ability0; u16 ability1; diff --git a/src/pokemon.c b/src/pokemon.c index 68d5a42437..d0c5555a99 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -1351,7 +1351,7 @@ void ConvertPokemonToBattleTowerPokemon(struct Pokemon *mon, struct BattleTowerP dest->spDefenseIV = GetMonData(mon, MON_DATA_SPDEF_IV, NULL); dest->abilityNum = GetMonData(mon, MON_DATA_ABILITY_NUM, NULL); dest->personality = GetMonData(mon, MON_DATA_PERSONALITY, NULL); - GetMonData(mon, MON_DATA_NICKNAME, dest->nickname); + GetMonData(mon, MON_DATA_NICKNAME10, dest->nickname); } static void CreateEventMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId) @@ -1681,35 +1681,12 @@ void GiveMonInitialMoveset(struct Pokemon *mon) GiveBoxMonInitialMoveset(&mon->box); } -void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon) +void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon) //Credit: AsparagusEduardo { u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); s32 level = GetLevelFromBoxMonExp(boxMon); s32 i; - const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); - - for (i = 0; learnset[i].move != LEVEL_UP_MOVE_END; i++) - { - if (learnset[i].level > level) - break; - if (learnset[i].level == 0) - continue; - if (GiveMoveToBoxMon(boxMon, learnset[i].move) == MON_HAS_MAX_MOVES) - DeleteFirstMoveAndGiveMoveToBoxMon(boxMon, learnset[i].move); - } -} - -void GiveMonInitialMoveset_Fast(struct Pokemon *mon) -{ - GiveBoxMonInitialMoveset_Fast(&mon->box); -} - -void GiveBoxMonInitialMoveset_Fast(struct BoxPokemon *boxMon) //Credit: AsparagusEduardo -{ - u16 species = GetBoxMonData(boxMon, MON_DATA_SPECIES, NULL); - s32 level = GetLevelFromBoxMonExp(boxMon); - s32 i; - u16 moves[MAX_MON_MOVES] = {0}; + u16 moves[MAX_MON_MOVES] = {MOVE_NONE}; u8 addedMoves = 0; const struct LevelUpMove *learnset = GetSpeciesLevelUpLearnset(species); @@ -1723,13 +1700,15 @@ void GiveBoxMonInitialMoveset_Fast(struct BoxPokemon *boxMon) //Credit: Asparagu if (learnset[i].level == 0) continue; - for (j = 0; j < addedMoves + 1; j++) + for (j = 0; j < addedMoves; j++) + { if (moves[j] == learnset[i].move) { alreadyKnown = TRUE; break; } - + } + if (!alreadyKnown) { if (addedMoves < MAX_MON_MOVES) @@ -2193,6 +2172,7 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) switch (field) { case MON_DATA_NICKNAME: + case MON_DATA_NICKNAME10: { if (boxMon->isBadEgg) { @@ -2235,7 +2215,7 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data) // so if both are 0 we assume that this is a vanilla // Pokémon and replace them with EOS. This means that // two CHAR_SPACE at the end of a nickname are trimmed. - if (POKEMON_NAME_LENGTH >= 12) + if (field != MON_DATA_NICKNAME10 && POKEMON_NAME_LENGTH >= 12) { if (substruct0->nickname11 == 0 && substruct0->nickname12 == 0) { @@ -2730,14 +2710,23 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) switch (field) { case MON_DATA_NICKNAME: + case MON_DATA_NICKNAME10: { s32 i; for (i = 0; i < min(sizeof(boxMon->nickname), POKEMON_NAME_LENGTH); i++) boxMon->nickname[i] = data[i]; - if (POKEMON_NAME_LENGTH >= 11) - substruct0->nickname11 = data[10]; - if (POKEMON_NAME_LENGTH >= 12) - substruct0->nickname12 = data[11]; + if (field != MON_DATA_NICKNAME10) + { + if (POKEMON_NAME_LENGTH >= 11) + substruct0->nickname11 = data[10]; + if (POKEMON_NAME_LENGTH >= 12) + substruct0->nickname12 = data[11]; + } + else + { + substruct0->nickname11 = EOS; + substruct0->nickname12 = EOS; + } break; } case MON_DATA_SPECIES: @@ -3548,8 +3537,17 @@ bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 mov { u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); dataUnsigned = sExpCandyExperienceTable[param - 1] + GetMonData(mon, MON_DATA_EXP, NULL); - if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL]) + + if (B_RARE_CANDY_CAP && EXP_CAP_HARD) + { + u32 currentLevelCap = GetCurrentLevelCap(); + if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][currentLevelCap]) + dataUnsigned = gExperienceTables[gSpeciesInfo[species].growthRate][currentLevelCap]; + } + else if (dataUnsigned > gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL]) + { dataUnsigned = gExperienceTables[gSpeciesInfo[species].growthRate][MAX_LEVEL]; + } } if (dataUnsigned != 0) // Failsafe diff --git a/src/pokemon_storage_system.c b/src/pokemon_storage_system.c index 013f7e21b4..111d153d2f 100644 --- a/src/pokemon_storage_system.c +++ b/src/pokemon_storage_system.c @@ -4028,16 +4028,16 @@ static void PrintDisplayMonInfo(void) FillWindowPixelBuffer(WIN_DISPLAY_INFO, PIXEL_FILL(1)); if (sStorage->boxOption != OPTION_MOVE_ITEMS) { - AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_NORMAL, sStorage->displayMonNameText, 6, 0, TEXT_SKIP_DRAW, NULL); - AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_SHORT, sStorage->displayMonSpeciesName, 6, 15, TEXT_SKIP_DRAW, NULL); + AddTextPrinterParameterized(WIN_DISPLAY_INFO, GetFontIdToFit(sStorage->displayMonNameText, FONT_NORMAL, 0, WindowWidthPx(WIN_DISPLAY_INFO) - 6), sStorage->displayMonNameText, 6, 0, TEXT_SKIP_DRAW, NULL); + AddTextPrinterParameterized(WIN_DISPLAY_INFO, GetFontIdToFit(sStorage->displayMonNameText, FONT_SHORT, 0, WindowWidthPx(WIN_DISPLAY_INFO) - 12), sStorage->displayMonSpeciesName, 6, 15, TEXT_SKIP_DRAW, NULL); AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_SHORT, sStorage->displayMonGenderLvlText, 10, 29, TEXT_SKIP_DRAW, NULL); - AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_SMALL, sStorage->displayMonItemName, 6, 43, TEXT_SKIP_DRAW, NULL); + AddTextPrinterParameterized(WIN_DISPLAY_INFO, GetFontIdToFit(sStorage->displayMonItemName, FONT_SMALL, 0, WindowWidthPx(WIN_DISPLAY_INFO) - 22), sStorage->displayMonItemName, 6, 43, TEXT_SKIP_DRAW, NULL); } else { - AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_SMALL, sStorage->displayMonItemName, 6, 0, TEXT_SKIP_DRAW, NULL); - AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_NORMAL, sStorage->displayMonNameText, 6, 13, TEXT_SKIP_DRAW, NULL); - AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_SHORT, sStorage->displayMonSpeciesName, 6, 28, TEXT_SKIP_DRAW, NULL); + AddTextPrinterParameterized(WIN_DISPLAY_INFO, GetFontIdToFit(sStorage->displayMonItemName, FONT_SMALL, 0, WindowWidthPx(WIN_DISPLAY_INFO) - 22), sStorage->displayMonItemName, 6, 0, TEXT_SKIP_DRAW, NULL); + AddTextPrinterParameterized(WIN_DISPLAY_INFO, GetFontIdToFit(sStorage->displayMonNameText, FONT_NORMAL, 0, WindowWidthPx(WIN_DISPLAY_INFO) - 6), sStorage->displayMonNameText, 6, 13, TEXT_SKIP_DRAW, NULL); + AddTextPrinterParameterized(WIN_DISPLAY_INFO, GetFontIdToFit(sStorage->displayMonSpeciesName, FONT_SHORT, 0, WindowWidthPx(WIN_DISPLAY_INFO) - 12), sStorage->displayMonSpeciesName, 6, 28, TEXT_SKIP_DRAW, NULL); AddTextPrinterParameterized(WIN_DISPLAY_INFO, FONT_SHORT, sStorage->displayMonGenderLvlText, 10, 42, TEXT_SKIP_DRAW, NULL); } diff --git a/src/pokemon_summary_screen.c b/src/pokemon_summary_screen.c index f5c2e7f6b7..f13e57ed8e 100644 --- a/src/pokemon_summary_screen.c +++ b/src/pokemon_summary_screen.c @@ -891,6 +891,10 @@ static const union AnimCmd sSpriteAnim_TypeFairy[] = { ANIMCMD_FRAME(TYPE_FAIRY * 8, 0, FALSE, FALSE), ANIMCMD_END }; +static const union AnimCmd sSpriteAnim_TypeStellar[] = { + ANIMCMD_FRAME(TYPE_STELLAR * 8, 0, FALSE, FALSE), + ANIMCMD_END +}; static const union AnimCmd sSpriteAnim_CategoryCool[] = { ANIMCMD_FRAME((CONTEST_CATEGORY_COOL + NUMBER_OF_MON_TYPES) * 8, 0, FALSE, FALSE), ANIMCMD_END @@ -931,6 +935,7 @@ static const union AnimCmd *const sSpriteAnimTable_MoveTypes[NUMBER_OF_MON_TYPES sSpriteAnim_TypeDragon, sSpriteAnim_TypeDark, sSpriteAnim_TypeFairy, + sSpriteAnim_TypeStellar, sSpriteAnim_CategoryCool, sSpriteAnim_CategoryBeauty, sSpriteAnim_CategoryCute, @@ -2795,12 +2800,28 @@ static void ResetWindows(void) sMonSummaryScreen->windowIds[i] = WINDOW_NONE; } -static void PrintTextOnWindow(u8 windowId, const u8 *string, u8 x, u8 y, u8 lineSpacing, u8 colorId) +static void PrintTextOnWindowWithFont(u8 windowId, const u8 *string, u8 x, u8 y, u8 lineSpacing, u8 colorId, u32 fontId) { if (DECAP_ENABLED && DECAP_MIRRORING && !DECAP_SUMMARY) - AddTextPrinterParameterized4(windowId, FONT_NORMAL, x, y, 0, lineSpacing, sTextColors[colorId], 0, MirrorPtr(string)); + AddTextPrinterParameterized4(windowId, fontId, x, y, 0, lineSpacing, sTextColors[colorId], 0, MirrorPtr(string)); else - AddTextPrinterParameterized4(windowId, FONT_NORMAL, x, y, 0, lineSpacing, sTextColors[colorId], 0, string); + AddTextPrinterParameterized4(windowId, fontId, x, y, 0, lineSpacing, sTextColors[colorId], 0, string); +} + +static void PrintTextOnWindow(u8 windowId, const u8 *string, u8 x, u8 y, u8 lineSpacing, u8 colorId) +{ + PrintTextOnWindowWithFont(windowId, string, x, y, lineSpacing, colorId, FONT_NORMAL); +} + +static void PrintTextOnWindowToFitPx(u8 windowId, const u8 *string, u8 x, u8 y, u8 lineSpacing, u8 colorId, u32 width) +{ + u32 fontId = GetFontIdToFit(string, FONT_NORMAL, 0, width); + PrintTextOnWindowWithFont(windowId, string, x, y, lineSpacing, colorId, fontId); +} + +static void PrintTextOnWindowToFit(u8 windowId, const u8 *string, u8 x, u8 y, u8 lineSpacing, u8 colorId) +{ + PrintTextOnWindowToFitPx(windowId, string, x, y, lineSpacing, colorId, WindowWidthPx(windowId)); } static void PrintMonInfo(void) @@ -2817,7 +2838,6 @@ static void PrintMonInfo(void) static void PrintNotEggInfo(void) { - u8 strArray[16]; struct Pokemon *mon = &sMonSummaryScreen->currentMon; struct PokeSummary *summary = &sMonSummaryScreen->summary; u16 dexNum = SpeciesToPokedexNum(summary->species); @@ -2853,10 +2873,9 @@ static void PrintNotEggInfo(void) StringAppend(gStringVar1, gStringVar2); PrintTextOnWindow(PSS_LABEL_WINDOW_PORTRAIT_SPECIES, gStringVar1, 24, 17, 0, 1); GetMonNickname(mon, gStringVar1); - PrintTextOnWindow(PSS_LABEL_WINDOW_PORTRAIT_NICKNAME, gStringVar1, 0, 1, 0, 1); - strArray[0] = CHAR_SLASH; - StringCopy(&strArray[1], &GetSpeciesName(summary->species2)[0]); - PrintTextOnWindow(PSS_LABEL_WINDOW_PORTRAIT_SPECIES, strArray, 0, 1, 0, 1); + PrintTextOnWindowToFitPx(PSS_LABEL_WINDOW_PORTRAIT_NICKNAME, gStringVar1, 0, 1, 0, 1, WindowWidthPx(PSS_LABEL_WINDOW_PORTRAIT_NICKNAME) - 9); + PrintTextOnWindow(PSS_LABEL_WINDOW_PORTRAIT_SPECIES, gText_Slash, 0, 1, 0, 1); + PrintTextOnWindowToFitPx(PSS_LABEL_WINDOW_PORTRAIT_SPECIES, GetSpeciesName(summary->species2), 6, 1, 0, 1, WindowWidthPx(PSS_LABEL_WINDOW_PORTRAIT_SPECIES) - 9); PrintGenderSymbol(mon, summary->species2); PutWindowTilemap(PSS_LABEL_WINDOW_PORTRAIT_NICKNAME); PutWindowTilemap(PSS_LABEL_WINDOW_PORTRAIT_SPECIES); @@ -3418,6 +3437,7 @@ static void Task_PrintSkillsPage(u8 taskId) static void PrintHeldItemName(void) { const u8 *text; + u32 fontId; int x; if (sMonSummaryScreen->summary.item == ITEM_ENIGMA_BERRY_E_READER @@ -3436,8 +3456,9 @@ static void PrintHeldItemName(void) text = gStringVar1; } - x = GetStringCenterAlignXOffset(FONT_NORMAL, text, 72) + 6; - PrintTextOnWindow(AddWindowFromTemplateList(sPageSkillsTemplate, PSS_DATA_WINDOW_SKILLS_HELD_ITEM), text, x, 1, 0, 0); + fontId = GetFontIdToFit(text, FONT_NORMAL, 0, WindowTemplateWidthPx(&sPageSkillsTemplate[PSS_DATA_WINDOW_SKILLS_HELD_ITEM]) - 8); + x = GetStringCenterAlignXOffset(fontId, text, 72) + 6; + PrintTextOnWindowWithFont(AddWindowFromTemplateList(sPageSkillsTemplate, PSS_DATA_WINDOW_SKILLS_HELD_ITEM), text, x, 1, 0, 0, fontId); } static void PrintRibbonCount(void) @@ -3621,7 +3642,7 @@ static void PrintMoveNameAndPP(u8 moveIndex) if (move != 0) { pp = CalculatePPWithBonus(move, summary->ppBonuses, moveIndex); - PrintTextOnWindow(moveNameWindowId, GetMoveName(move), 0, moveIndex * 16 + 1, 0, 1); + PrintTextOnWindowToFit(moveNameWindowId, GetMoveName(move), 0, moveIndex * 16 + 1, 0, 1); ConvertIntToDecimalStringN(gStringVar1, summary->pp[moveIndex], STR_CONV_MODE_RIGHT_ALIGN, 2); ConvertIntToDecimalStringN(gStringVar2, pp, STR_CONV_MODE_RIGHT_ALIGN, 2); DynamicPlaceholderTextUtil_Reset(); @@ -3789,9 +3810,9 @@ static void PrintNewMoveDetailsOrCancelText(void) u16 move = sMonSummaryScreen->newMove; if (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES) - PrintTextOnWindow(windowId1, GetMoveName(move), 0, 65, 0, 6); + PrintTextOnWindowToFit(windowId1, GetMoveName(move), 0, 65, 0, 6); else - PrintTextOnWindow(windowId1, GetMoveName(move), 0, 65, 0, 5); + PrintTextOnWindowToFit(windowId1, GetMoveName(move), 0, 65, 0, 5); ConvertIntToDecimalStringN(gStringVar1, gMovesInfo[move].pp, STR_CONV_MODE_RIGHT_ALIGN, 2); DynamicPlaceholderTextUtil_Reset(); diff --git a/src/pokenav_conditions.c b/src/pokenav_conditions.c index 19cfe38b95..382ddde413 100644 --- a/src/pokenav_conditions.c +++ b/src/pokenav_conditions.c @@ -372,6 +372,8 @@ static u8 *CopyConditionMonNameGender(u8 *str, u16 listId, bool8 skipPadding) while (*str_ != EOS) (str_++); + str_ = WrapFontIdToFit(str, str_, FONT_NORMAL, 57); + *(str_++) = EXT_CTRL_CODE_BEGIN; *(str_++) = EXT_CTRL_CODE_SKIP; *(str_++) = 60; diff --git a/src/pokenav_conditions_search_results.c b/src/pokenav_conditions_search_results.c index 24fe966dc3..9afb2bb2d9 100644 --- a/src/pokenav_conditions_search_results.c +++ b/src/pokenav_conditions_search_results.c @@ -692,8 +692,9 @@ static void BufferSearchMonListItem(struct PokenavMonListItem * item, u8 *dest) { u8 gender; u8 level; - u8 *s; + u8 *s, *end; const u8 *genderStr; + u32 fontId; // Mon is in party if (item->boxId == TOTAL_BOXES_COUNT) @@ -712,8 +713,6 @@ static void BufferSearchMonListItem(struct PokenavMonListItem * item, u8 *dest) GetBoxMonData(mon, MON_DATA_NICKNAME, gStringVar3); } - StringGet_Nickname(gStringVar3); - dest = GetStringClearToWidth(dest, FONT_NORMAL, gStringVar3, 60); switch (gender) { default: @@ -726,6 +725,11 @@ static void BufferSearchMonListItem(struct PokenavMonListItem * item, u8 *dest) genderStr = sText_FemaleSymbol; break; } + end = StringGet_Nickname(gStringVar3); + fontId = GetFontIdToFit(gStringVar3, FONT_NORMAL, 0, 60); + WrapFontIdToFit(gStringVar3, end, FONT_NORMAL, 60); + dest = GetStringClearToWidth(dest, fontId, gStringVar3, 60); + s = StringCopy(gStringVar1, genderStr); *s++ = CHAR_SLASH; *s++ = CHAR_EXTRA_SYMBOL; diff --git a/src/pokenav_ribbons_list.c b/src/pokenav_ribbons_list.c index 72783b0972..834dc926ad 100644 --- a/src/pokenav_ribbons_list.c +++ b/src/pokenav_ribbons_list.c @@ -699,9 +699,10 @@ static void BufferRibbonMonInfoText(struct PokenavListItem * listItem, u8 *dest) { u8 gender; u8 level; - u8 *s; + u8 *s, *end; const u8 *genderStr; struct PokenavMonListItem * item = (struct PokenavMonListItem *)listItem; + u32 fontId; // Mon is in party if (item->boxId == TOTAL_BOXES_COUNT) @@ -720,8 +721,6 @@ static void BufferRibbonMonInfoText(struct PokenavListItem * listItem, u8 *dest) GetBoxMonData(mon, MON_DATA_NICKNAME, gStringVar3); } - StringGet_Nickname(gStringVar3); - dest = GetStringClearToWidth(dest, FONT_NORMAL, gStringVar3, 60); switch (gender) { default: @@ -734,6 +733,10 @@ static void BufferRibbonMonInfoText(struct PokenavListItem * listItem, u8 *dest) genderStr = sText_FemaleSymbol; break; } + end = StringGet_Nickname(gStringVar3); + fontId = GetFontIdToFit(gStringVar3, FONT_NORMAL, 0, 60); + WrapFontIdToFit(gStringVar3, end, FONT_NORMAL, 60); + dest = GetStringClearToWidth(dest, fontId, gStringVar3, 60); s = StringCopy(gStringVar1, genderStr); *s++ = CHAR_SLASH; diff --git a/src/pokenav_ribbons_summary.c b/src/pokenav_ribbons_summary.c index 1ff55dc187..bba1c3600c 100644 --- a/src/pokenav_ribbons_summary.c +++ b/src/pokenav_ribbons_summary.c @@ -878,7 +878,6 @@ static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) FillWindowPixelBuffer(windowId, PIXEL_FILL(1)); GetMonNicknameLevelGender(gStringVar3, &level, &gender); - AddTextPrinterParameterized(windowId, FONT_NORMAL, gStringVar3, 0, 1, TEXT_SKIP_DRAW, NULL); switch (gender) { case MON_MALE: @@ -891,6 +890,7 @@ static void PrintRibbbonsSummaryMonInfo(struct Pokenav_RibbonsSummaryMenu *menu) genderTxt = sGenderlessIconString; break; } + AddTextPrinterParameterized(windowId, GetFontIdToFit(gStringVar3, FONT_NORMAL, 0, 60), gStringVar3, 0, 1, TEXT_SKIP_DRAW, NULL); txtPtr = StringCopy(gStringVar1, genderTxt); *(txtPtr++) = CHAR_SLASH; diff --git a/src/script_pokemon_util.c b/src/script_pokemon_util.c index 31e40fa31a..f7dacbbfb7 100644 --- a/src/script_pokemon_util.c +++ b/src/script_pokemon_util.c @@ -7,6 +7,7 @@ #include "decompress.h" #include "event_data.h" #include "international_string_util.h" +#include "item.h" #include "link.h" #include "link_rfu.h" #include "main.h" @@ -38,6 +39,10 @@ void HealPlayerParty(void) HealPokemon(&gPlayerParty[i]); if (OW_PC_HEAL >= GEN_8) HealPlayerBoxes(); + + // Recharge Tera Orb, if possible. + if (B_FLAG_TERA_ORB_CHARGED != 0 && CheckBagHasItem(ITEM_TERA_ORB, 1)) + FlagSet(B_FLAG_TERA_ORB_CHARGED); } static void HealPlayerBoxes(void) @@ -289,6 +294,25 @@ void ToggleGigantamaxFactor(struct ScriptContext *ctx) } } +void CheckTeraType(struct ScriptContext *ctx) +{ + u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + gSpecialVar_Result = TYPE_NONE; + + if (partyIndex < PARTY_SIZE) + gSpecialVar_Result = GetMonData(&gPlayerParty[partyIndex], MON_DATA_TERA_TYPE); +} + +void SetTeraType(struct ScriptContext *ctx) +{ + u32 type = ScriptReadByte(ctx); + u32 partyIndex = VarGet(ScriptReadHalfword(ctx)); + + if (type < NUMBER_OF_MON_TYPES && partyIndex < PARTY_SIZE) + SetMonData(&gPlayerParty[partyIndex], MON_DATA_TERA_TYPE, &type); +} + u32 ScriptGiveMonParameterized(u16 species, u8 level, u16 item, u8 ball, u8 nature, u8 abilityNum, u8 gender, u8 *evs, u8 *ivs, u16 *moves, bool8 isShiny, bool8 ggMaxFactor, u8 teraType) { u16 nationalDexNum; diff --git a/src/shop.c b/src/shop.c index e792e41605..620a49394d 100644 --- a/src/shop.c +++ b/src/shop.c @@ -217,7 +217,8 @@ static const struct ListMenuTemplate sShopBuyMenuListTemplate = .itemVerticalPadding = 0, .scrollMultiple = LIST_NO_MULTIPLE_SCROLL, .fontId = FONT_NARROW, - .cursorKind = CURSOR_BLACK_ARROW + .cursorKind = CURSOR_BLACK_ARROW, + .textNarrowWidth = 84, }; static const struct BgTemplate sShopBuyMenuBgTemplates[] = diff --git a/src/strings.c b/src/strings.c index 4fde380240..84c8112681 100644 --- a/src/strings.c +++ b/src/strings.c @@ -221,20 +221,20 @@ const u8 gText_xVar1[] = _("×{STR_VAR_1}"); const u8 gText_Berry2[] = _(" BERRY"); // Unused const u8 gText_Coins[] = _("{STR_VAR_1} COINS"); const u8 gText_CloseBag[] = _("CLOSE BAG"); -const u8 gText_Var1IsSelected[] = _("{STR_VAR_1} is\nselected."); +const u8 gText_Var1IsSelected[] = _("{STR_VAR_1}\nis selected."); const u8 gText_CantWriteMail[] = _("You can't write\nMAIL here."); const u8 gText_NoPokemon[] = _("There is no\nPOKéMON."); const u8 gText_MoveVar1Where[] = _("Move the\n{STR_VAR_1}\nwhere?"); const u8 gText_Var1CantBeHeld[] = _("The {STR_VAR_1} can't be held."); const u8 gText_Var1CantBeHeldHere[] = _("The {STR_VAR_1} can't be held\nhere."); -const u8 gText_DepositHowManyVar1[] = _("Deposit how many\n{STR_VAR_1}(s)?"); -const u8 gText_DepositedVar2Var1s[] = _("Deposited {STR_VAR_2}\n{STR_VAR_1}(s)."); +const u8 gText_DepositHowManyVar1[] = _("Deposit how many\n{STR_VAR_1}?"); +const u8 gText_DepositedVar2Var1s[] = _("Deposited {STR_VAR_2}\n{STR_VAR_1}."); const u8 gText_NoRoomForItems[] = _("There's no room to\nstore items."); const u8 gText_CantStoreImportantItems[] = _("Important items\ncan't be stored in\nthe PC!"); const u8 gText_TooImportantToToss[] = _("That's much too\nimportant to toss\nout!"); -const u8 gText_TossHowManyVar1s[] = _("Toss out how many\n{STR_VAR_1}(s)?"); -const u8 gText_ThrewAwayVar2Var1s[] = _("Threw away {STR_VAR_2}\n{STR_VAR_1}(s)."); -const u8 gText_ConfirmTossItems[] = _("Is it okay to\nthrow away {STR_VAR_2}\n{STR_VAR_1}(s)?"); +const u8 gText_TossHowManyVar1s[] = _("Toss out how many\n{STR_VAR_1}?"); +const u8 gText_ThrewAwayVar2Var1s[] = _("Threw away {STR_VAR_2}\n{STR_VAR_1}."); +const u8 gText_ConfirmTossItems[] = _("Is it okay to\nthrow away {STR_VAR_2}\n{STR_VAR_1}?"); const u8 gText_DadsAdvice[] = _("DAD's advice…\n{PLAYER}, there's a time and place for\leverything!{PAUSE_UNTIL_PRESS}"); const u8 gText_CantDismountBike[] = _("You can't dismount your BIKE here.{PAUSE_UNTIL_PRESS}"); const u8 gText_ItemFinderNearby[] = _("Huh?\nThe ITEMFINDER's responding!\pThere's an item buried around here!{PAUSE_UNTIL_PRESS}"); @@ -597,8 +597,8 @@ const u8 gText_TakeOutItemsFromPC[] = _("Take out items from the PC."); const u8 gText_ThrowAwayItemsInPC[] = _("Throw away items stored in the PC."); const u8 gText_NoItems[] = _("There are no items.{PAUSE_UNTIL_PRESS}"); const u8 gText_NoRoomInBag[] = _("There is no more\nroom in the BAG."); -const u8 gText_WithdrawHowManyItems[] = _("Withdraw how many\n{STR_VAR_1}(s)?"); -const u8 gText_WithdrawXItems[] = _("Withdrew {STR_VAR_2}\n{STR_VAR_1}(s)."); +const u8 gText_WithdrawHowManyItems[] = _("Withdraw how many\n{STR_VAR_1}?"); +const u8 gText_WithdrawXItems[] = _("Withdrew {STR_VAR_2}\n{STR_VAR_1}."); const u8 gText_Read[] = _("READ"); const u8 gText_MoveToBag[] = _("MOVE TO BAG"); const u8 gText_Give2[] = _("GIVE"); diff --git a/src/tv.c b/src/tv.c index 215af04dce..5530e519f6 100644 --- a/src/tv.c +++ b/src/tv.c @@ -1455,7 +1455,7 @@ void BravoTrainerPokemonProfile_BeforeInterview2(u8 contestStandingPlace) show->bravoTrainer.contestCategory = gSpecialVar_ContestCategory; show->bravoTrainer.contestRank = gSpecialVar_ContestRank; show->bravoTrainer.species = GetMonData(&gPlayerParty[gContestMonPartyIndex], MON_DATA_SPECIES, NULL); - GetMonData(&gPlayerParty[gContestMonPartyIndex], MON_DATA_NICKNAME, show->bravoTrainer.pokemonNickname); + GetMonData(&gPlayerParty[gContestMonPartyIndex], MON_DATA_NICKNAME10, show->bravoTrainer.pokemonNickname); StripExtCtrlCodes(show->bravoTrainer.pokemonNickname); show->bravoTrainer.pokemonNameLanguage = GetMonData(&gPlayerParty[gContestMonPartyIndex], MON_DATA_LANGUAGE); } @@ -1536,7 +1536,7 @@ void PutNameRaterShowOnTheAir(void) show->nameRaterShow.random2 = Random() % 2; show->nameRaterShow.randomSpecies = GetRandomDifferentSpeciesSeenByPlayer(show->nameRaterShow.species); StringCopy(show->nameRaterShow.trainerName, gSaveBlock2Ptr->playerName); - GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME, show->nameRaterShow.pokemonName); + GetMonData(&gPlayerParty[gSpecialVar_0x8004], MON_DATA_NICKNAME10, show->nameRaterShow.pokemonName); StripExtCtrlCodes(show->nameRaterShow.pokemonName); StorePlayerIdInNormalShow(show); show->nameRaterShow.language = gGameLanguage; @@ -1612,7 +1612,7 @@ static void InterviewAfter_PkmnFanClubOpinions(void) show->fanclubOpinions.friendshipHighNybble = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_FRIENDSHIP, NULL) >> 4; show->fanclubOpinions.questionAsked = gSpecialVar_0x8007; StringCopy(show->fanclubOpinions.playerName, gSaveBlock2Ptr->playerName); - GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_NICKNAME, show->fanclubOpinions.nickname); + GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_NICKNAME10, show->fanclubOpinions.nickname); StripExtCtrlCodes(show->fanclubOpinions.nickname); show->fanclubOpinions.species = GetMonData(&gPlayerParty[GetLeadMonIndex()], MON_DATA_SPECIES, NULL); StorePlayerIdInNormalShow(show); @@ -2229,7 +2229,7 @@ void TryPutSpotTheCutiesOnAir(struct Pokemon *pokemon, u8 ribbonMonDataIdx) show->cuties.kind = TVSHOW_CUTIES; show->cuties.active = FALSE; // NOTE: Show is not active until passed via Record Mix. StringCopy(show->cuties.playerName, gSaveBlock2Ptr->playerName); - GetMonData(pokemon, MON_DATA_NICKNAME, show->cuties.nickname); + GetMonData(pokemon, MON_DATA_NICKNAME10, show->cuties.nickname); StripExtCtrlCodes(show->cuties.nickname); show->cuties.nRibbons = GetRibbonCount(pokemon); show->cuties.selectedRibbon = MonDataIdxToRibbon(ribbonMonDataIdx); diff --git a/test/battle/ability/beads_of_ruin.c b/test/battle/ability/beads_of_ruin.c index 1b2eb2a522..2fc4f9cdc1 100644 --- a/test/battle/ability/beads_of_ruin.c +++ b/test/battle/ability/beads_of_ruin.c @@ -29,3 +29,47 @@ SINGLE_BATTLE_TEST("Beads of Ruin reduces Sp. Def if opposing mon's ability does EXPECT_MUL_EQ(damage[1], Q_4_12(1.33), damage[0]); } } + +SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battlers fainted - Player") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1);} + PLAYER(SPECIES_CHI_YU); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_RUINATION); } + } SCENE { + HP_BAR(opponent, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + // Everyone faints. + MESSAGE("Go! Chi-Yu!"); + ABILITY_POPUP(player, ABILITY_BEADS_OF_RUIN); + MESSAGE("Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Beads of Ruin's message displays correctly after all battlers fainted - Opponent") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1);} + OPPONENT(SPECIES_CHI_YU); + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_RUINATION); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + MESSAGE("Go! Wobbuffet!"); + MESSAGE("2 sent out Chi-Yu!"); + ABILITY_POPUP(opponent, ABILITY_BEADS_OF_RUIN); + MESSAGE("Foe Chi-Yu's Beads of Ruin weakened the Sp. Def of all surrounding Pokémon!"); + } +} diff --git a/test/battle/ability/booster_energy.c b/test/battle/ability/booster_energy.c index 6d08659781..a63f462b72 100644 --- a/test/battle/ability/booster_energy.c +++ b/test/battle/ability/booster_energy.c @@ -50,17 +50,17 @@ SINGLE_BATTLE_TEST("Booster Energy will activate Protosynthesis after harsh sunl ABILITY_POPUP(opponent, ABILITY_DROUGHT); NONE_OF { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); - MESSAGE("RagingBolt used its Booster Energy to activate Protosynthesis!"); - MESSAGE("RagingBolt's Sp. Atk was heightened!"); + MESSAGE("Raging Bolt used its Booster Energy to activate Protosynthesis!"); + MESSAGE("Raging Bolt's Sp. Atk was heightened!"); } ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("The harsh sunlight activated RagingBolt's Protosynthesis!"); - MESSAGE("RagingBolt's Sp. Atk was heightened!"); + MESSAGE("The harsh sunlight activated Raging Bolt's Protosynthesis!"); + MESSAGE("Raging Bolt's Sp. Atk was heightened!"); MESSAGE("The sunlight faded."); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("RagingBolt used its Booster Energy to activate Protosynthesis!"); - MESSAGE("RagingBolt's Sp. Atk was heightened!"); + MESSAGE("Raging Bolt used its Booster Energy to activate Protosynthesis!"); + MESSAGE("Raging Bolt's Sp. Atk was heightened!"); } } @@ -82,17 +82,17 @@ SINGLE_BATTLE_TEST("Booster Energy activates Protosynthesis and increases highes } SCENE { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("RagingBolt used its Booster Energy to activate Protosynthesis!"); + MESSAGE("Raging Bolt used its Booster Energy to activate Protosynthesis!"); if (attack == 110) - MESSAGE("RagingBolt's Attack was heightened!"); + MESSAGE("Raging Bolt's Attack was heightened!"); else if (defense == 110) - MESSAGE("RagingBolt's Defense was heightened!"); + MESSAGE("Raging Bolt's Defense was heightened!"); else if (speed == 110) - MESSAGE("RagingBolt's Speed was heightened!"); + MESSAGE("Raging Bolt's Speed was heightened!"); else if (spAttack == 110) - MESSAGE("RagingBolt's Sp. Atk was heightened!"); + MESSAGE("Raging Bolt's Sp. Atk was heightened!"); else if (spDefense == 110) - MESSAGE("RagingBolt's Sp. Def was heightened!"); + MESSAGE("Raging Bolt's Sp. Def was heightened!"); } THEN { EXPECT(player->item == ITEM_NONE); } @@ -185,7 +185,7 @@ SINGLE_BATTLE_TEST("Booster Energy increases special defense by 30% if it is the SINGLE_BATTLE_TEST("Booster Energy can't be flung if a Paradox species is involved") { GIVEN { - ASSUME(gSpeciesInfo[SPECIES_IRON_MOTH].isParadoxForm == TRUE); + ASSUME(gSpeciesInfo[SPECIES_IRON_MOTH].isParadox == TRUE); PLAYER(SPECIES_IRON_MOTH); OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BOOSTER_ENERGY); } } WHEN { @@ -199,7 +199,7 @@ SINGLE_BATTLE_TEST("Booster Energy can't be flung if a Paradox species is involv SINGLE_BATTLE_TEST("Booster Energy can't be tricked if a Paradox species is involved") { GIVEN { - ASSUME(gSpeciesInfo[SPECIES_IRON_MOTH].isParadoxForm == TRUE); + ASSUME(gSpeciesInfo[SPECIES_IRON_MOTH].isParadox == TRUE); PLAYER(SPECIES_IRON_MOTH) { Item(ITEM_BERRY_JUICE); } OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_BOOSTER_ENERGY); } } WHEN { diff --git a/test/battle/ability/color_change.c b/test/battle/ability/color_change.c new file mode 100644 index 0000000000..86c009e8ac --- /dev/null +++ b/test/battle/ability/color_change.c @@ -0,0 +1,148 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Color Change changes the type of a Pokemon being hit by a move if the type of the move and the Pokemon are different") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Wobbuffet's Color Change made it the Normal type!"); + } +} + +SINGLE_BATTLE_TEST("Color Change does not change the type when hit by a move that's the same type as itself") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_PSYCHO_CUT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Wobbuffet's Color Change made it the Normal type!"); + } + } +} + +SINGLE_BATTLE_TEST("Color Change does not change the type of a dual-type Pokemon when hit by a move that shares its primary type") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_XATU) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_PSYCHO_CUT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Xatu's Color Change made it the Psychic type!"); + } + } +} + +SINGLE_BATTLE_TEST("Color Change does not change the type of a dual-type Pokemon when hit by a move that shares its secondary type") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SLOWBRO) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_PSYCHO_CUT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player); + NONE_OF { + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Slowbro's Color Change made it the Psychic type!"); + } + } +} + +SINGLE_BATTLE_TEST("Color Change changes the user to Electric type if hit by a move while the opponent is under the effect of Electrify") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(opponent, MOVE_ELECTRIFY); MOVE(player, MOVE_PSYCHO_CUT); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHO_CUT, player); + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Wobbuffet's Color Change made it the Electric type!"); + } +} + +SINGLE_BATTLE_TEST("Color Change changes the type when a Pokemon is hit by Future Sight") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_SNORLAX) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("Foe Snorlax took the Future Sight attack!"); + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Snorlax's Color Change made it the Psychic type!"); + } +} + +SINGLE_BATTLE_TEST("Color Change changes the type when a Pokemon is hit by Doom Desire") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(player, MOVE_DOOM_DESIRE); } + TURN { } + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOOM_DESIRE, player); + MESSAGE("Foe Wobbuffet took the Doom Desire attack!"); + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Wobbuffet's Color Change made it the Steel type!"); + } +} + +SINGLE_BATTLE_TEST("Color Change changes the type to Electric when a Pokemon is hit by a forseen attack under the effect of Electrify") +{ + KNOWN_FAILING; // #4471. + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_BLASTOISE) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { MOVE(opponent, MOVE_ELECTRIFY); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("Foe Blastoise took the Future Sight attack!"); + MESSAGE("It's super effective!"); + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Blastoise's Color Change made it the Electr type!"); + } +} + +SINGLE_BATTLE_TEST("Color Change changes the type to Normal when a Pokemon is hit by a forseen attack under the effect of Normalize") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Ability(ABILITY_NORMALIZE); } + OPPONENT(SPECIES_BLASTOISE) { Ability(ABILITY_COLOR_CHANGE); } + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_FUTURE_SIGHT); } + TURN { } + TURN { } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player); + MESSAGE("Foe Blastoise took the Future Sight attack!"); + ABILITY_POPUP(opponent, ABILITY_COLOR_CHANGE); + MESSAGE("Foe Blastoise's Color Change made it the Normal type!"); + } +} diff --git a/test/battle/ability/costar.c b/test/battle/ability/costar.c new file mode 100644 index 0000000000..7674ab0966 --- /dev/null +++ b/test/battle/ability/costar.c @@ -0,0 +1,8 @@ +#include "global.h" +#include "test/battle.h" + +TO_DO_BATTLE_TEST("Costar copies an ally's stat stages upon entering battle"); + +// Copy from Ruin ability tests +TO_DO_BATTLE_TEST("Costar's message displays correctly after all battlers fainted - Player"); +TO_DO_BATTLE_TEST("Costar's message displays correctly after all battlers fainted - Opponent"); diff --git a/test/battle/move_effect/cud_chuw.c b/test/battle/ability/cud_chew.c similarity index 93% rename from test/battle/move_effect/cud_chuw.c rename to test/battle/ability/cud_chew.c index ba59d355a4..305969aa93 100644 --- a/test/battle/move_effect/cud_chuw.c +++ b/test/battle/ability/cud_chew.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -SINGLE_BATTLE_TEST("Cud Chuw will activate Kee Berry effect again on the next turn") +SINGLE_BATTLE_TEST("Cud Chew will activate Kee Berry effect again on the next turn") { GIVEN { ASSUME(gItemsInfo[ITEM_KEE_BERRY].holdEffect == HOLD_EFFECT_KEE_BERRY); @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Cud Chuw will activate Kee Berry effect again on the next tu } } -SINGLE_BATTLE_TEST("Cud Chuw will activate Oran Berry effect again on the next turn") +SINGLE_BATTLE_TEST("Cud Chew will activate Oran Berry effect again on the next turn") { GIVEN { ASSUME(gItemsInfo[ITEM_ORAN_BERRY].holdEffect == HOLD_EFFECT_RESTORE_HP); diff --git a/test/battle/ability/dancer.c b/test/battle/ability/dancer.c index 7e520f440b..34af26e75e 100644 --- a/test/battle/ability/dancer.c +++ b/test/battle/ability/dancer.c @@ -36,11 +36,11 @@ SINGLE_BATTLE_TEST("Dancer can copy Teeter Dance") DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targets") { - KNOWN_FAILING; // Fails because copied move that targets both opposing mons, targets only one when copied by Dancer GIVEN { ASSUME(gMovesInfo[MOVE_TEETER_DANCE].danceMove == TRUE); + ASSUME(gItemsInfo[ITEM_LUM_BERRY].holdEffect == HOLD_EFFECT_CURE_STATUS); PLAYER(SPECIES_WOBBUFFET) - PLAYER(SPECIES_WYNAUT) + PLAYER(SPECIES_WYNAUT) { Item(ITEM_LUM_BERRY); } OPPONENT(SPECIES_ORICORIO) { Ability(ABILITY_DANCER); Item(ITEM_LUM_BERRY); } OPPONENT(SPECIES_SLOWPOKE) { Ability(ABILITY_OWN_TEMPO); } } WHEN { @@ -50,6 +50,6 @@ DOUBLE_BATTLE_TEST("Dancer can copy Teeter Dance and confuse both opposing targe ABILITY_POPUP(opponentLeft, ABILITY_DANCER); ANIMATION(ANIM_TYPE_MOVE, MOVE_TEETER_DANCE, opponentLeft); MESSAGE("Wobbuffet became confused!"); - MESSAGE("Wynaut became confusef!"); + MESSAGE("Wynaut became confused!"); } } diff --git a/test/battle/ability/embody_aspect.c b/test/battle/ability/embody_aspect.c index 8b37dd1a74..728ba8cb94 100644 --- a/test/battle/ability/embody_aspect.c +++ b/test/battle/ability/embody_aspect.c @@ -2,14 +2,14 @@ #include "test/battle.h" -SINGLE_BATTLE_TEST("Embodoy Aspect raises a stat depending on the users form by one stage") +SINGLE_BATTLE_TEST("Embody Aspect raises a stat depending on the users form by one stage") { u16 species, ability; - PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_TEAL; } - PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_HEARTHFLAME; } - PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_WELLSPRING; } - PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_CORNERSTONE; } + PARAMETRIZE { species = SPECIES_OGERPON_TEAL_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_TEAL_MASK; } + PARAMETRIZE { species = SPECIES_OGERPON_HEARTHFLAME_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK; } + PARAMETRIZE { species = SPECIES_OGERPON_WELLSPRING_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_WELLSPRING_MASK; } + PARAMETRIZE { species = SPECIES_OGERPON_CORNERSTONE_MASK_TERA; ability = ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK; } GIVEN { PLAYER(SPECIES_WOBBUFFET); @@ -19,32 +19,32 @@ SINGLE_BATTLE_TEST("Embodoy Aspect raises a stat depending on the users form by } SCENE { ABILITY_POPUP(opponent, ability); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - if (ability == ABILITY_EMBODY_ASPECT_TEAL) - MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Atk!"); - else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME) + if (ability == ABILITY_EMBODY_ASPECT_TEAL_MASK) + MESSAGE("Foe Ogerpon's Embody Aspect raised its Speed!"); + else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK) MESSAGE("Foe Ogerpon's Embody Aspect raised its Attack!"); - else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING) + else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING_MASK) MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Def!"); - else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE) + else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK) MESSAGE("Foe Ogerpon's Embody Aspect raised its Defense!"); } THEN { - if (ability == ABILITY_EMBODY_ASPECT_TEAL) - EXPECT_EQ(opponent->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); - else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME) + if (ability == ABILITY_EMBODY_ASPECT_TEAL_MASK) + EXPECT_EQ(opponent->statStages[STAT_SPEED], DEFAULT_STAT_STAGE + 1); + else if (ability == ABILITY_EMBODY_ASPECT_HEARTHFLAME_MASK) EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); - else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING) + else if (ability == ABILITY_EMBODY_ASPECT_WELLSPRING_MASK) EXPECT_EQ(opponent->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1); - else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE) + else if (ability == ABILITY_EMBODY_ASPECT_CORNERSTONE_MASK) EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); } } -SINGLE_BATTLE_TEST("Embodoy Aspect activates when it's no longer effected by Neutralizing Gas") +SINGLE_BATTLE_TEST("Embody Aspect activates when it's no longer effected by Neutralizing Gas") { GIVEN { PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); } PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_OGERPON_TEAL_MASK_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL); } + OPPONENT(SPECIES_OGERPON_TEAL_MASK_TERA) { Ability(ABILITY_EMBODY_ASPECT_TEAL_MASK); } } WHEN { TURN { SWITCH(player, 1); } } SCENE { @@ -52,8 +52,8 @@ SINGLE_BATTLE_TEST("Embodoy Aspect activates when it's no longer effected by Neu MESSAGE("Neutralizing Gas filled the area!"); MESSAGE("Weezing, that's enough! Come back!"); MESSAGE("The effects of Neutralizing Gas wore off!"); - ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL); + ABILITY_POPUP(opponent, ABILITY_EMBODY_ASPECT_TEAL_MASK); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("Foe Ogerpon's Embody Aspect raised its Sp. Atk!"); + MESSAGE("Foe Ogerpon's Embody Aspect raised its Speed!"); } } diff --git a/test/battle/ability/frisk.c b/test/battle/ability/frisk.c index dd6d0f691f..385ab7e1f9 100644 --- a/test/battle/ability/frisk.c +++ b/test/battle/ability/frisk.c @@ -37,9 +37,9 @@ SINGLE_BATTLE_TEST("Frisk triggers in a Single Battle") DOUBLE_BATTLE_TEST("Frisk triggers for player in a Double Battle after switching-in after fainting") { - bool32 targetLeft; - PARAMETRIZE { targetLeft = TRUE; } - PARAMETRIZE { targetLeft = FALSE; } + struct BattlePokemon *target = NULL; + PARAMETRIZE { target = playerLeft; } + PARAMETRIZE { target = playerRight; } GIVEN { ASSUME(gMovesInfo[MOVE_POUND].power != 0); @@ -49,20 +49,20 @@ DOUBLE_BATTLE_TEST("Frisk triggers for player in a Double Battle after switching OPPONENT(SPECIES_WYNAUT) { Item(ITEM_POTION); } OPPONENT(SPECIES_WYNAUT); } WHEN { - TURN { MOVE(opponentLeft, MOVE_POUND, target: targetLeft ? playerLeft : playerRight); SEND_OUT(targetLeft ? playerLeft : playerRight, 2); } + TURN { MOVE(opponentLeft, MOVE_POUND, target: target); SEND_OUT(target, 2); } } SCENE { MESSAGE("Foe Wynaut used Pound!"); MESSAGE("Wobbuffet fainted!"); - ABILITY_POPUP(targetLeft ? playerLeft : playerRight, ABILITY_FRISK); + ABILITY_POPUP(target, ABILITY_FRISK); MESSAGE("Furret frisked Foe Wynaut and found its Potion!"); } } DOUBLE_BATTLE_TEST("Frisk triggers for opponent in a Double Battle after switching-in after fainting") { - bool32 targetLeft; - PARAMETRIZE { targetLeft = TRUE; } - PARAMETRIZE { targetLeft = FALSE; } + struct BattlePokemon *target = NULL; + PARAMETRIZE { target = opponentLeft; } + PARAMETRIZE { target = opponentRight; } GIVEN { ASSUME(gMovesInfo[MOVE_POUND].power != 0); @@ -72,11 +72,11 @@ DOUBLE_BATTLE_TEST("Frisk triggers for opponent in a Double Battle after switchi OPPONENT(SPECIES_WOBBUFFET) { HP(1); } OPPONENT(SPECIES_FURRET) { Ability(ABILITY_FRISK); }; } WHEN { - TURN { MOVE(playerLeft, MOVE_POUND, target: targetLeft ? opponentLeft : opponentRight); SEND_OUT(targetLeft ? opponentLeft : opponentRight, 2); } + TURN { MOVE(playerLeft, MOVE_POUND, target: target); SEND_OUT(target, 2); } } SCENE { MESSAGE("Wynaut used Pound!"); MESSAGE("Foe Wobbuffet fainted!"); - ABILITY_POPUP(targetLeft ? opponentLeft : opponentRight, ABILITY_FRISK); + ABILITY_POPUP(target, ABILITY_FRISK); MESSAGE("Foe Furret frisked Wynaut and found its Potion!"); } } diff --git a/test/battle/ability/hospitality.c b/test/battle/ability/hospitality.c index 74648b0c9a..308177d90f 100644 --- a/test/battle/ability/hospitality.c +++ b/test/battle/ability/hospitality.c @@ -18,12 +18,12 @@ DOUBLE_BATTLE_TEST("Hospitality user restores 25% of ally's health") } SCENE { if (health == 75) { ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY); - MESSAGE("Wobbuffet drank down all the matcha that Ptchageist made!"); + MESSAGE("Wobbuffet drank down all the matcha that Poltchageist made!"); HP_BAR(playerRight, damage: -25); } else { NONE_OF { ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY); - MESSAGE("Wobbuffet drank down all the matcha that Ptchageist made!"); + MESSAGE("Wobbuffet drank down all the matcha that Poltchageist made!"); HP_BAR(playerRight, damage: -25); } } @@ -42,9 +42,9 @@ DOUBLE_BATTLE_TEST("Hospitality user restores 25% of ally's health on switch-in" TURN { SWITCH(playerLeft, 2); } } SCENE { MESSAGE("Wobbuffet, that's enough! Come back!"); - MESSAGE("Go! Ptchageist!"); + MESSAGE("Go! Poltchageist!"); ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY); - MESSAGE("Wobbuffet drank down all the matcha that Ptchageist made!"); + MESSAGE("Wobbuffet drank down all the matcha that Poltchageist made!"); HP_BAR(playerRight, damage: -25); } } @@ -63,8 +63,29 @@ DOUBLE_BATTLE_TEST("Hospitality ignores Substitute") } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, playerRight); MESSAGE("Wobbuffet, that's enough! Come back!"); - MESSAGE("Go! Ptchageist!"); + MESSAGE("Go! Poltchageist!"); ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY); - MESSAGE("Wobbuffet drank down all the matcha that Ptchageist made!"); + MESSAGE("Wobbuffet drank down all the matcha that Poltchageist made!"); + } +} + +DOUBLE_BATTLE_TEST("Hospitality does not trigger if there is no ally on the field") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_WOBBUFFET) { HP(1); } + PLAYER(SPECIES_POLTCHAGEIST) { Ability(ABILITY_HOSPITALITY); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_BLIZZARD); SEND_OUT(playerLeft, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BLIZZARD, opponentLeft); + HP_BAR(playerLeft); + MESSAGE("Wobbuffet fainted!"); + HP_BAR(playerRight); + MESSAGE("Wobbuffet fainted!"); + MESSAGE("Go! Poltchageist!"); + NOT ABILITY_POPUP(playerLeft, ABILITY_HOSPITALITY); } } diff --git a/test/battle/ability/intimidate.c b/test/battle/ability/intimidate.c index 298e021732..08560ccb00 100644 --- a/test/battle/ability/intimidate.c +++ b/test/battle/ability/intimidate.c @@ -184,3 +184,29 @@ DOUBLE_BATTLE_TEST("Intimidate activates immediately after the mon was switched EXPECT_EQ(playerLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); } } + +SINGLE_BATTLE_TEST("Intimidate can not further lower opponents Atk stat if it is at minimum stages") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); } + } WHEN { + TURN { MOVE(opponent, MOVE_CHARM); } + TURN { MOVE(opponent, MOVE_CHARM); } + TURN { MOVE(opponent, MOVE_CHARM); } + TURN { SWITCH(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CHARM, opponent); + ABILITY_POPUP(opponent, ABILITY_INTIMIDATE); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Foe Arbok's Intimidate cuts Wobbuffet's attack!"); + } + MESSAGE("Wobbuffet's Attack won't go lower!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], MIN_STAT_STAGE); + } +} diff --git a/test/battle/ability/magic_bounce.c b/test/battle/ability/magic_bounce.c index 95eaf382e6..8d583b154d 100644 --- a/test/battle/ability/magic_bounce.c +++ b/test/battle/ability/magic_bounce.c @@ -81,3 +81,54 @@ DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting both foes at two foe MESSAGE("Foe Wynaut's Defense fell!"); } } + +DOUBLE_BATTLE_TEST("Magic Bounce bounces back moves hitting foes field") +{ + u32 battlerOne, battlerTwo, abilityBattlerOne, abilityBattlerTwo; + + PARAMETRIZE { battlerOne = SPECIES_NATU; abilityBattlerOne = ABILITY_MAGIC_BOUNCE; + battlerTwo = SPECIES_ESPEON; abilityBattlerTwo = ABILITY_SYNCHRONIZE; } + PARAMETRIZE { battlerOne = SPECIES_NATU; abilityBattlerOne = ABILITY_KEEN_EYE; + battlerTwo = SPECIES_ESPEON; abilityBattlerTwo = ABILITY_MAGIC_BOUNCE; } + + GIVEN { + ASSUME(gMovesInfo[MOVE_STEALTH_ROCK].target == MOVE_TARGET_OPPONENTS_FIELD); + PLAYER(SPECIES_ABRA); + PLAYER(SPECIES_KADABRA); + OPPONENT(battlerOne) { Ability(abilityBattlerOne); } + OPPONENT(battlerTwo) { Ability(abilityBattlerTwo); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_STEALTH_ROCK); } + } SCENE { + if (abilityBattlerOne == ABILITY_MAGIC_BOUNCE) + ABILITY_POPUP(opponentLeft, ABILITY_MAGIC_BOUNCE); + else + ABILITY_POPUP(opponentRight, ABILITY_MAGIC_BOUNCE); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, playerLeft); + if (abilityBattlerOne == ABILITY_MAGIC_BOUNCE) { + MESSAGE("Abra's Stealth Rock was bounced back by Foe Natu's Magic Bounce!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft); + } else { + MESSAGE("Abra's Stealth Rock was bounced back by Foe Espeon's Magic Bounce!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentRight); + } + } +} + +SINGLE_BATTLE_TEST("Magic Bounce bounced back status moves can not be bounced back by Magic Bounce") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_TOXIC].effect == EFFECT_TOXIC); + PLAYER(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } + OPPONENT(SPECIES_ESPEON) { Ability(ABILITY_MAGIC_BOUNCE); } + } WHEN { + TURN { MOVE(player, MOVE_TOXIC); } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_MAGIC_BOUNCE); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, player); + MESSAGE("Espeon's Toxic was bounced back by Foe Espeon's Magic Bounce!"); + NOT ABILITY_POPUP(player, ABILITY_MAGIC_BOUNCE); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC, opponent); + STATUS_ICON(player, badPoison: TRUE); + } +} diff --git a/test/battle/ability/mirror_armor.c b/test/battle/ability/mirror_armor.c index 38ee8dab91..39c22a66c5 100644 --- a/test/battle/ability/mirror_armor.c +++ b/test/battle/ability/mirror_armor.c @@ -55,11 +55,11 @@ SINGLE_BATTLE_TEST("Mirror Armor triggers even if the attacking Pokemon also has } WHEN { TURN { MOVE(opponent, MOVE_LEER); } } SCENE { - MESSAGE("Foe Corviknigh used Leer!"); + MESSAGE("Foe Corviknight used Leer!"); ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); - MESSAGE("Foe Corviknigh's Defense fell!"); + MESSAGE("Foe Corviknight's Defense fell!"); } THEN { EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE); EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1); @@ -153,9 +153,9 @@ SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stat of the attacking Pokemon TURN { MOVE(player, MOVE_SCREECH); } TURN { MOVE(opponent, MOVE_LEER); } } SCENE { - MESSAGE("Corviknigh used Screech!"); - MESSAGE("Corviknigh used Screech!"); - MESSAGE("Corviknigh used Screech!"); + MESSAGE("Corviknight used Screech!"); + MESSAGE("Corviknight used Screech!"); + MESSAGE("Corviknight used Screech!"); MESSAGE("Foe Wynaut used Leer!"); ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent); @@ -188,8 +188,8 @@ DOUBLE_BATTLE_TEST("Mirror Armor lowers Speed of the partner Pokemon after Court MESSAGE("Wobbuffet used Sticky Web!"); MESSAGE("Foe Wynaut used Court Change!"); MESSAGE("Foe Wynaut swapped the battle effects affecting each side!"); - MESSAGE("Go! Corviknigh!"); - MESSAGE("Corviknigh was caught in a Sticky Web!"); + MESSAGE("Go! Corviknight!"); + MESSAGE("Corviknight was caught in a Sticky Web!"); ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft); MESSAGE("Wobbuffet's Speed fell!"); diff --git a/test/battle/ability/poison_puppeteer.c b/test/battle/ability/poison_puppeteer.c new file mode 100644 index 0000000000..af5d5389fa --- /dev/null +++ b/test/battle/ability/poison_puppeteer.c @@ -0,0 +1,73 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ +} + +SINGLE_BATTLE_TEST("Poison Puppeteer confuses target if it was poisoned by a damaging move") +{ + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE); + PLAYER(SPECIES_PECHARUNT) { Ability(ABILITY_POISON_PUPPETEER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_POISON_STING); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_STING, player); + HP_BAR(opponent); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); + STATUS_ICON(opponent, poison: TRUE); + ABILITY_POPUP(player, ABILITY_POISON_PUPPETEER); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, opponent); + MESSAGE("Foe Wobbuffet became confused!"); + } +} + +SINGLE_BATTLE_TEST("Poison Puppeteer confuses target if it was (badly) poisoned by a status move") +{ + u32 move; + + PARAMETRIZE { move = MOVE_POISON_POWDER; } + PARAMETRIZE { move = MOVE_TOXIC; } + + GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE); + PLAYER(SPECIES_PECHARUNT) { Ability(ABILITY_POISON_PUPPETEER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, move); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, move, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); + if (move == MOVE_POISON_POWDER) + STATUS_ICON(opponent, poison: TRUE); + else + STATUS_ICON(opponent, badPoison: TRUE); + ABILITY_POPUP(player, ABILITY_POISON_PUPPETEER); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, opponent); + MESSAGE("Foe Wobbuffet became confused!"); + } +} + +SINGLE_BATTLE_TEST("Poison Puppeteer does not trigger if poison is Toxic Spikes induced") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_TOXIC_SPIKES].effect == EFFECT_TOXIC_SPIKES); + PLAYER(SPECIES_PECHARUNT) { Ability(ABILITY_POISON_PUPPETEER); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TOXIC_SPIKES);} + TURN { SWITCH(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_TOXIC_SPIKES, player); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PSN, opponent); + STATUS_ICON(opponent, poison: TRUE); + NONE_OF { + ABILITY_POPUP(player, ABILITY_POISON_PUPPETEER); + ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, opponent); + MESSAGE("Foe Wobbuffet became confused!"); + } + } +} diff --git a/test/battle/ability/protosynthesis.c b/test/battle/ability/protosynthesis.c index 264548c207..3cb35164ec 100644 --- a/test/battle/ability/protosynthesis.c +++ b/test/battle/ability/protosynthesis.c @@ -17,8 +17,8 @@ SINGLE_BATTLE_TEST("Protosynthesis boosts the highest stat") } SCENE { ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, player); ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("The harsh sunlight activated WalkngWake's Protosynthesis!"); - MESSAGE("WalkngWake's Sp. Atk was heightened!"); + MESSAGE("The harsh sunlight activated Walking Wake's Protosynthesis!"); + MESSAGE("Walking Wake's Sp. Atk was heightened!"); } } @@ -68,19 +68,19 @@ SINGLE_BATTLE_TEST("Protosynthesis ability pop up activates only once during the } SCENE { ABILITY_POPUP(opponent, ABILITY_DROUGHT); ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("The harsh sunlight activated WalkngWake's Protosynthesis!"); - MESSAGE("WalkngWake's Sp. Atk was heightened!"); + MESSAGE("The harsh sunlight activated Walking Wake's Protosynthesis!"); + MESSAGE("Walking Wake's Sp. Atk was heightened!"); NONE_OF { for (turns = 0; turns < 4; turns++) { ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("The harsh sunlight activated WalkngWake's Protosynthesis!"); - MESSAGE("WalkngWake's Sp. Atk was heightened!"); + MESSAGE("The harsh sunlight activated Walking Wake's Protosynthesis!"); + MESSAGE("Walking Wake's Sp. Atk was heightened!"); } } ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent); ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("The harsh sunlight activated WalkngWake's Protosynthesis!"); - MESSAGE("WalkngWake's Sp. Atk was heightened!"); + MESSAGE("The harsh sunlight activated Walking Wake's Protosynthesis!"); + MESSAGE("Walking Wake's Sp. Atk was heightened!"); } } @@ -95,7 +95,7 @@ SINGLE_BATTLE_TEST("Protosynthesis activates on switch-in") } SCENE { ABILITY_POPUP(opponent, ABILITY_DROUGHT); ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS); - MESSAGE("The harsh sunlight activated RoarngMoon's Protosynthesis!"); - MESSAGE("RoarngMoon's Attack was heightened!"); + MESSAGE("The harsh sunlight activated Roaring Moon's Protosynthesis!"); + MESSAGE("Roaring Moon's Attack was heightened!"); } } diff --git a/test/battle/ability/supersweet_syrup.c b/test/battle/ability/supersweet_syrup.c index 016c621ee5..6a2fd4fd76 100644 --- a/test/battle/ability/supersweet_syrup.c +++ b/test/battle/ability/supersweet_syrup.c @@ -45,3 +45,29 @@ DOUBLE_BATTLE_TEST("Supersweet Syrup lowers evasion of both opposing mon's in ba EXPECT_EQ(playerRight->statStages[STAT_EVASION], DEFAULT_STAT_STAGE - 1); } } + +SINGLE_BATTLE_TEST("Supersweet Syrup can not further lower opponents evasion if it is at minimum stages") +{ + GIVEN { + PLAYER(SPECIES_ODDISH); + OPPONENT(SPECIES_ODDISH); + OPPONENT(SPECIES_HYDRAPPLE) { Ability(ABILITY_SUPERSWEET_SYRUP); } + } WHEN { + TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + TURN { MOVE(opponent, MOVE_SWEET_SCENT); } + TURN { SWITCH(opponent, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent); + ABILITY_POPUP(opponent, ABILITY_SUPERSWEET_SYRUP); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Oddish's evasiveness fell!"); + } + MESSAGE("Oddish's evasiveness won't go lower!"); + } THEN { + EXPECT_EQ(player->statStages[STAT_EVASION], MIN_STAT_STAGE); + } +} diff --git a/test/battle/ability/supreme_overlord.c b/test/battle/ability/supreme_overlord.c index a01a5d6306..5d24850245 100644 --- a/test/battle/ability/supreme_overlord.c +++ b/test/battle/ability/supreme_overlord.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -DOUBLE_BATTLE_TEST("Supreme Overlord boosts Attack by an additive 10% per fainted mon on the side", s16 damage) +DOUBLE_BATTLE_TEST("Supreme Overlord boosts Attack by an additive 10% per fainted mon on its side upon switch in", s16 damage) { bool32 switchMon = 0; PARAMETRIZE { switchMon = FALSE; } @@ -21,6 +21,10 @@ DOUBLE_BATTLE_TEST("Supreme Overlord boosts Attack by an additive 10% per fainte TURN { SWITCH(playerLeft, 0); } TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentLeft); } } SCENE { + if (switchMon) { + ABILITY_POPUP(playerLeft, ABILITY_SUPREME_OVERLORD); + MESSAGE("Kingambit gained strength from the fallen!"); + } ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerLeft); HP_BAR(opponentLeft, captureDamage: &results[i].damage); } FINALLY { @@ -51,6 +55,8 @@ DOUBLE_BATTLE_TEST("Supreme Overlord's boost caps at a 1.5x multipler", s16 dama TURN { SWITCH(playerRight, 3); } TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); } } SCENE { + ABILITY_POPUP(playerRight, ABILITY_SUPREME_OVERLORD); + MESSAGE("Kingambit gained strength from the fallen!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight); HP_BAR(opponentLeft, captureDamage: &results[i].damage); } FINALLY { @@ -85,3 +91,52 @@ SINGLE_BATTLE_TEST("Supreme Overlord does not boost attack if party members are EXPECT_EQ(results[0].damage, results[1].damage); } } + +SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Player") +{ + // For some reason the Ability Pop Up fails to appear after Explosion. + KNOWN_FAILING; + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1);} + PLAYER(SPECIES_KINGAMBIT); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_KOWTOW_CLEAVE); } + } SCENE { + HP_BAR(opponent, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + // Everyone faints. + MESSAGE("Go! Kingambit!"); + ABILITY_POPUP(player, ABILITY_SUPREME_OVERLORD); + MESSAGE("Kingambit gained strength from the fallen!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Supreme Overlord's message displays correctly after all battlers fainted - Opponent") +{ + // For some reason the Ability Pop Up fails to appear after Explosion. + KNOWN_FAILING; + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1);} + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_KINGAMBIT); + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { SWITCH(opponent, 2); MOVE(player, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + MESSAGE("Go! Wobbuffet!"); + MESSAGE("2 sent out Kingambit!"); + ABILITY_POPUP(opponent, ABILITY_SUPREME_OVERLORD); + MESSAGE("Foe Kingambit gained strength from the fallen!"); + } +} diff --git a/test/battle/ability/sword_of_ruin.c b/test/battle/ability/sword_of_ruin.c index c6c1ffc4b2..329031f68d 100644 --- a/test/battle/ability/sword_of_ruin.c +++ b/test/battle/ability/sword_of_ruin.c @@ -29,3 +29,47 @@ SINGLE_BATTLE_TEST("Sword of Ruin reduces Defense if opposing mon's ability does EXPECT_MUL_EQ(damage[1], Q_4_12(1.33), damage[0]); } } + +SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battlers fainted - Player") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1);} + PLAYER(SPECIES_CHIEN_PAO); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_RUINATION); } + } SCENE { + HP_BAR(opponent, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + // Everyone faints. + MESSAGE("Go! Chien-Pao!"); + ABILITY_POPUP(player, ABILITY_SWORD_OF_RUIN); + MESSAGE("Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Sword of Ruin's message displays correctly after all battlers fainted - Opponent") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1);} + OPPONENT(SPECIES_CHIEN_PAO); + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_RUINATION); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + MESSAGE("Go! Wobbuffet!"); + MESSAGE("2 sent out Chien-Pao!"); + ABILITY_POPUP(opponent, ABILITY_SWORD_OF_RUIN); + MESSAGE("Foe Chien-Pao's Sword of Ruin weakened the Defense of all surrounding Pokémon!"); + } +} diff --git a/test/battle/ability/tablets_of_ruin.c b/test/battle/ability/tablets_of_ruin.c index d1f9cf3d2e..abdaab7563 100644 --- a/test/battle/ability/tablets_of_ruin.c +++ b/test/battle/ability/tablets_of_ruin.c @@ -29,3 +29,47 @@ SINGLE_BATTLE_TEST("Tablets of Ruin reduces Attack if opposing mon's ability doe EXPECT_MUL_EQ(damage[0], Q_4_12(1.33), damage[1]); } } + +SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battlers fainted - Player") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1);} + PLAYER(SPECIES_WO_CHIEN); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_RUINATION); } + } SCENE { + HP_BAR(opponent, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + // Everyone faints. + MESSAGE("Go! Wo-Chien!"); + ABILITY_POPUP(player, ABILITY_TABLETS_OF_RUIN); + MESSAGE("Wo-Chien's Tablets of Ruin weakened the Attack of all surrounding Pokémon!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Tablets of Ruin's message displays correctly after all battlers fainted - Opponent") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1);} + OPPONENT(SPECIES_WO_CHIEN); + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_RUINATION); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + MESSAGE("Go! Wobbuffet!"); + MESSAGE("2 sent out Wo-Chien!"); + ABILITY_POPUP(opponent, ABILITY_TABLETS_OF_RUIN); + MESSAGE("Foe Wo-Chien's Tablets of Ruin weakened the Attack of all surrounding Pokémon!"); + } +} diff --git a/test/battle/ability/tera_shell.c b/test/battle/ability/tera_shell.c new file mode 100644 index 0000000000..138a56f9b4 --- /dev/null +++ b/test/battle/ability/tera_shell.c @@ -0,0 +1,99 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Tera Shell makes all moves against Terapagos not very effective when at full HP") +{ + u16 hp; + PARAMETRIZE { hp = 100; } + PARAMETRIZE { hp = 99; } + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); HP(hp); MaxHP(100);} + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + } SCENE { + if (hp == 100) { + MESSAGE("Foe Wobbuffet used Tackle!"); + ABILITY_POPUP(player, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + HP_BAR(player); + MESSAGE("It's not very effective…"); + } + else { + NONE_OF { + ABILITY_POPUP(player, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + MESSAGE("It's not very effective…"); + } + } + } +} + +SINGLE_BATTLE_TEST("Tera Shell makes all hits of multi-hit moves against Terapagos not very effective") +{ + s16 firstHit; + s16 secondHit; + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_DOUBLE_HIT); } + } SCENE { + MESSAGE("Foe Wobbuffet used Double Hit!"); + ABILITY_POPUP(player, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, opponent); + HP_BAR(player, captureDamage: &firstHit); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_HIT, opponent); + HP_BAR(player, captureDamage: &secondHit); + MESSAGE("It's not very effective…"); + } THEN { + EXPECT_EQ(firstHit, secondHit); + } +} + +DOUBLE_BATTLE_TEST("Tera Shell only makes the first hit of a double battle turn not very effective") +{ + s16 firstHit; + s16 secondHit; + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_TACKLE, target: playerLeft); MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentLeft); + HP_BAR(playerLeft, captureDamage: &firstHit); + MESSAGE("It's not very effective…"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight); + HP_BAR(playerLeft, captureDamage: &secondHit); + NOT MESSAGE("It's not very effective…"); + } THEN { + EXPECT_MUL_EQ(firstHit, Q_4_12(2.0), secondHit); + } +} + +DOUBLE_BATTLE_TEST("Tera Shell only makes the first hit against Terapagos from a multi-target move not very effective") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_TERASTAL) { Ability(ABILITY_TERA_SHELL); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_BLIZZARD); } + } SCENE { + ABILITY_POPUP(playerLeft, ABILITY_TERA_SHELL); + MESSAGE("Terapagos made its shell gleam! It's distorting type matchups!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BLIZZARD, opponentLeft); + HP_BAR(playerLeft); + MESSAGE("It's not very effective…"); + HP_BAR(playerRight); + NOT MESSAGE("It's not very effective…"); + } +} diff --git a/test/battle/ability/tera_shift.c b/test/battle/ability/tera_shift.c new file mode 100644 index 0000000000..9149160cd1 --- /dev/null +++ b/test/battle/ability/tera_shift.c @@ -0,0 +1,35 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Tera Shift transforms Terapagos into its Terastal form on switch in") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_NORMAL) { Ability(ABILITY_TERA_SHIFT); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { ; } + } SCENE { + ABILITY_POPUP(player, ABILITY_TERA_SHIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Terapagos transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_TERAPAGOS_TERASTAL); + } +} + +SINGLE_BATTLE_TEST("Tera Shift can't be suppressed by Neutralizing Gas") +{ + GIVEN { + PLAYER(SPECIES_TERAPAGOS_NORMAL) { Ability(ABILITY_TERA_SHIFT); } + OPPONENT(SPECIES_KOFFING) { Ability(ABILITY_NEUTRALIZING_GAS); } + } WHEN { + TURN { ; } + } SCENE { + ABILITY_POPUP(opponent, ABILITY_NEUTRALIZING_GAS); + ABILITY_POPUP(player, ABILITY_TERA_SHIFT); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_FORM_CHANGE, player); + MESSAGE("Terapagos transformed!"); + } THEN { + EXPECT_EQ(player->species, SPECIES_TERAPAGOS_TERASTAL); + } +} diff --git a/test/battle/ability/vessel_of_ruin.c b/test/battle/ability/vessel_of_ruin.c index 4d369df691..ce8eae4dab 100644 --- a/test/battle/ability/vessel_of_ruin.c +++ b/test/battle/ability/vessel_of_ruin.c @@ -29,3 +29,47 @@ SINGLE_BATTLE_TEST("Vessel of Ruin reduces Sp. Atk if opposing mon's ability doe EXPECT_MUL_EQ(damage[0], Q_4_12(1.33), damage[1]); } } + +SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battlers fainted - Player") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET) { HP(1);} + PLAYER(SPECIES_TING_LU); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_RUINATION); } + } SCENE { + HP_BAR(opponent, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + // Everyone faints. + MESSAGE("Go! Ting-Lu!"); + ABILITY_POPUP(player, ABILITY_VESSEL_OF_RUIN); + MESSAGE("Ting-Lu's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Vessel of Ruin's message displays correctly after all battlers fainted - Opponent") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { HP(1);} + OPPONENT(SPECIES_TING_LU); + } WHEN { + TURN { MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_RUINATION); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + MESSAGE("Go! Wobbuffet!"); + MESSAGE("2 sent out Ting-Lu!"); + ABILITY_POPUP(opponent, ABILITY_VESSEL_OF_RUIN); + MESSAGE("Foe Ting-Lu's Vessel of Ruin weakened the Sp. Atk of all surrounding Pokémon!"); + } +} diff --git a/test/battle/ability/wind_power.c b/test/battle/ability/wind_power.c index bbf76cd6fb..146c47f3dd 100644 --- a/test/battle/ability/wind_power.c +++ b/test/battle/ability/wind_power.c @@ -167,12 +167,12 @@ DOUBLE_BATTLE_TEST("Wind Power activates correctly for every battler with the ab HP_BAR(playerLeft); if (abilityLeft == ABILITY_WIND_POWER) { ABILITY_POPUP(playerLeft, ABILITY_WIND_POWER); - MESSAGE("Being hit by PetalBlizzrd charged Wattrel with power!"); + MESSAGE("Being hit by Petal Blizzard charged Wattrel with power!"); } HP_BAR(playerRight); if (abilityRight == ABILITY_WIND_POWER) { ABILITY_POPUP(playerRight, ABILITY_WIND_POWER); - MESSAGE("Being hit by PetalBlizzrd charged Wattrel with power!"); + MESSAGE("Being hit by Petal Blizzard charged Wattrel with power!"); } HP_BAR(opponentRight); NOT HP_BAR(opponentLeft); diff --git a/test/battle/ability/zero_to_hero.c b/test/battle/ability/zero_to_hero.c index 4a186661a6..05914be5ee 100644 --- a/test/battle/ability/zero_to_hero.c +++ b/test/battle/ability/zero_to_hero.c @@ -20,7 +20,7 @@ SINGLE_BATTLE_TEST("Zero to Hero transforms Palafin when it switches out") } THEN { EXPECT_EQ(player->species, SPECIES_PALAFIN_HERO); } } -SINGLE_BATTLE_TEST("Zero to Hero can't be surpressed by Neutralizing Gas") +SINGLE_BATTLE_TEST("Zero to Hero can't be suppressed by Neutralizing Gas") { GIVEN { PLAYER(SPECIES_PALAFIN_ZERO) { Ability(ABILITY_ZERO_TO_HERO); } @@ -136,6 +136,52 @@ SINGLE_BATTLE_TEST("Imposter doesn't apply the heroic transformation message whe } THEN { EXPECT_EQ(player->species, SPECIES_PALAFIN_HERO); } } +SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers fainted - Player") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_PALAFIN_ZERO); + PLAYER(SPECIES_WOBBUFFET) { HP(1);} + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FLIP_TURN); SEND_OUT(player, 1); } + TURN { MOVE(opponent, MOVE_EXPLOSION); SEND_OUT(player, 0); SEND_OUT(opponent, 1); } + TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE); } + } SCENE { + HP_BAR(opponent, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, opponent); + // Everyone faints. + MESSAGE("Go! Palafin!"); + ABILITY_POPUP(player, ABILITY_ZERO_TO_HERO); + MESSAGE("Palafin underwent a heroic transformation!"); + MESSAGE("2 sent out Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Zero to Hero's message displays correctly after all battlers fainted - Opponent") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION); + PLAYER(SPECIES_WOBBUFFET); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_PALAFIN_ZERO); + OPPONENT(SPECIES_WOBBUFFET) { HP(1);} + } WHEN { + TURN { MOVE(opponent, MOVE_FLIP_TURN); SEND_OUT(opponent, 1); } + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_EXPLOSION); SEND_OUT(player, 1); SEND_OUT(opponent, 0); } + TURN { MOVE(opponent, MOVE_TACKLE); MOVE(player, MOVE_TACKLE); } + } SCENE { + HP_BAR(player, hp: 0); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, player); + // Everyone faints. + MESSAGE("Go! Wobbuffet!"); + MESSAGE("2 sent out Palafin!"); + ABILITY_POPUP(opponent, ABILITY_ZERO_TO_HERO); + MESSAGE("Foe Palafin underwent a heroic transformation!"); + } +} + // Write Trace test and move this one to that file (including every other ability that can't be copied) SINGLE_BATTLE_TEST("Zero to Hero cannot be copied by Trace") { diff --git a/test/battle/ai.c b/test/battle/ai.c index 0597925356..0d890da466 100644 --- a/test/battle/ai.c +++ b/test/battle/ai.c @@ -548,6 +548,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculati AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculation checks whether incoming damage is zero to avoid an infinite loop") { GIVEN { + ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); PLAYER(SPECIES_BULBASAUR) { Level(5); Moves(MOVE_SWORDS_DANCE, MOVE_WHIRLWIND, MOVE_SAND_ATTACK, MOVE_TAIL_WHIP); } // Scenario courtesy of Duke, who triggered the bug in the first place @@ -561,6 +562,23 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Number of hits to KO calculati } } +AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: Avoid infinite loop if damage taken is equal to recurring healing") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_LEFTOVERS].holdEffect == HOLD_EFFECT_LEFTOVERS); + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES); + PLAYER(SPECIES_MEOWTH_GALARIAN) { Level(100); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); } + // Scenario courtesy of Duke, who triggered the bug in the first place + OPPONENT(SPECIES_MEOWTH_GALARIAN) { Level(5); Moves(MOVE_GROWL, MOVE_FAKE_OUT, MOVE_HONE_CLAWS); } + OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); } + OPPONENT(SPECIES_GEODUDE) { Level(5); Moves(MOVE_DOUBLE_EDGE); } + OPPONENT(SPECIES_NOSEPASS) { Level(5); Moves(MOVE_DOUBLE_EDGE); } + OPPONENT(SPECIES_HOUNDSTONE) { Level(5); Moves(MOVE_NIGHT_SHADE, MOVE_BODY_PRESS, MOVE_WILL_O_WISP, MOVE_PROTECT); Item(ITEM_LEFTOVERS); } + } WHEN { + TURN { MOVE(player, MOVE_FAKE_OUT); EXPECT_MOVES(opponent, MOVE_FAKE_OUT); } + } +} + AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemon which is slower and gets 1HKOed after fainting") { bool32 alakazamFirst; diff --git a/test/battle/damage_formula.c b/test/battle/damage_formula.c index 2fdb9bed0f..d89fb7e7fd 100644 --- a/test/battle/damage_formula.c +++ b/test/battle/damage_formula.c @@ -109,7 +109,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Marshadow vs Mawile)") } } SCENE{ - MESSAGE("Marshadow used SpectrlThief!"); + MESSAGE("Marshadow used Spectral Thief!"); HP_BAR(opponent, captureDamage: &dmg); } THEN{ diff --git a/test/dynamax.c b/test/battle/gimmick/dynamax.c similarity index 99% rename from test/dynamax.c rename to test/battle/gimmick/dynamax.c index 2db55d87b6..a9ee2fe4d0 100644 --- a/test/dynamax.c +++ b/test/battle/gimmick/dynamax.c @@ -834,9 +834,9 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Mindstorm sets up Psychic Terrain") TURN { MOVE(opponent, MOVE_EXTREME_SPEED); MOVE(player, MOVE_PSYCHIC, dynamax: TRUE); } TURN { MOVE(opponent, MOVE_EXTREME_SPEED); MOVE(player, MOVE_PSYCHIC); } } SCENE { - MESSAGE("Foe Wobbuffet used ExtremeSpeed!"); + MESSAGE("Foe Wobbuffet used Extreme Speed!"); MESSAGE("Wobbuffet used Max Mindstorm!"); - MESSAGE("Foe Wobbuffet cannot use ExtremeSpeed!"); + MESSAGE("Foe Wobbuffet cannot use Extreme Speed!"); MESSAGE("Wobbuffet used Max Mindstorm!"); } } @@ -1347,7 +1347,7 @@ DOUBLE_BATTLE_TEST("(DYNAMAX) G-Max Centiferno traps both opponents in Fire Spin TURN { SWITCH(playerLeft, 2); } } SCENE { // turn 1 - MESSAGE("Centiskorc used G-Max Centiferno!"); + MESSAGE("Centiskorch used G-Max Centiferno!"); MESSAGE("Foe Wobbuffet is hurt by Fire Spin!"); HP_BAR(opponentLeft); MESSAGE("Foe Wynaut is hurt by Fire Spin!"); diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c new file mode 100644 index 0000000000..18eab992af --- /dev/null +++ b/test/battle/gimmick/terastal.c @@ -0,0 +1,794 @@ +#include "global.h" +#include "test/battle.h" + +// Base Power and STAB Checks + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into a different type preserves other STAB boosts", s16 damage1, s16 damage2) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_BULBASAUR) { TeraType(TYPE_NORMAL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_VINE_WHIP, tera: tera); } + TURN { MOVE(player, MOVE_SLUDGE_BOMB); } + } SCENE { + MESSAGE("Bulbasaur used Vine Whip!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_VINE_WHIP, player); + HP_BAR(opponent, captureDamage: &results[i].damage1); + MESSAGE("Bulbasaur used Sludge Bomb!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SLUDGE_BOMB, player); + HP_BAR(opponent, captureDamage: &results[i].damage2); + } FINALLY { + EXPECT_EQ(results[0].damage1, results[1].damage1); + EXPECT_EQ(results[0].damage2, results[1].damage2); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing does not affect the power of non-STAB moves", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_HEADBUTT, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Headbutt!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into a different type gives that type 1.5x STAB", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_NORMAL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_HEADBUTT, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Headbutt!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // The jump from no STAB to 1.5x STAB is a 1.5x boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into the same type gives that type 2x STAB", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_PSYCHIC, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Psychic!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHIC, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // The jump from 1.5x STAB to 2.0x STAB is a 1.33x boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.33), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into a different type with Adaptability gives 2.0x STAB", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_CRAWDAUNT) { Ability(ABILITY_ADAPTABILITY); TeraType(TYPE_NORMAL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_HEADBUTT, tera: tera); } + } SCENE { + MESSAGE("Crawdaunt used Headbutt!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEADBUTT, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // The jump from no STAB to 2.0x STAB is a 2.0x boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into the same type with Adaptability gives 2.25x STAB", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_CRAWDAUNT) { Ability(ABILITY_ADAPTABILITY); TeraType(TYPE_WATER); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_WATER_PULSE, tera: tera); } + } SCENE { + MESSAGE("Crawdaunt used Water Pulse!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_PULSE, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // The jump from 2x STAB to 2.25x STAB is a 1.125x boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.125), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing boosts moves of the same type to 60 BP", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + ASSUME(gMovesInfo[MOVE_ABSORB].power == 20); + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GRASS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ABSORB, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Absorb!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // The jump from 20 BP to 90 BP (60 * 1.5x) is a 4.5x boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(4.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor occurs after Technician", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + ASSUME(gMovesInfo[MOVE_MEGA_DRAIN].power == 40); + PLAYER(SPECIES_MR_MIME) { Ability(ABILITY_TECHNICIAN); TeraType(TYPE_GRASS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MEGA_DRAIN, tera: tera); } + } SCENE { + MESSAGE("Mr. Mime used Mega Drain!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_DRAIN, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // This should be the same as a normal Tera boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor occurs after Technician", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_MR_MIME) { Ability(ABILITY_TECHNICIAN); TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STORED_POWER, tera: tera); } + } SCENE { + MESSAGE("Mr. Mime used Stored Power!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STORED_POWER, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // The jump from 45 BP (20 * 1.5x * 1.5x) to 120 BP (60 * 2.0x) is a 2.667x boost. + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.667), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor does not apply to multi-hit moves", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_NORMAL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_FURY_SWIPES, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Fury Swipes!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_FURY_SWIPES, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor does not apply to priority moves", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_NORMAL); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_QUICK_ATTACK, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Quick Attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); + } +} + +// Defensive Type Checks + +SINGLE_BATTLE_TEST("(TERA) Terastallization changes type effectiveness", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GRASS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: tera); MOVE(opponent, MOVE_WATER_GUN); } + } SCENE { + MESSAGE("Foe Wobbuffet used Water Gun!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallization changes type effectiveness") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_FLYING); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: TRUE); MOVE(opponent, MOVE_EARTHQUAKE); } + } SCENE { + MESSAGE("Foe Wobbuffet used Earthquake!"); + MESSAGE("It doesn't affect Wobbuffet…"); + NOT { HP_BAR(player); } + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallization persists across switches") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_FLYING); } + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: TRUE); MOVE(opponent, MOVE_EARTHQUAKE); } + TURN { SWITCH(player, 1); } + TURN { SWITCH(player, 0); } + TURN { MOVE(opponent, MOVE_EARTHQUAKE); } + } SCENE { + // turn 1 + MESSAGE("Foe Wobbuffet used Earthquake!"); + MESSAGE("It doesn't affect Wobbuffet…"); + NOT { HP_BAR(player); } + // turn 4 + MESSAGE("Foe Wobbuffet used Earthquake!"); + MESSAGE("It doesn't affect Wobbuffet…"); + NOT { HP_BAR(player); } + } +} + +// Other Type Checks + +SINGLE_BATTLE_TEST("(TERA) Terastallization changes the effect of Curse") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GHOST); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CURSE, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Curse!"); + HP_BAR(player); + MESSAGE("Wobbuffet cut its own HP and laid a CURSE on Foe Wobbuffet!"); + NOT { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); } + } +} + +SINGLE_BATTLE_TEST("(TERA) Roost does not remove the user's Flying type while Terastallized") +{ + GIVEN { + PLAYER(SPECIES_ZAPDOS) { HP(1); TeraType(TYPE_FLYING); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ROOST, tera: TRUE); MOVE(opponent, MOVE_ICE_BEAM); } + } SCENE { + MESSAGE("Zapdos used Roost!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player); + MESSAGE("Foe Wobbuffet used Ice Beam!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_BEAM, opponent); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Type-changing moves fail against a Terastallized Pokemon") +{ + u16 move; + PARAMETRIZE { move = MOVE_SOAK; } + PARAMETRIZE { move = MOVE_FORESTS_CURSE; } + PARAMETRIZE { move = MOVE_TRICK_OR_TREAT; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: TRUE); MOVE(opponent, move); } + } SCENE { + if (move != MOVE_SOAK) + NOT { ANIMATION(ANIM_TYPE_MOVE, move, opponent); } + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Reflect Type fails if used by a Terastallized Pokemon") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_REFLECT_TYPE, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Reflect Type!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Conversion fails if used by a Terastallized Pokemon") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CONVERSION, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Conversion!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if used by a Terastallized Pokemon") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_PSYCHIC); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_TACKLE); } + TURN { MOVE(player, MOVE_CONVERSION_2, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Conversion 2!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Reflect Type copies a Terastallized Pokemon's Tera Type") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GHOST); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE, tera: TRUE); } + TURN { MOVE(opponent, MOVE_REFLECT_TYPE); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + // turn 2 + MESSAGE("Foe Wobbuffet used Reflect Type!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, opponent); + // turn 3 + MESSAGE("Wobbuffet used Tackle!"); + MESSAGE("It doesn't affect Foe Wobbuffet…"); + NOT { HP_BAR(opponent); } + } +} + +SINGLE_BATTLE_TEST("(TERA) Synchronoise uses a Terastallized Pokemon's Tera Type") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_GHOST); } + OPPONENT(SPECIES_WOBBUFFET) { TeraType(TYPE_GHOST); } + } WHEN { + TURN { MOVE(opponent, MOVE_SYNCHRONOISE); MOVE(player, MOVE_CELEBRATE, tera: TRUE); } + TURN { MOVE(opponent, MOVE_SYNCHRONOISE, tera: TRUE); } + } SCENE { + // turn 1 + MESSAGE("Foe Wobbuffet used Synchronoise!"); + MESSAGE("It had no effect on Wobbuffet!"); + // turn 2 + MESSAGE("Foe Wobbuffet used Synchronoise!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_SYNCHRONOISE, opponent); + } +} + +SINGLE_BATTLE_TEST("(TERA) Revelation Dance uses a Terastallized Pokemon's Tera Type") +{ + GIVEN { + ASSUME(P_GEN_7_POKEMON); + PLAYER(SPECIES_ORICORIO) { TeraType(TYPE_NORMAL); } + OPPONENT(SPECIES_GENGAR); + } WHEN { + TURN { MOVE(player, MOVE_REVELATION_DANCE, tera: TRUE); } + } SCENE { + MESSAGE("Oricorio used Revelation Dance!"); + MESSAGE("It doesn't affect Foe Gengar…"); + NOT { HP_BAR(opponent); } + } +} + +// This tests that Tera STAB modifiers depend on the user's original types, too. +SINGLE_BATTLE_TEST("(TERA) Double Shock does not remove the user's Electric type while Terastallized, and changes STAB modifier depending on when it is used") +{ + s16 damage[4]; + GIVEN { + ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + PLAYER(SPECIES_PICHU) { TeraType(TYPE_ELECTRIC); } + PLAYER(SPECIES_WOBBUFFET) + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_DOUBLE_SHOCK, tera: TRUE); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); MOVE(opponent, MOVE_RECOVER); } + TURN { SWITCH(player, 1); MOVE(opponent, MOVE_RECOVER); } + TURN { SWITCH(player, 0); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } + } SCENE { + // turn 1 - regular STAB + MESSAGE("Pichu used Double Shock!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 2 - lost Electric type, gained back from Tera + MESSAGE("Pichu used Double Shock!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + HP_BAR(opponent, captureDamage: &damage[1]); + // turn 3 - retained Electric type + MESSAGE("Pichu used Double Shock!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + // turn 6 - original type reset, regular STAB + Tera boost + MESSAGE("Pichu used Double Shock!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + HP_BAR(opponent, captureDamage: &damage[2]); + // turn 7 - regular STAB + Tera boost stays + MESSAGE("Pichu used Double Shock!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + HP_BAR(opponent, captureDamage: &damage[3]); + } THEN { + EXPECT_EQ(damage[0], damage[1]); + EXPECT_MUL_EQ(damage[0], Q_4_12(1.333), damage[2]); + EXPECT_EQ(damage[2], damage[3]); + } +} + +SINGLE_BATTLE_TEST("(TERA) Transform does not copy the target's Tera Type, and if the user is Terastallized it keeps its own Tera Type") +{ + KNOWN_FAILING; // Transform seems to be bugged in tests. + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_TACKLE, MOVE_EARTHQUAKE); TeraType(TYPE_GHOST); } + OPPONENT(SPECIES_DITTO) { TeraType(TYPE_FLYING); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: TRUE); MOVE(opponent, MOVE_TRANSFORM); } + TURN { MOVE(player, MOVE_EARTHQUAKE); } + // TURN { MOVE(player, MOVE_TACKLE); MOVE(opponent, MOVE_TACKLE, target: player, tera: TRUE); } + } SCENE { + // turn 2 + MESSAGE("Wobbuffet used Earthquake!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, player); + HP_BAR(opponent); + // turn 3 + MESSAGE("Wobbuffet used Tackle!"); + MESSAGE("It doesn't affect Ditto…"); + NOT { HP_BAR(opponent); } + } +} + +// Stellar Type checks +SINGLE_BATTLE_TEST("(TERA) Stellar type does not change the user's defensive profile", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: tera); MOVE(opponent, MOVE_PSYCHIC); } + } SCENE { + MESSAGE("Foe Wobbuffet used Psychic!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_PSYCHIC, opponent); + HP_BAR(player, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_EQ(results[0].damage, results[1].damage); + } +} + +SINGLE_BATTLE_TEST("(TERA) Reflect Type copies a Stellar-type Pokemon's base type") +{ + GIVEN { + PLAYER(SPECIES_BANETTE) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player, MOVE_CELEBRATE, tera: TRUE); } + TURN { MOVE(opponent, MOVE_REFLECT_TYPE); } + TURN { MOVE(player, MOVE_TACKLE); } + } SCENE { + // turn 2 + MESSAGE("Foe Wobbuffet used Reflect Type!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, opponent); + // turn 3 + MESSAGE("Banette used Tackle!"); + MESSAGE("It doesn't affect Foe Wobbuffet…"); + NOT { HP_BAR(opponent); } + } +} + +SINGLE_BATTLE_TEST("(TERA) Revelation Dance uses a Stellar-type Pokemon's base type") +{ + GIVEN { + ASSUME(P_GEN_7_POKEMON); + PLAYER(SPECIES_ORICORIO_SENSU) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_GUMSHOOS); + } WHEN { + TURN { MOVE(player, MOVE_REVELATION_DANCE, tera: TRUE); } + } SCENE { + MESSAGE("Oricorio used Revelation Dance!"); + MESSAGE("It doesn't affect Foe Gumshoos…"); + NOT { HP_BAR(opponent); } + } +} + +SINGLE_BATTLE_TEST("(TERA) Conversion2 fails if last hit by a Stellar-type move") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); } + TURN { MOVE(opponent, MOVE_CONVERSION_2); } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + // turn 2 + MESSAGE("Foe Wobbuffet used Conversion 2!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Roost does not remove Flying-type ground immunity when Terastallized into the Stellar type") +{ + GIVEN { + PLAYER(SPECIES_ZAPDOS) { HP(1); TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_ROOST, tera: TRUE); MOVE(opponent, MOVE_ICE_BEAM); } + } SCENE { + MESSAGE("Zapdos used Roost!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ROOST, player); + MESSAGE("Foe Wobbuffet used Ice Beam!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_ICE_BEAM, opponent); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar-type provides a one-time 2.0x boost to STAB moves") +{ + s16 damage[3]; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_EXTRASENSORY); } + TURN { MOVE(player, MOVE_EXTRASENSORY, tera: TRUE); } + TURN { MOVE(player, MOVE_EXTRASENSORY); } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Extrasensory!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXTRASENSORY, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 2 + MESSAGE("Wobbuffet used Extrasensory!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXTRASENSORY, player); + HP_BAR(opponent, captureDamage: &damage[1]); + // turn 3 + MESSAGE("Wobbuffet used Extrasensory!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_EXTRASENSORY, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + // Extrasensory goes from a 50% boost to a 100% boost for a 1.33x total multiplier + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.33), damage[1]); + EXPECT_EQ(damage[0], damage[2]); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar-type provides a one-time 1.2x boost to non-STAB moves") +{ + s16 damage[3]; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TAKE_DOWN); } + TURN { MOVE(player, MOVE_TAKE_DOWN, tera: TRUE); } + TURN { MOVE(player, MOVE_TAKE_DOWN); } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 2 + MESSAGE("Wobbuffet used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[1]); + // turn 3 + MESSAGE("Wobbuffet used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.2), damage[1]); + EXPECT_EQ(damage[0], damage[2]); + } +} + +SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves up to 60 BP once per type") +{ + s16 damage[4]; + GIVEN { + ASSUME(gMovesInfo[MOVE_MEGA_DRAIN].power == 40); + ASSUME(gMovesInfo[MOVE_BUBBLE].power == 40); + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_MEGA_DRAIN); } + TURN { MOVE(player, MOVE_MEGA_DRAIN, tera: TRUE); } + TURN { MOVE(player, MOVE_MEGA_DRAIN); } + TURN { MOVE(player, MOVE_BUBBLE); } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Mega Drain!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_DRAIN, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 2 + MESSAGE("Wobbuffet used Mega Drain!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_DRAIN, player); + HP_BAR(opponent, captureDamage: &damage[1]); + // turn 3 + MESSAGE("Wobbuffet used Mega Drain!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_DRAIN, player); + HP_BAR(opponent, captureDamage: &damage[2]); + // turn 4 + MESSAGE("Wobbuffet used Bubble!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_BUBBLE, player); + HP_BAR(opponent, captureDamage: &damage[3]); + } THEN { + // The jump from 40 BP to 72 BP (60 * 1.2x) is a 1.8x boost. + EXPECT_MUL_EQ(damage[0], Q_4_12(1.8), damage[1]); + EXPECT_EQ(damage[0], damage[2]); + EXPECT_EQ(damage[1], damage[3]); + } +} + +SINGLE_BATTLE_TEST("(TERA) Protean cannot change the type of a Terastallized Pokemon") +{ + GIVEN { + PLAYER(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); TeraType(TYPE_GRASS); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BUBBLE, tera: TRUE); + MOVE(opponent, MOVE_EMBER); } + } SCENE { + MESSAGE("Greninja used Bubble!"); + MESSAGE("Foe Wobbuffet used Ember!"); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("(TERA) Status moves don't expend Stellar's one-time type boost") +{ + s16 damage[2]; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_GROWL, tera: TRUE); } + TURN { MOVE(player, MOVE_TAKE_DOWN); } + TURN { MOVE(player, MOVE_TAKE_DOWN); } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Growl!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_GROWL, player); + // turn 2 + MESSAGE("Wobbuffet used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 3 + MESSAGE("Wobbuffet used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[1]); + } THEN { + EXPECT_MUL_EQ(damage[1], UQ_4_12(1.20), damage[0]); + } +} + +SINGLE_BATTLE_TEST("(TERA) Stellar type's one-time boost factors in dynamically-typed moves") +{ + s16 damage[4]; + GIVEN { + ASSUME(gMovesInfo[MOVE_WEATHER_BALL].type == TYPE_NORMAL); + PLAYER(SPECIES_PELIPPER) { Ability(ABILITY_DRIZZLE); TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_WEATHER_BALL, tera: TRUE); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_TAKE_DOWN); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_TAKE_DOWN); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_WATER_PULSE); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_WATER_PULSE); MOVE(opponent, MOVE_RECOVER); } + } SCENE { + MESSAGE("Pelipper used Weather Ball!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WEATHER_BALL, player); + // turn 2 + MESSAGE("Pelipper used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 3 + MESSAGE("Pelipper used Take Down!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAKE_DOWN, player); + HP_BAR(opponent, captureDamage: &damage[1]); + // turn 4 + MESSAGE("Pelipper used Water Pulse!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_PULSE, player); + HP_BAR(opponent, captureDamage: &damage[2]); + // turn 5 + MESSAGE("Pelipper used Water Pulse!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_PULSE, player); + HP_BAR(opponent, captureDamage: &damage[3]); + } THEN { + // Take Down should have a Normal type boost applied + EXPECT_MUL_EQ(damage[1], UQ_4_12(1.20), damage[0]); + // Water Pulse should not have a Water type boost applied + EXPECT_EQ(damage[3], damage[2]); + } +} + +SINGLE_BATTLE_TEST("(TERA) All type indicators function correctly") +{ + u32 type; + PARAMETRIZE { type = TYPE_NORMAL; } + PARAMETRIZE { type = TYPE_FIGHTING; } + PARAMETRIZE { type = TYPE_FLYING; } + PARAMETRIZE { type = TYPE_POISON; } + PARAMETRIZE { type = TYPE_GROUND; } + PARAMETRIZE { type = TYPE_ROCK; } + PARAMETRIZE { type = TYPE_BUG; } + PARAMETRIZE { type = TYPE_GHOST; } + PARAMETRIZE { type = TYPE_STEEL; } + PARAMETRIZE { type = TYPE_MYSTERY; } + PARAMETRIZE { type = TYPE_FIRE; } + PARAMETRIZE { type = TYPE_WATER; } + PARAMETRIZE { type = TYPE_GRASS; } + PARAMETRIZE { type = TYPE_ELECTRIC; } + PARAMETRIZE { type = TYPE_PSYCHIC; } + PARAMETRIZE { type = TYPE_ICE; } + PARAMETRIZE { type = TYPE_DRAGON; } + PARAMETRIZE { type = TYPE_DARK; } + PARAMETRIZE { type = TYPE_FAIRY; } + PARAMETRIZE { type = TYPE_STELLAR; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(type); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, tera: TRUE); } + } +} diff --git a/test/battle/hold_effect/eject_pack.c b/test/battle/hold_effect/eject_pack.c index 1a54d5a2e9..7640292079 100644 --- a/test/battle/hold_effect/eject_pack.c +++ b/test/battle/hold_effect/eject_pack.c @@ -6,7 +6,7 @@ ASSUMPTIONS ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK); } -SINGLE_BATTLE_TEST("Eject Pack does not cause the new pokemon to lose hp due to it's held Life Orb") +SINGLE_BATTLE_TEST("Eject Pack does not cause the new Pokémon to lose HP due to it's held Life Orb") { GIVEN { ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); @@ -22,10 +22,11 @@ SINGLE_BATTLE_TEST("Eject Pack does not cause the new pokemon to lose hp due to MESSAGE("Wobbuffet is switched out with the Eject Pack!"); MESSAGE("Go! Wynaut!"); NOT MESSAGE("Wynaut was hurt by its Life Orb!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); } } -SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no pokemon left to battle") +SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no Pokémon left to battle") { GIVEN { PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); } @@ -41,3 +42,24 @@ SINGLE_BATTLE_TEST("Eject Pack does not activate if there are no pokemon left to } } } + +SINGLE_BATTLE_TEST("Eject Pack is triggered by self-inflicting stat decreases") +{ + GIVEN { + ASSUME(gItemsInfo[ITEM_LIFE_ORB].holdEffect == HOLD_EFFECT_LIFE_ORB); + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); } + PLAYER(SPECIES_WYNAUT); + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); } + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_OVERHEAT); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_OVERHEAT, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet is switched out with the Eject Pack!"); + MESSAGE("Go! Wynaut!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + } +} diff --git a/test/battle/hold_effect/red_card.c b/test/battle/hold_effect/red_card.c index ce4ac80b96..8d7e175cea 100644 --- a/test/battle/hold_effect/red_card.c +++ b/test/battle/hold_effect/red_card.c @@ -447,4 +447,25 @@ SINGLE_BATTLE_TEST("Red Card does not cause the dragged out mon to lose hp due t } } +SINGLE_BATTLE_TEST("Red Card does not activate if holder is switched in mid-turn") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_RED_CARD); } + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_ENDURE); MOVE(opponent, MOVE_TACKLE); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet is switched out with the Eject Button!"); + NONE_OF { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Wobbuffet held up its Red Card against Foe Wobbuffet!"); + } + } +} + // SINGLE_BATTLE_TEST("Red Card activates but fails if the attacker has Dynamaxed") diff --git a/test/battle/hold_effect/white_herb.c b/test/battle/hold_effect/restore_stats.c similarity index 100% rename from test/battle/hold_effect/white_herb.c rename to test/battle/hold_effect/restore_stats.c diff --git a/test/battle/hold_effect/safety_goggles.c b/test/battle/hold_effect/safety_goggles.c index b20f19e0a5..4c5c6a2965 100644 --- a/test/battle/hold_effect/safety_goggles.c +++ b/test/battle/hold_effect/safety_goggles.c @@ -16,7 +16,7 @@ SINGLE_BATTLE_TEST("Safety Goggles block powder and spore moves") TURN { MOVE(player, MOVE_STUN_SPORE); } } SCENE { NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player); - MESSAGE("Foe Abra is not affected thanks to its SafetyGoggles!"); + MESSAGE("Foe Abra is not affected thanks to its Safety Goggles!"); } } diff --git a/test/battle/item_effect/increase_stat.c b/test/battle/item_effect/increase_stat.c index df36b8ff33..4eba548961 100644 --- a/test/battle/item_effect/increase_stat.c +++ b/test/battle/item_effect/increase_stat.c @@ -63,7 +63,7 @@ SINGLE_BATTLE_TEST("X Sp. Atk sharply raises battler's Sp. Attack stat", s16 dam if (useItem) TURN { USE_ITEM(player, ITEM_X_SP_ATK); } TURN { MOVE(player, MOVE_DISARMING_VOICE); } } SCENE { - MESSAGE("Wobbuffet used DisrmngVoice!"); + MESSAGE("Wobbuffet used Disarming Voice!"); HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { if (B_X_ITEMS_BUFF >= GEN_7) @@ -87,7 +87,7 @@ SINGLE_BATTLE_TEST("X Sp. Def sharply raises battler's Sp. Defense stat", s16 da if (useItem) TURN { USE_ITEM(player, ITEM_X_SP_DEF); } TURN { MOVE(opponent, MOVE_DISARMING_VOICE); } } SCENE { - MESSAGE("Foe Wobbuffet used DisrmngVoice!"); + MESSAGE("Foe Wobbuffet used Disarming Voice!"); HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { if (B_X_ITEMS_BUFF >= GEN_7) @@ -205,7 +205,7 @@ SINGLE_BATTLE_TEST("Max Mushrooms raises battler's Sp. Attack stat", s16 damage) if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } TURN { MOVE(player, MOVE_DISARMING_VOICE); } } SCENE { - MESSAGE("Wobbuffet used DisrmngVoice!"); + MESSAGE("Wobbuffet used Disarming Voice!"); HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); @@ -225,7 +225,7 @@ SINGLE_BATTLE_TEST("Max Mushrooms battler's Sp. Defense stat", s16 damage) if (useItem) TURN { USE_ITEM(player, ITEM_MAX_MUSHROOMS); } TURN { MOVE(opponent, MOVE_DISARMING_VOICE); } } SCENE { - MESSAGE("Foe Wobbuffet used DisrmngVoice!"); + MESSAGE("Foe Wobbuffet used Disarming Voice!"); HP_BAR(player, captureDamage: &results[i].damage); } FINALLY { EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.66), results[1].damage); diff --git a/test/battle/move_effect/burn_up.c b/test/battle/move_effect/burn_up.c deleted file mode 100644 index 46b26a49a0..0000000000 --- a/test/battle/move_effect/burn_up.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); - ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); - ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); -} - -SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type") -{ - GIVEN { - PLAYER(SPECIES_CYNDAQUIL); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_BURN_UP); } - TURN { MOVE(player, MOVE_BURN_UP); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); - MESSAGE("Cyndaquil burned itself out!"); - MESSAGE("Cyndaquil used Burn Up!"); - MESSAGE("But it failed!"); - } -} - -SINGLE_BATTLE_TEST("Burn Up fails if the user isn't a Fire-type") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_BURN_UP); } - } SCENE { - NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); } - MESSAGE("Wobbuffet used Burn Up!"); - MESSAGE("But it failed!"); - } -} - -SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type if enemy faints") -{ - GIVEN { - PLAYER(SPECIES_CYNDAQUIL); - OPPONENT(SPECIES_WOBBUFFET) { HP(1); } - } WHEN { - TURN { MOVE(player, MOVE_BURN_UP); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); - HP_BAR(opponent, hp: 0); - MESSAGE("Cyndaquil burned itself out!"); - } -} diff --git a/test/battle/move_effect/techno_blast.c b/test/battle/move_effect/change_type_on_item.c similarity index 100% rename from test/battle/move_effect/techno_blast.c rename to test/battle/move_effect/change_type_on_item.c diff --git a/test/battle/move_effect/corrosive_gas.c b/test/battle/move_effect/corrosive_gas.c index c2c921cf74..714702703a 100644 --- a/test/battle/move_effect/corrosive_gas.c +++ b/test/battle/move_effect/corrosive_gas.c @@ -19,7 +19,7 @@ SINGLE_BATTLE_TEST("Corrosive Gas destroys the target's item or fails if the tar } WHEN { TURN { MOVE(player, MOVE_CORROSIVE_GAS); } } SCENE { - MESSAGE("Wobbuffet used CorrosiveGas!"); + MESSAGE("Wobbuffet used Corrosive Gas!"); if (item == ITEM_POTION) { ANIMATION(ANIM_TYPE_MOVE, MOVE_CORROSIVE_GAS, player); MESSAGE("Wobbuffet corroded Foe Wobbuffet's Potion!"); @@ -40,11 +40,11 @@ SINGLE_BATTLE_TEST("Corrosive Gas doesn't destroy the item of a Pokemon with the } WHEN { TURN { MOVE(player, MOVE_CORROSIVE_GAS); } } SCENE { - MESSAGE("Wobbuffet used CorrosiveGas!"); + MESSAGE("Wobbuffet used Corrosive Gas!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_CORROSIVE_GAS, player); NOT MESSAGE("Wobbuffet corroded Foe Wobbuffet's Potion!"); ABILITY_POPUP(opponent, ABILITY_STICKY_HOLD); - MESSAGE("Foe Muk's Sticky Hold made CorrosiveGas ineffective!"); + MESSAGE("Foe Muk's Sticky Hold made Corrosive Gas ineffective!"); } THEN { EXPECT_EQ(opponent->item, ITEM_POISON_BARB); } @@ -59,7 +59,7 @@ SINGLE_BATTLE_TEST("Items lost to Corrosive Gas cannot be restored by Recycle") } WHEN { TURN { MOVE(player, MOVE_CORROSIVE_GAS); MOVE(opponent, MOVE_RECYCLE); } } SCENE { - MESSAGE("Wobbuffet used CorrosiveGas!"); + MESSAGE("Wobbuffet used Corrosive Gas!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_CORROSIVE_GAS, player); MESSAGE("Wobbuffet corroded Foe Wobbuffet's Oran Berry!"); MESSAGE("Foe Wobbuffet used Recycle!"); @@ -93,7 +93,7 @@ DOUBLE_BATTLE_TEST("Corrosive Gas destroys foes and ally's items if they have on } WHEN { TURN { MOVE(playerRight, MOVE_CORROSIVE_GAS); } } SCENE { - MESSAGE("Wynaut used CorrosiveGas!"); + MESSAGE("Wynaut used Corrosive Gas!"); if (itemPlayerLeft == ITEM_CHERI_BERRY) { MESSAGE("Wynaut corroded Wobbuffet's Cheri Berry!"); } else { diff --git a/test/battle/move_effect/curse.c b/test/battle/move_effect/curse.c new file mode 100644 index 0000000000..5fe17d3561 --- /dev/null +++ b/test/battle/move_effect/curse.c @@ -0,0 +1,36 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_CURSE].effect == EFFECT_CURSE); +} + +SINGLE_BATTLE_TEST("Curse lowers Speed, raises Attack, and raises Defense when used by non-Ghost-types") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CURSE); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CURSE, player); + MESSAGE("Wobbuffet's Speed fell!"); + MESSAGE("Wobbuffet's Attack rose!"); + MESSAGE("Wobbuffet's Defense rose!"); + } +} + +SINGLE_BATTLE_TEST("Curse cuts the user's HP in half when used by Ghost-types") +{ + GIVEN { + PLAYER(SPECIES_MISDREAVUS); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CURSE); } + } SCENE { + s32 maxHP = GetMonData(&PLAYER_PARTY[0], MON_DATA_MAX_HP); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CURSE, player); + HP_BAR(player, hp: maxHP / 2); + } +} diff --git a/test/battle/move_effect/double_shock.c b/test/battle/move_effect/double_shock.c deleted file mode 100644 index b7f59a3ab7..0000000000 --- a/test/battle/move_effect/double_shock.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); - ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); - ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); - ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); -} - -SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type") -{ - GIVEN { - PLAYER(SPECIES_PIKACHU); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } - TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); - MESSAGE("Pikachu used up all of its electricity!"); - MESSAGE("Pikachu used Double Shock!"); - MESSAGE("But it failed!"); - } -} - -SINGLE_BATTLE_TEST("Double Shock fails if the user isn't an Electric-type") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } - } SCENE { - NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); } - MESSAGE("Wobbuffet used Double Shock!"); - MESSAGE("But it failed!"); - } -} - -SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type if enemy faints") -{ - GIVEN { - PLAYER(SPECIES_PIKACHU); - OPPONENT(SPECIES_WOBBUFFET) { HP(1); } - } WHEN { - TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); - HP_BAR(opponent, hp: 0); - MESSAGE("Pikachu used up all of its electricity!"); - } -} diff --git a/test/battle/move_effect/embargo.c b/test/battle/move_effect/embargo.c index 8d9cc9c86d..0d69496efc 100644 --- a/test/battle/move_effect/embargo.c +++ b/test/battle/move_effect/embargo.c @@ -352,7 +352,7 @@ SINGLE_BATTLE_TEST("Embargo doesn't prevent Mega Evolution") ANIMATION(ANIM_TYPE_MOVE, MOVE_BATON_PASS, opponent); MESSAGE("2 sent out Charizard!"); // Turn 3 - MESSAGE("Foe Charizard's CharizarditeY is reacting to 2's Mega Ring!"); + MESSAGE("Foe Charizard's Charizardite Y is reacting to 2's Mega Ring!"); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_MEGA_EVOLUTION, opponent); MESSAGE("Foe Charizard has Mega Evolved into Mega Charizard!"); } diff --git a/test/battle/move_effect/fail_if_not_arg_type.c b/test/battle/move_effect/fail_if_not_arg_type.c new file mode 100644 index 0000000000..4ffe0a0323 --- /dev/null +++ b/test/battle/move_effect/fail_if_not_arg_type.c @@ -0,0 +1,112 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); + ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); + PLAYER(SPECIES_CYNDAQUIL); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BURN_UP); } + TURN { MOVE(player, MOVE_BURN_UP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); + MESSAGE("Cyndaquil burned itself out!"); + MESSAGE("Cyndaquil used Burn Up!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("Burn Up fails if the user isn't a Fire-type") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BURN_UP); } + } SCENE { + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); } + MESSAGE("Wobbuffet used Burn Up!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("Burn Up user loses its Fire-type if enemy faints") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_BURN_UP].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_BURN_UP, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_FIRE) == TRUE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_FIRE || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_FIRE); + ASSUME(gSpeciesInfo[SPECIES_CYNDAQUIL].types[0] == TYPE_FIRE || gSpeciesInfo[SPECIES_CYNDAQUIL].types[1] == TYPE_FIRE); + PLAYER(SPECIES_CYNDAQUIL); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + } WHEN { + TURN { MOVE(player, MOVE_BURN_UP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player); + HP_BAR(opponent, hp: 0); + MESSAGE("Cyndaquil burned itself out!"); + } +} + +SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); + ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); + PLAYER(SPECIES_PIKACHU); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + MESSAGE("Pikachu used up all of its electricity!"); + MESSAGE("Pikachu used Double Shock!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("Double Shock fails if the user isn't an Electric-type") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } + } SCENE { + NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); } + MESSAGE("Wobbuffet used Double Shock!"); + MESSAGE("But it failed!"); + } +} + +SINGLE_BATTLE_TEST("Double Shock user loses its Electric-type if enemy faints") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_DOUBLE_SHOCK].effect == EFFECT_FAIL_IF_NOT_ARG_TYPE); + ASSUME(MoveHasAdditionalEffectSelfArg(MOVE_DOUBLE_SHOCK, MOVE_EFFECT_REMOVE_ARG_TYPE, TYPE_ELECTRIC) == TRUE); + ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] != TYPE_ELECTRIC || gSpeciesInfo[SPECIES_WOBBUFFET].types[1] != TYPE_ELECTRIC); + ASSUME(gSpeciesInfo[SPECIES_PIKACHU].types[0] == TYPE_ELECTRIC || gSpeciesInfo[SPECIES_PIKACHU].types[1] == TYPE_ELECTRIC); + PLAYER(SPECIES_PIKACHU); + OPPONENT(SPECIES_WOBBUFFET) { HP(1); } + } WHEN { + TURN { MOVE(player, MOVE_DOUBLE_SHOCK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_SHOCK, player); + HP_BAR(opponent, hp: 0); + MESSAGE("Pikachu used up all of its electricity!"); + } +} diff --git a/test/battle/move_effect/fling.c b/test/battle/move_effect/fling.c index f6b83215a1..b4b25484b3 100644 --- a/test/battle/move_effect/fling.c +++ b/test/battle/move_effect/fling.c @@ -114,7 +114,7 @@ SINGLE_BATTLE_TEST("Fling - Item is lost even when there is no target") TURN { MOVE(opponent, MOVE_SELF_DESTRUCT); MOVE(player, MOVE_FLING); SEND_OUT(opponent, 1); } TURN { MOVE(player, MOVE_FLING); } } SCENE { - MESSAGE("Foe Wobbuffet used SelfDestruct!"); + MESSAGE("Foe Wobbuffet used Self-Destruct!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_SELF_DESTRUCT, opponent); HP_BAR(player); MESSAGE("Foe Wobbuffet fainted!"); diff --git a/test/battle/ability/gastro_acid.c b/test/battle/move_effect/gastro_acid.c similarity index 96% rename from test/battle/ability/gastro_acid.c rename to test/battle/move_effect/gastro_acid.c index a9fba14f89..2f5b04dab9 100644 --- a/test/battle/ability/gastro_acid.c +++ b/test/battle/move_effect/gastro_acid.c @@ -23,7 +23,7 @@ SINGLE_BATTLE_TEST("Gastro Acid fails if target has a banned ability") PARAMETRIZE { species = SPECIES_CRAMORANT; ability = ABILITY_GULP_MISSILE; } PARAMETRIZE { species = SPECIES_PALAFIN_ZERO; ability = ABILITY_ZERO_TO_HERO; } PARAMETRIZE { species = SPECIES_TATSUGIRI; ability = ABILITY_COMMANDER; } - // Needs confirmation since those abilities can be surpressed by Neutralizing Gas + // Needs confirmation since those abilities can be suppressed by Neutralizing Gas // PARAMETRIZE { species = SPECIES_IRON_MOTH; ability = ABILITY_QUARK_DRIVE; } // PARAMETRIZE { species = SPECIES_WALKING_WAKE; ability = ABILITY_PROTOSYNTHESIS; } PARAMETRIZE { species = SPECIES_CALYREX_SHADOW_RIDER; ability = ABILITY_AS_ONE_SHADOW_RIDER; } diff --git a/test/battle/move_effect/hex.c b/test/battle/move_effect/hex.c deleted file mode 100644 index 25660d7309..0000000000 --- a/test/battle/move_effect/hex.c +++ /dev/null @@ -1,34 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(gMovesInfo[MOVE_HEX].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_HEX].argument == STATUS1_ANY); -} - -SINGLE_BATTLE_TEST("Hex deals double damage to foes with a status", s16 damage) -{ - u32 status1; - PARAMETRIZE { status1 = STATUS1_NONE; } - PARAMETRIZE { status1 = STATUS1_SLEEP; } - PARAMETRIZE { status1 = STATUS1_POISON; } - PARAMETRIZE { status1 = STATUS1_BURN; } - PARAMETRIZE { status1 = STATUS1_FREEZE; } - PARAMETRIZE { status1 = STATUS1_PARALYSIS; } - PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } - } WHEN { - TURN { MOVE(player, MOVE_HEX); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_HEX, player); - HP_BAR(opponent, captureDamage: &results[i].damage); - } THEN { - if (i > 0) - EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[i].damage); - if (i > 1) - EXPECT_EQ(results[i-1].damage, results[i].damage); - } -} diff --git a/test/battle/move_effect/hit_set_entry_hazardss.c b/test/battle/move_effect/hit_set_entry_hazardss.c deleted file mode 100644 index fa405ed3b3..0000000000 --- a/test/battle/move_effect/hit_set_entry_hazardss.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(MoveHasAdditionalEffect(MOVE_STONE_AXE, MOVE_EFFECT_STEALTH_ROCK) == TRUE); - ASSUME(MoveHasAdditionalEffect(MOVE_CEASELESS_EDGE, MOVE_EFFECT_SPIKES) == TRUE); -} - -SINGLE_BATTLE_TEST("Stone Axe / Ceaseless Edge set up hazards after hitting the target") -{ - u16 move; - PARAMETRIZE { move = MOVE_STONE_AXE; } - PARAMETRIZE { move = MOVE_CEASELESS_EDGE; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - } WHEN { - TURN { MOVE(player, move); } - TURN { SWITCH(opponent, 1); } - } SCENE { - s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); - ANIMATION(ANIM_TYPE_MOVE, move, player); - HP_BAR(opponent); - if (move == MOVE_CEASELESS_EDGE) { - MESSAGE("Spikes were scattered all around the opposing team!"); - } - else { - MESSAGE("Pointed stones float in the air around the opposing team!"); - } - MESSAGE("2 sent out Wobbuffet!"); - if (move == MOVE_CEASELESS_EDGE) { - HP_BAR(opponent, damage: maxHP / 8); - MESSAGE("Foe Wobbuffet is hurt by spikes!"); - } - else { - HP_BAR(opponent, damage: maxHP / 8); - MESSAGE("Pointed stones dug into Foe Wobbuffet!"); - } - } -} - -SINGLE_BATTLE_TEST("Ceaseless Edge can set up to 3 layers of Spikes") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT); - } WHEN { - TURN { MOVE(player, MOVE_CEASELESS_EDGE); } - TURN { MOVE(player, MOVE_CEASELESS_EDGE); } - TURN { MOVE(player, MOVE_CEASELESS_EDGE); } - TURN { MOVE(player, MOVE_CEASELESS_EDGE); } - TURN { SWITCH(opponent, 1); } - } SCENE { - s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); - HP_BAR(opponent); - MESSAGE("Spikes were scattered all around the opposing team!"); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); - HP_BAR(opponent); - MESSAGE("Spikes were scattered all around the opposing team!"); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); - HP_BAR(opponent); - MESSAGE("Spikes were scattered all around the opposing team!"); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); - HP_BAR(opponent); - NOT MESSAGE("Spikes were scattered all around the opposing team!"); - - MESSAGE("2 sent out Wynaut!"); - HP_BAR(opponent, damage: maxHP / 4); - MESSAGE("Foe Wynaut is hurt by spikes!"); - } -} - -SINGLE_BATTLE_TEST("Stone Axe can set up pointed stones only once") -{ - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WYNAUT); - } WHEN { - TURN { MOVE(player, MOVE_STONE_AXE); } - TURN { MOVE(player, MOVE_STONE_AXE); } - TURN { MOVE(player, MOVE_STONE_AXE); } - TURN { MOVE(player, MOVE_STONE_AXE); } - TURN { SWITCH(opponent, 1); } - } SCENE { - s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); - HP_BAR(opponent); - MESSAGE("Pointed stones float in the air around the opposing team!"); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); - HP_BAR(opponent); - NOT MESSAGE("Pointed stones float in the air around the opposing team!"); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); - HP_BAR(opponent); - NOT MESSAGE("Pointed stones float in the air around the opposing team!"); - - ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); - HP_BAR(opponent); - NOT MESSAGE("Pointed stones float in the air around the opposing team!"); - - MESSAGE("2 sent out Wynaut!"); - HP_BAR(opponent, damage: maxHP / 8); - MESSAGE("Pointed stones dug into Foe Wynaut!"); - } -} - diff --git a/test/battle/move_effect/hit_set_remove_terrain.c b/test/battle/move_effect/hit_set_remove_terrain.c index 834b2dc223..549b6bf04f 100644 --- a/test/battle/move_effect/hit_set_remove_terrain.c +++ b/test/battle/move_effect/hit_set_remove_terrain.c @@ -82,3 +82,45 @@ SINGLE_BATTLE_TEST("Ice Spinner doesn't fail if there is no terrain on the field NOT MESSAGE("But it failed!"); } } + +AI_SINGLE_BATTLE_TEST("Steel Roller will not be chosen by the AI if it might fail") +{ + u32 move; + + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_NONE; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_STEEL_ROLLER, MOVE_ICE_SHARD); } + } WHEN { + if (move == MOVE_ELECTRIC_TERRAIN) { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } + TURN { EXPECT_MOVE(opponent, MOVE_STEEL_ROLLER); } + } else { + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SHARD); } + } + } +} + +AI_SINGLE_BATTLE_TEST("Ice Spinner can be chosen by the AI regardless if there is a terrain or not") +{ + u32 move; + + PARAMETRIZE { move = MOVE_ELECTRIC_TERRAIN; } + PARAMETRIZE { move = MOVE_NONE; } + + GIVEN { + AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_ICE_SPINNER, MOVE_ICE_SHARD); } + } WHEN { + if (move == MOVE_ELECTRIC_TERRAIN) { + TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + } else { + TURN { EXPECT_MOVE(opponent, MOVE_ICE_SPINNER); } + } + } +} diff --git a/test/battle/move_effect/knock_off.c b/test/battle/move_effect/knock_off.c index 177e3b18c1..49e5c499d3 100644 --- a/test/battle/move_effect/knock_off.c +++ b/test/battle/move_effect/knock_off.c @@ -43,8 +43,8 @@ SINGLE_BATTLE_TEST("Knock Off activates after Rocky Helmet and Weakness Policy") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); if (item == ITEM_WEAKNESS_POLICY) { ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE); - MESSAGE("Using WeaknssPolicy, the Attack of Foe Wobbuffet sharply rose!"); - MESSAGE("Using WeaknssPolicy, the Sp. Atk of Foe Wobbuffet sharply rose!"); + MESSAGE("Using Weakness Policy, the Attack of Foe Wobbuffet sharply rose!"); + MESSAGE("Using Weakness Policy, the Sp. Atk of Foe Wobbuffet sharply rose!"); } else if (item == ITEM_ROCKY_HELMET) { HP_BAR(player); MESSAGE("Wobbuffet was hurt by Foe Wobbuffet's Rocky Helmet!"); diff --git a/test/battle/move_effect/metronome.c b/test/battle/move_effect/metronome.c index d4efcaafff..22e3390cb2 100644 --- a/test/battle/move_effect/metronome.c +++ b/test/battle/move_effect/metronome.c @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Metronome's called powder move fails against Grass Types") } SCENE { MESSAGE("Wobbuffet used Metronome!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_METRONOME, player); - MESSAGE("Wobbuffet used PoisonPowder!"); + MESSAGE("Wobbuffet used Poison Powder!"); NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_POISON_POWDER, player); MESSAGE("It doesn't affect Foe Tangela…"); NOT STATUS_ICON(opponent, poison: TRUE); diff --git a/test/battle/move_effect/quash.c b/test/battle/move_effect/quash.c new file mode 100644 index 0000000000..fd2bd9d877 --- /dev/null +++ b/test/battle/move_effect/quash.c @@ -0,0 +1,45 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_QUASH].effect == EFFECT_QUASH); +} + +DOUBLE_BATTLE_TEST("Quash-affected target will move last in the priority bracket") +{ + GIVEN { + PLAYER(SPECIES_VOLBEAT) { Speed(10); Ability(ABILITY_PRANKSTER); } + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_TORCHIC) { Speed(20); } + OPPONENT(SPECIES_TREECKO) { Speed(40); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_QUASH, target: opponentRight); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight); + } +} + +DOUBLE_BATTLE_TEST("Quash is not affected by dynamic speed") +{ + GIVEN { + ASSUME(B_RECALC_TURN_AFTER_ACTIONS >= GEN_8); + ASSUME(gMovesInfo[MOVE_TAILWIND].effect == EFFECT_TAILWIND); + PLAYER(SPECIES_VOLBEAT) { Speed(10); Ability(ABILITY_PRANKSTER); } + PLAYER(SPECIES_WOBBUFFET) { Speed(30); } + OPPONENT(SPECIES_TORCHIC) { Speed(50); } + OPPONENT(SPECIES_TREECKO) { Speed(40); } + } WHEN { + TURN { MOVE(playerLeft, MOVE_QUASH, target: opponentRight); + MOVE(opponentLeft, MOVE_TAILWIND); + } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUASH, playerLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TAILWIND, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, playerRight); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponentRight); + } +} diff --git a/test/battle/move_effect/reflect_type.c b/test/battle/move_effect/reflect_type.c index e873516034..b75ffc0b0d 100644 --- a/test/battle/move_effect/reflect_type.c +++ b/test/battle/move_effect/reflect_type.c @@ -171,7 +171,7 @@ SINGLE_BATTLE_TEST("Reflect Type defaults to Normal type for the user's type1 an HP_BAR(player); MESSAGE("Foe Arcanine burned itself out!"); // Turn 2 - MESSAGE("Wobbuffet used Forest'sCurs!"); + MESSAGE("Wobbuffet used Forest's Curse!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESTS_CURSE, player); MESSAGE("Grass type was added to Foe Arcanine!"); // Turn 3 diff --git a/test/battle/move_effect/revival_blessing.c b/test/battle/move_effect/revival_blessing.c index 397e01e73a..d44e9110d5 100644 --- a/test/battle/move_effect/revival_blessing.c +++ b/test/battle/move_effect/revival_blessing.c @@ -5,12 +5,6 @@ // behaviors. These have been tested in-game, in double, in multi, and in link battles. AI will always // revive their first fainted party member in order. -#if B_EXPANDED_MOVE_NAMES -#define REVIVAL_BLESSING "Revival Blessing" -#else -#define REVIVAL_BLESSING "RevivlBlesng" -#endif - ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING); @@ -26,7 +20,7 @@ SINGLE_BATTLE_TEST("Revival Blessing revives a chosen fainted party member for t } WHEN { TURN { MOVE(player, MOVE_REVIVAL_BLESSING); SEND_OUT(player, 2); } } SCENE { - MESSAGE("Wobbuffet used " REVIVAL_BLESSING "!"); + MESSAGE("Wobbuffet used Revival Blessing!"); MESSAGE("Wynaut was revived and is ready to fight again!"); } } @@ -41,7 +35,7 @@ SINGLE_BATTLE_TEST("Revival Blessing revives a fainted party member for an oppon } WHEN { TURN { MOVE(opponent, MOVE_REVIVAL_BLESSING); SEND_OUT(opponent, 1); } } SCENE { - MESSAGE("Foe Raichu used " REVIVAL_BLESSING "!"); + MESSAGE("Foe Raichu used Revival Blessing!"); MESSAGE("Pichu was revived and is ready to fight again!"); } } @@ -54,7 +48,7 @@ SINGLE_BATTLE_TEST("Revival Blessing fails if no party members are fainted") } WHEN { TURN { MOVE(player, MOVE_REVIVAL_BLESSING); } } SCENE { - MESSAGE("Wobbuffet used " REVIVAL_BLESSING "!"); + MESSAGE("Wobbuffet used Revival Blessing!"); MESSAGE("But it failed!"); } } @@ -82,10 +76,10 @@ TO_DO_BATTLE_TEST("Revival Blessing cannot revive a partner's party member"); // TURN { MOVE(user, MOVE_REVIVAL_BLESSING); } // } SCENE { // if (user == opponentLeft) { -// MESSAGE("Foe Wobbuffet used " REVIVAL_BLESSING "!"); +// MESSAGE("Foe Wobbuffet used Revival Blessing!"); // MESSAGE("But it failed!"); // } else { -// MESSAGE("Foe Wynaut used " REVIVAL_BLESSING "!"); +// MESSAGE("Foe Wynaut used Revival Blessing!"); // MESSAGE("Wynaut was revived and is ready to fight again!"); // } // } @@ -108,7 +102,7 @@ TO_DO_BATTLE_TEST("Revived battlers still lose their turn"); // } SCENE { // MESSAGE("Wobbuffet used Tackle!"); // MESSAGE("Foe Wynaut fainted!"); -// MESSAGE("Foe Wobbuffet used " REVIVAL_BLESSING "!"); +// MESSAGE("Foe Wobbuffet used Revival Blessing!"); // MESSAGE("Wynaut was revived and is ready to fight again!"); // NOT { MESSAGE("Wynaut used Celebrate!"); } // } diff --git a/test/battle/ability/role_play.c b/test/battle/move_effect/role_play.c similarity index 100% rename from test/battle/ability/role_play.c rename to test/battle/move_effect/role_play.c diff --git a/test/battle/move_effect/semi_invulnerable_moves.c b/test/battle/move_effect/semi_invulnerable.c similarity index 97% rename from test/battle/move_effect/semi_invulnerable_moves.c rename to test/battle/move_effect/semi_invulnerable.c index 97760225d1..3ba4889005 100644 --- a/test/battle/move_effect/semi_invulnerable_moves.c +++ b/test/battle/move_effect/semi_invulnerable.c @@ -58,7 +58,7 @@ SINGLE_BATTLE_TEST("Semi-invulnerable moves make the user semi-invulnerable turn break; case MOVE_PHANTOM_FORCE: NOT MESSAGE("Wobbuffet vanished instantly!"); - MESSAGE("Wobbuffet used PhantomForce!"); + MESSAGE("Wobbuffet used Phantom Force!"); break; case MOVE_SHADOW_FORCE: NOT MESSAGE("Wobbuffet vanished instantly!"); @@ -112,7 +112,7 @@ SINGLE_BATTLE_TEST("Semi-invulnerable moves make the user semi-invulnerable turn MESSAGE("Wobbuffet used Dive!"); break; case MOVE_PHANTOM_FORCE: - MESSAGE("Wobbuffet used PhantomForce!"); + MESSAGE("Wobbuffet used Phantom Force!"); break; case MOVE_SHADOW_FORCE: MESSAGE("Wobbuffet used Shadow Force!"); @@ -163,7 +163,7 @@ SINGLE_BATTLE_TEST("Semi-invulnerable moves don't need to charge with Power Herb break; case MOVE_PHANTOM_FORCE: NOT MESSAGE("Wobbuffet vanished instantly!"); - MESSAGE("Wobbuffet used PhantomForce!"); + MESSAGE("Wobbuffet used Phantom Force!"); break; case MOVE_SHADOW_FORCE: NOT MESSAGE("Wobbuffet vanished instantly!"); @@ -215,7 +215,7 @@ SINGLE_BATTLE_TEST("Semi-invulnerable moves don't need to charge with Power Herb MESSAGE("Wobbuffet used Dive!"); break; case MOVE_PHANTOM_FORCE: - MESSAGE("Wobbuffet used PhantomForce!"); + MESSAGE("Wobbuffet used Phantom Force!"); break; case MOVE_SHADOW_FORCE: MESSAGE("Wobbuffet used Shadow Force!"); diff --git a/test/battle/move_effect/spit_up.c b/test/battle/move_effect/spit_up.c new file mode 100644 index 0000000000..1291962e1f --- /dev/null +++ b/test/battle/move_effect/spit_up.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +// Go to test/battle/move_effect/stockpile.c for Spit Up's tests diff --git a/test/battle/move_effect/stealth_rock.c b/test/battle/move_effect/stealth_rock.c index 23a773f8e8..f8c7a6369e 100644 --- a/test/battle/move_effect/stealth_rock.c +++ b/test/battle/move_effect/stealth_rock.c @@ -30,3 +30,46 @@ SINGLE_BATTLE_TEST("Stealth Rock damage on switch in based on typing") HP_BAR(opponent, damage: maxHP / divisor); } } + +SINGLE_BATTLE_TEST("Stealth Rock damages the correct pokemon when Eject Button is triggered") +{ + GIVEN { + PLAYER(SPECIES_METAPOD) { Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_METAPOD); + OPPONENT(SPECIES_JOLTEON); + } WHEN { + TURN { MOVE(opponent, MOVE_STEALTH_ROCK); MOVE(player, MOVE_HARDEN); } + TURN { MOVE(opponent, MOVE_QUICK_ATTACK); MOVE(player, MOVE_HARDEN); SEND_OUT(player, 1); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponent); + ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponent); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player); + MESSAGE("Go! Metapod!"); + HP_BAR(player); + } THEN { + EXPECT_EQ(opponent->hp, opponent->maxHP); + } +} + +DOUBLE_BATTLE_TEST("Stealth Rock damages the correct pokemon when Eject Button is triggered in double battle") +{ + GIVEN { + PLAYER(SPECIES_METAPOD) { Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_METAPOD) { Item(ITEM_EJECT_BUTTON); } + PLAYER(SPECIES_METAPOD); + OPPONENT(SPECIES_JOLTEON); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponentLeft, MOVE_STEALTH_ROCK); MOVE(opponentRight, MOVE_TACKLE, target: playerLeft); SEND_OUT(playerLeft, 2); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_STEALTH_ROCK, opponentLeft); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponentRight); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft); + MESSAGE("Go! Metapod!"); + HP_BAR(playerLeft); + } THEN { + EXPECT_EQ(opponentLeft->hp, opponentLeft->maxHP); + } +} diff --git a/test/battle/move_effect/sticky_web.c b/test/battle/move_effect/sticky_web.c index 6c6f8f156c..e3c96ca2fa 100644 --- a/test/battle/move_effect/sticky_web.c +++ b/test/battle/move_effect/sticky_web.c @@ -123,8 +123,8 @@ DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - the ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, BATTLER_PLAYER); MESSAGE("A sticky web spreads out on the ground around the opposing team!"); - MESSAGE("Go! Corviknigh!"); - MESSAGE("Corviknigh was caught in a Sticky Web!"); + MESSAGE("Go! Corviknight!"); + MESSAGE("Corviknight was caught in a Sticky Web!"); ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, BATTLER_OPPONENT); if (opponentSetUpper == 0) { @@ -170,8 +170,8 @@ DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no o MESSAGE("A sticky web spreads out on the ground around the opposing team!"); } - MESSAGE("Go! Corviknigh!"); - MESSAGE("Corviknigh was caught in a Sticky Web!"); + MESSAGE("Go! Corviknight!"); + MESSAGE("Corviknight was caught in a Sticky Web!"); ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); } THEN { @@ -219,8 +219,8 @@ DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no o MESSAGE("2 sent out Pidgey!"); } - MESSAGE("Go! Corviknigh!"); - MESSAGE("Corviknigh was caught in a Sticky Web!"); + MESSAGE("Go! Corviknight!"); + MESSAGE("Corviknight was caught in a Sticky Web!"); ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR); NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft); } THEN { diff --git a/test/battle/move_effect/swallow.c b/test/battle/move_effect/swallow.c new file mode 100644 index 0000000000..bce0a4470c --- /dev/null +++ b/test/battle/move_effect/swallow.c @@ -0,0 +1,4 @@ +#include "global.h" +#include "test/battle.h" + +// Go to test/battle/move_effect/stockpile.c for Swallow's tests diff --git a/test/battle/move_effect/tera_blast.c b/test/battle/move_effect/tera_blast.c new file mode 100644 index 0000000000..4592cf32a5 --- /dev/null +++ b/test/battle/move_effect/tera_blast.c @@ -0,0 +1,137 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(gMovesInfo[MOVE_TERA_BLAST].effect == EFFECT_TERA_BLAST); +} + +SINGLE_BATTLE_TEST("Tera Blast changes from Normal-type to the user's Tera Type") +{ + GIVEN { + ASSUME(gMovesInfo[MOVE_TERA_BLAST].type == TYPE_NORMAL); + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_DARK); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Tera Blast becomes a physical move if the user is Terastallized and has a higher Attack stat", s16 damage) +{ + bool32 tera; + PARAMETRIZE { tera = FALSE; } + PARAMETRIZE { tera = TRUE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_NORMAL); Attack(100); SpAttack(50); } + OPPONENT(SPECIES_WOBBUFFET) { Defense(200); SpDefense(200); } + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: tera); } + } SCENE { + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + // Since Wobbuffett has equal defenses, Tera Blast should do 1.5x more damage + // from gaining STAB and an additional 2.0x damage from using its highest + // attacking stat. + EXPECT_MUL_EQ(results[0].damage, UQ_4_12(3.0), results[1].damage); + } +} + +SINGLE_BATTLE_TEST("Stellar-type Tera Blast lowers both offensive stats") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); + MESSAGE("Wobbuffet's Attack fell!"); + MESSAGE("Wobbuffet's Sp. Atk fell!"); + } +} + + +SINGLE_BATTLE_TEST("Stellar-type Tera Blast has 100 BP and a one-time 1.2x boost") +{ + s16 damage[3]; + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST); MOVE(opponent, MOVE_RECOVER); } + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); } + TURN { MOVE(player, MOVE_WORK_UP); } + TURN { MOVE(player, MOVE_TERA_BLAST); } + } SCENE { + // turn 1 + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + HP_BAR(opponent, captureDamage: &damage[0]); + // turn 2 + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + HP_BAR(opponent, captureDamage: &damage[1]); + // turn 4 + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + HP_BAR(opponent, captureDamage: &damage[2]); + } THEN { + // 80 BP to 120 BP (100 * 1.2) boost upon Terastallizing + EXPECT_MUL_EQ(damage[0], UQ_4_12(1.50), damage[1]); + // 120 BP to 100 BP after Stellar boost expended + EXPECT_MUL_EQ(damage[2], UQ_4_12(1.20), damage[1]); + } +} + +SINGLE_BATTLE_TEST("Stellar-type Tera Blast is super-effective on Stellar-type Pokemon") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); MOVE(opponent, MOVE_CELEBRATE, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + MESSAGE("It's super effective!"); + } +} + +SINGLE_BATTLE_TEST("Stellar-type Tera Blast activates a Stellar-type Pokemon's Weakness Policy") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); } + OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_WEAKNESS_POLICY); TeraType(TYPE_NORMAL); } + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); MOVE(opponent, MOVE_CELEBRATE, tera: TRUE); } + } SCENE { + MESSAGE("Wobbuffet used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + MESSAGE("It's super effective!"); + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent); + } +} + +SINGLE_BATTLE_TEST("Flying-type Tera Blast does not have its priority boosted by Gale Wings") +{ + GIVEN { + PLAYER(SPECIES_TALONFLAME) { Ability(ABILITY_GALE_WINGS); TeraType(TYPE_FLYING); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_TERA_BLAST, tera: TRUE); MOVE(opponent, MOVE_QUICK_ATTACK); } + } SCENE { + MESSAGE("Foe Wobbuffet used Quick Attack!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_QUICK_ATTACK, opponent); + MESSAGE("Talonflame used Tera Blast!"); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TERA_BLAST, player); + } +} diff --git a/test/battle/move_effect/two_turn_moves.c b/test/battle/move_effect/two_turns_attack.c similarity index 100% rename from test/battle/move_effect/two_turn_moves.c rename to test/battle/move_effect/two_turns_attack.c diff --git a/test/battle/move_effect/venoshock.c b/test/battle/move_effect/venoshock.c deleted file mode 100644 index feea48df10..0000000000 --- a/test/battle/move_effect/venoshock.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -ASSUMPTIONS -{ - ASSUME(gMovesInfo[MOVE_VENOSHOCK].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); - ASSUME(gMovesInfo[MOVE_VENOSHOCK].argument == STATUS1_PSN_ANY); -} - -SINGLE_BATTLE_TEST("Venoshock's power doubles if the target is poisoned/badly poisoned", s16 damage) -{ - u32 status1; - PARAMETRIZE { status1 = 0; } - PARAMETRIZE { status1 = STATUS1_POISON; } - PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } - GIVEN { - PLAYER(SPECIES_WOBBUFFET); - OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } - } WHEN { - TURN { MOVE(player, MOVE_VENOSHOCK); } - } SCENE { - ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOSHOCK, player); - HP_BAR(opponent, captureDamage: &results[i].damage); - } FINALLY { - EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); - EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[2].damage); - } -} diff --git a/test/battle/move_effect/bug_bite.c b/test/battle/move_effect_secondary/bug_bite.c similarity index 100% rename from test/battle/move_effect/bug_bite.c rename to test/battle/move_effect_secondary/bug_bite.c diff --git a/test/battle/move_effect/burn_hit.c b/test/battle/move_effect_secondary/burn.c similarity index 100% rename from test/battle/move_effect/burn_hit.c rename to test/battle/move_effect_secondary/burn.c diff --git a/test/battle/move_effect/confusion_hit.c b/test/battle/move_effect_secondary/confusion.c similarity index 100% rename from test/battle/move_effect/confusion_hit.c rename to test/battle/move_effect_secondary/confusion.c diff --git a/test/battle/move_effect/clanging_scales.c b/test/battle/move_effect_secondary/def_minus_1.c similarity index 100% rename from test/battle/move_effect/clanging_scales.c rename to test/battle/move_effect_secondary/def_minus_1.c diff --git a/test/battle/move_effect/dire_claw.c b/test/battle/move_effect_secondary/dire_claw.c similarity index 100% rename from test/battle/move_effect/dire_claw.c rename to test/battle/move_effect_secondary/dire_claw.c diff --git a/test/battle/move_effect_secondary/double_power_on_arg_status.c b/test/battle/move_effect_secondary/double_power_on_arg_status.c new file mode 100644 index 0000000000..d147264470 --- /dev/null +++ b/test/battle/move_effect_secondary/double_power_on_arg_status.c @@ -0,0 +1,52 @@ +#include "global.h" +#include "test/battle.h" + +SINGLE_BATTLE_TEST("Hex deals double damage to foes with a status", s16 damage) +{ + u32 status1; + PARAMETRIZE { status1 = STATUS1_NONE; } + PARAMETRIZE { status1 = STATUS1_SLEEP; } + PARAMETRIZE { status1 = STATUS1_POISON; } + PARAMETRIZE { status1 = STATUS1_BURN; } + PARAMETRIZE { status1 = STATUS1_FREEZE; } + PARAMETRIZE { status1 = STATUS1_PARALYSIS; } + PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } + GIVEN { + ASSUME(gMovesInfo[MOVE_HEX].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(gMovesInfo[MOVE_HEX].argument == STATUS1_ANY); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } + } WHEN { + TURN { MOVE(player, MOVE_HEX); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HEX, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } THEN { + if (i > 0) + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[i].damage); + if (i > 1) + EXPECT_EQ(results[i-1].damage, results[i].damage); + } +} + +SINGLE_BATTLE_TEST("Venoshock's power doubles if the target is poisoned/badly poisoned", s16 damage) +{ + u32 status1; + PARAMETRIZE { status1 = 0; } + PARAMETRIZE { status1 = STATUS1_POISON; } + PARAMETRIZE { status1 = STATUS1_TOXIC_POISON; } + GIVEN { + ASSUME(gMovesInfo[MOVE_VENOSHOCK].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); + ASSUME(gMovesInfo[MOVE_VENOSHOCK].argument == STATUS1_PSN_ANY); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET) { Status1(status1); } + } WHEN { + TURN { MOVE(player, MOVE_VENOSHOCK); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_VENOSHOCK, player); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[1].damage); + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.0), results[2].damage); + } +} diff --git a/test/battle/move_effect/flinch_hit.c b/test/battle/move_effect_secondary/flinch.c similarity index 100% rename from test/battle/move_effect/flinch_hit.c rename to test/battle/move_effect_secondary/flinch.c diff --git a/test/battle/move_effect/freeze_hit.c b/test/battle/move_effect_secondary/freeze.c similarity index 100% rename from test/battle/move_effect/freeze_hit.c rename to test/battle/move_effect_secondary/freeze.c diff --git a/test/battle/move_effect/paralyze_hit.c b/test/battle/move_effect_secondary/paralysis.c similarity index 100% rename from test/battle/move_effect/paralyze_hit.c rename to test/battle/move_effect_secondary/paralysis.c diff --git a/test/battle/move_effect/pay_day.c b/test/battle/move_effect_secondary/pay_day.c similarity index 100% rename from test/battle/move_effect/pay_day.c rename to test/battle/move_effect_secondary/pay_day.c diff --git a/test/battle/move_effect/poison_hit.c b/test/battle/move_effect_secondary/poison.c similarity index 86% rename from test/battle/move_effect/poison_hit.c rename to test/battle/move_effect_secondary/poison.c index f7f46df4f9..63b2816bfd 100644 --- a/test/battle/move_effect/poison_hit.c +++ b/test/battle/move_effect_secondary/poison.c @@ -1,15 +1,10 @@ #include "global.h" #include "test/battle.h" -ASSUMPTIONS -{ - ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE); - ASSUME(MoveHasAdditionalEffect(MOVE_TWINEEDLE, MOVE_EFFECT_POISON) == TRUE); -} - SINGLE_BATTLE_TEST("Poison Sting inflicts poison") { GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_POISON_STING, MOVE_EFFECT_POISON) == TRUE); PLAYER(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET); } WHEN { @@ -29,6 +24,7 @@ SINGLE_BATTLE_TEST("Poison cannot be inflicted on Poison and Steel-type Pokémon PARAMETRIZE { mon = SPECIES_NIDORAN_M; } PARAMETRIZE { mon = SPECIES_REGISTEEL; } GIVEN { + ASSUME(MoveHasAdditionalEffect(MOVE_TWINEEDLE, MOVE_EFFECT_POISON) == TRUE); ASSUME(gSpeciesInfo[SPECIES_NIDORAN_M].types[0] == TYPE_POISON); ASSUME(gSpeciesInfo[SPECIES_REGISTEEL].types[0] == TYPE_STEEL); PLAYER(SPECIES_WOBBUFFET); diff --git a/test/battle/move_effect/psychic_noise.c b/test/battle/move_effect_secondary/psychic_noise.c similarity index 97% rename from test/battle/move_effect/psychic_noise.c rename to test/battle/move_effect_secondary/psychic_noise.c index 7846157b77..e8d50dc961 100644 --- a/test/battle/move_effect/psychic_noise.c +++ b/test/battle/move_effect_secondary/psychic_noise.c @@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Psychic Noise is blocked by Soundproof") TURN { MOVE(player, MOVE_PSYCHIC_NOISE); MOVE(opponent, MOVE_RECOVER); } } SCENE { ABILITY_POPUP(opponent, ABILITY_SOUNDPROOF); - MESSAGE("Foe Voltorb's Soundproof blocks PsychicNoise!"); + MESSAGE("Foe Voltorb's Soundproof blocks Psychic Noise!"); ANIMATION(ANIM_TYPE_MOVE, MOVE_RECOVER, opponent); } } diff --git a/test/battle/move_effect/rapid_spin.c b/test/battle/move_effect_secondary/rapid_spin.c similarity index 100% rename from test/battle/move_effect/rapid_spin.c rename to test/battle/move_effect_secondary/rapid_spin.c diff --git a/test/battle/move_effect/sp_atk_two_down.c b/test/battle/move_effect_secondary/sp_atk_two_down.c similarity index 100% rename from test/battle/move_effect/sp_atk_two_down.c rename to test/battle/move_effect_secondary/sp_atk_two_down.c diff --git a/test/battle/move_effect/spin_out.c b/test/battle/move_effect_secondary/spd_minus_2.c similarity index 100% rename from test/battle/move_effect/spin_out.c rename to test/battle/move_effect_secondary/spd_minus_2.c diff --git a/test/battle/move_effect_secondary/spikes.c b/test/battle/move_effect_secondary/spikes.c new file mode 100644 index 0000000000..b9c72930c2 --- /dev/null +++ b/test/battle/move_effect_secondary/spikes.c @@ -0,0 +1,64 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_CEASELESS_EDGE, MOVE_EFFECT_SPIKES) == TRUE); +} + +SINGLE_BATTLE_TEST("Ceaseless Edge sets up hazards after hitting the target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CEASELESS_EDGE); } + TURN { SWITCH(opponent, 1); } + } SCENE { + s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); + HP_BAR(opponent); + MESSAGE("Spikes were scattered all around the opposing team!"); + MESSAGE("2 sent out Wobbuffet!"); + HP_BAR(opponent, damage: maxHP / 8); + MESSAGE("Foe Wobbuffet is hurt by spikes!"); + } +} + +SINGLE_BATTLE_TEST("Ceaseless Edge can set up to 3 layers of Spikes") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_CEASELESS_EDGE); } + TURN { MOVE(player, MOVE_CEASELESS_EDGE); } + TURN { MOVE(player, MOVE_CEASELESS_EDGE); } + TURN { MOVE(player, MOVE_CEASELESS_EDGE); } + TURN { SWITCH(opponent, 1); } + } SCENE { + s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); + HP_BAR(opponent); + MESSAGE("Spikes were scattered all around the opposing team!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); + HP_BAR(opponent); + MESSAGE("Spikes were scattered all around the opposing team!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); + HP_BAR(opponent); + MESSAGE("Spikes were scattered all around the opposing team!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_CEASELESS_EDGE, player); + HP_BAR(opponent); + NOT MESSAGE("Spikes were scattered all around the opposing team!"); + + MESSAGE("2 sent out Wynaut!"); + HP_BAR(opponent, damage: maxHP / 4); + MESSAGE("Foe Wynaut is hurt by spikes!"); + } +} diff --git a/test/battle/move_effect_secondary/stealth_rock.c b/test/battle/move_effect_secondary/stealth_rock.c new file mode 100644 index 0000000000..034e2c347b --- /dev/null +++ b/test/battle/move_effect_secondary/stealth_rock.c @@ -0,0 +1,65 @@ +#include "global.h" +#include "test/battle.h" + +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_STONE_AXE, MOVE_EFFECT_STEALTH_ROCK) == TRUE); +} + +SINGLE_BATTLE_TEST("Stone Axe sets up hazards after hitting the target") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_STONE_AXE); } + TURN { SWITCH(opponent, 1); } + } SCENE { + s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); + ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); + HP_BAR(opponent); + MESSAGE("Pointed stones float in the air around the opposing team!"); + MESSAGE("2 sent out Wobbuffet!"); + HP_BAR(opponent, damage: maxHP / 8); + MESSAGE("Pointed stones dug into Foe Wobbuffet!"); + } +} + +SINGLE_BATTLE_TEST("Stone Axe can set up pointed stones only once") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WYNAUT); + } WHEN { + TURN { MOVE(player, MOVE_STONE_AXE); } + TURN { MOVE(player, MOVE_STONE_AXE); } + TURN { MOVE(player, MOVE_STONE_AXE); } + TURN { MOVE(player, MOVE_STONE_AXE); } + TURN { SWITCH(opponent, 1); } + } SCENE { + s32 maxHP = GetMonData(&OPPONENT_PARTY[1], MON_DATA_MAX_HP); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); + HP_BAR(opponent); + MESSAGE("Pointed stones float in the air around the opposing team!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); + HP_BAR(opponent); + NOT MESSAGE("Pointed stones float in the air around the opposing team!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); + HP_BAR(opponent); + NOT MESSAGE("Pointed stones float in the air around the opposing team!"); + + ANIMATION(ANIM_TYPE_MOVE, MOVE_STONE_AXE, player); + HP_BAR(opponent); + NOT MESSAGE("Pointed stones float in the air around the opposing team!"); + + MESSAGE("2 sent out Wynaut!"); + HP_BAR(opponent, damage: maxHP / 8); + MESSAGE("Pointed stones dug into Foe Wynaut!"); + } +} + diff --git a/test/battle/move_effect/syrup_bomb.c b/test/battle/move_effect_secondary/syrup_bomb.c similarity index 98% rename from test/battle/move_effect/syrup_bomb.c rename to test/battle/move_effect_secondary/syrup_bomb.c index 57831abb55..1e6d613721 100644 --- a/test/battle/move_effect/syrup_bomb.c +++ b/test/battle/move_effect_secondary/syrup_bomb.c @@ -1,6 +1,11 @@ #include "global.h" #include "test/battle.h" +ASSUMPTIONS +{ + ASSUME(MoveHasAdditionalEffect(MOVE_SYRUP_BOMB, MOVE_EFFECT_SYRUP_BOMB) == TRUE); +} + SINGLE_BATTLE_TEST("Syrup Bomb covers the foe in sticky syrup for 3 turns") { u8 j; diff --git a/test/battle/move_effect/rampage.c b/test/battle/move_effect_secondary/thrash.c similarity index 100% rename from test/battle/move_effect/rampage.c rename to test/battle/move_effect_secondary/thrash.c diff --git a/test/battle/move_effect/throat_chop.c b/test/battle/move_effect_secondary/throat_chop.c similarity index 100% rename from test/battle/move_effect/throat_chop.c rename to test/battle/move_effect_secondary/throat_chop.c diff --git a/test/battle/move_effect/jaw_lock.c b/test/battle/move_effect_secondary/trap_both.c similarity index 100% rename from test/battle/move_effect/jaw_lock.c rename to test/battle/move_effect_secondary/trap_both.c diff --git a/test/battle/move_effect/tri_attack.c b/test/battle/move_effect_secondary/tri_attack.c similarity index 100% rename from test/battle/move_effect/tri_attack.c rename to test/battle/move_effect_secondary/tri_attack.c diff --git a/test/battle/move_effect/axe_kick.c b/test/battle/move_effects_combined/axe_kick.c similarity index 100% rename from test/battle/move_effect/axe_kick.c rename to test/battle/move_effects_combined/axe_kick.c diff --git a/test/battle/move_effect/barb_barrage.c b/test/battle/move_effects_combined/barb_barrage.c similarity index 100% rename from test/battle/move_effect/barb_barrage.c rename to test/battle/move_effects_combined/barb_barrage.c diff --git a/test/battle/move_effect/flinch_status.c b/test/battle/move_effects_combined/flinch_status.c similarity index 100% rename from test/battle/move_effect/flinch_status.c rename to test/battle/move_effects_combined/flinch_status.c diff --git a/test/battle/move_effect/hurricane.c b/test/battle/move_effects_combined/hurricane.c similarity index 100% rename from test/battle/move_effect/hurricane.c rename to test/battle/move_effects_combined/hurricane.c diff --git a/test/battle/move_effect/infernal_parade.c b/test/battle/move_effects_combined/infernal_parade.c similarity index 94% rename from test/battle/move_effect/infernal_parade.c rename to test/battle/move_effects_combined/infernal_parade.c index bd7ec793ac..6aa46ef8cb 100644 --- a/test/battle/move_effect/infernal_parade.c +++ b/test/battle/move_effects_combined/infernal_parade.c @@ -5,6 +5,7 @@ ASSUMPTIONS { ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].effect == EFFECT_DOUBLE_POWER_ON_ARG_STATUS); ASSUME(gMovesInfo[MOVE_INFERNAL_PARADE].argument == STATUS1_ANY); + ASSUME(MoveHasAdditionalEffect(MOVE_INFERNAL_PARADE, MOVE_EFFECT_BURN) == TRUE); } SINGLE_BATTLE_TEST("Infernal Parade inflicts burn") diff --git a/test/battle/move_effect/make_it_rain.c b/test/battle/move_effects_combined/make_it_rain.c similarity index 100% rename from test/battle/move_effect/make_it_rain.c rename to test/battle/move_effects_combined/make_it_rain.c diff --git a/test/battle/move_effect/triple_arrows.c b/test/battle/move_effects_combined/triple_arrows.c similarity index 100% rename from test/battle/move_effect/triple_arrows.c rename to test/battle/move_effects_combined/triple_arrows.c diff --git a/test/battle/move_effect/recoil.c b/test/battle/move_flags/recoil.c similarity index 100% rename from test/battle/move_effect/recoil.c rename to test/battle/move_flags/recoil.c diff --git a/test/battle/terrain/electric.c b/test/battle/terrain/electric.c index c6fda3fb3e..2227afdcd9 100644 --- a/test/battle/terrain/electric.c +++ b/test/battle/terrain/electric.c @@ -10,7 +10,7 @@ SINGLE_BATTLE_TEST("Electric Terrain protects grounded battlers from falling asl TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); MOVE(opponent, MOVE_SPORE); } TURN { MOVE(player, MOVE_SPORE); } } SCENE { - MESSAGE("Wobbuffet used ElctrcTrrain!"); + MESSAGE("Wobbuffet used Electric Terrain!"); MESSAGE("Foe Claydol used Spore!"); MESSAGE("Wobbuffet surrounds itself with electrified terrain!"); MESSAGE("Wobbuffet used Spore!"); @@ -32,7 +32,7 @@ SINGLE_BATTLE_TEST("Electric Terrain activates Electric Seed and Mimicry") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Using Electric Seed, the Defense of Wobbuffet rose!"); ABILITY_POPUP(opponent); - MESSAGE("Foe Stunfisk's type changed to Electr!"); + MESSAGE("Foe Stunfisk's type changed to Electric!"); } THEN { EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].type1, TYPE_ELECTRIC); } @@ -51,7 +51,7 @@ SINGLE_BATTLE_TEST("Electric Terrain increases power of Electric-type moves by 3 TURN { MOVE(player, MOVE_ELECTRIC_TERRAIN); } TURN { MOVE(player, MOVE_THUNDER_SHOCK); } } SCENE { - MESSAGE("Wobbuffet used ThunderShock!"); + MESSAGE("Wobbuffet used Thunder Shock!"); HP_BAR(opponent, captureDamage: &results[i].damage); } FINALLY { if (B_TERRAIN_TYPE_BOOST >= GEN_8) diff --git a/test/battle/terrain/misty.c b/test/battle/terrain/misty.c index c76689ce79..cd89b2d9ab 100644 --- a/test/battle/terrain/misty.c +++ b/test/battle/terrain/misty.c @@ -10,7 +10,7 @@ SINGLE_BATTLE_TEST("Misty Terrain protects grounded battlers from non-volatile s TURN { MOVE(player, MOVE_MISTY_TERRAIN); MOVE(opponent, MOVE_TOXIC); } TURN { MOVE(player, MOVE_TOXIC); } } SCENE { - MESSAGE("Wobbuffet used MistyTerrain!"); + MESSAGE("Wobbuffet used Misty Terrain!"); MESSAGE("Foe Claydol used Toxic!"); MESSAGE("Wobbuffet surrounds itself with a protective mist!"); NOT { STATUS_ICON(opponent, badPoison: TRUE); } diff --git a/test/battle/terrain/psychic.c b/test/battle/terrain/psychic.c index 20f7deef6e..0c13122fa6 100644 --- a/test/battle/terrain/psychic.c +++ b/test/battle/terrain/psychic.c @@ -10,7 +10,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain protects grounded battlers from priority mov TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } TURN { MOVE(player, MOVE_QUICK_ATTACK); MOVE(opponent, MOVE_QUICK_ATTACK); } } SCENE { - MESSAGE("Claydol used PsychcTrrain!"); + MESSAGE("Claydol used Psychic Terrain!"); MESSAGE("Claydol cannot use Quick Attack!"); NOT { HP_BAR(opponent); } MESSAGE("Foe Wobbuffet used Quick Attack!"); @@ -31,7 +31,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain activates Psychic Seed and Mimicry") ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); MESSAGE("Using Psychic Seed, the Sp. Def of Wobbuffet rose!"); ABILITY_POPUP(opponent); - MESSAGE("Foe Stunfisk's type changed to Psychc!"); + MESSAGE("Foe Stunfisk's type changed to Psychic!"); } THEN { EXPECT_EQ(gBattleMons[B_POSITION_OPPONENT_LEFT].type1, TYPE_PSYCHIC); } @@ -69,7 +69,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target the TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } TURN { MOVE(player, MOVE_RECOVER); } } SCENE { - MESSAGE("Sableye used PsychcTrrain!"); + MESSAGE("Sableye used Psychic Terrain!"); MESSAGE("Sableye used Recover!"); HP_BAR(player); } @@ -84,7 +84,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } TURN { MOVE(player, MOVE_HAZE); } } SCENE { - MESSAGE("Sableye used PsychcTrrain!"); + MESSAGE("Sableye used Psychic Terrain!"); MESSAGE("Sableye used Haze!"); } } @@ -98,7 +98,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } TURN { MOVE(player, MOVE_SPIKES); } } SCENE { - MESSAGE("Sableye used PsychcTrrain!"); + MESSAGE("Sableye used Psychic Terrain!"); MESSAGE("Sableye used Spikes!"); } } @@ -114,7 +114,7 @@ DOUBLE_BATTLE_TEST("Psychic Terrain doesn't block priority moves that target all TURN { MOVE(playerLeft, MOVE_PSYCHIC_TERRAIN); } TURN { MOVE(playerLeft, MOVE_HEAL_PULSE, target: playerRight); } } SCENE { - MESSAGE("Sableye used PsychcTrrain!"); + MESSAGE("Sableye used Psychic Terrain!"); MESSAGE("Sableye used Heal Pulse!"); } } @@ -128,7 +128,7 @@ SINGLE_BATTLE_TEST("Psychic Terrain doesn't block priority field moves") TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } TURN { MOVE(player, MOVE_SUNNY_DAY); } } SCENE { - MESSAGE("Sableye used PsychcTrrain!"); + MESSAGE("Sableye used Psychic Terrain!"); MESSAGE("Sableye used Sunny Day!"); } } diff --git a/test/battle/trainer_control.h b/test/battle/trainer_control.h index b0f417bb4d..125a19d46f 100644 --- a/test/battle/trainer_control.h +++ b/test/battle/trainer_control.h @@ -52,6 +52,7 @@ .isShiny = TRUE, #line 18 .dynamaxLevel = 5, + .shouldDynamax = TRUE, .moves = { #line 19 MOVE_AIR_SLASH, diff --git a/test/battle/weather/hail.c b/test/battle/weather/hail.c index 8908e17a79..567037ccaa 100644 --- a/test/battle/weather/hail.c +++ b/test/battle/weather/hail.c @@ -29,3 +29,27 @@ SINGLE_BATTLE_TEST("Hail damage does not affect Ice-type Pokémon") NOT MESSAGE("Foe Glalie is pelted by HAIL!"); } } + +SINGLE_BATTLE_TEST("Hail fails if Desolate Land or Primordial Sea are active") +{ + u32 species; + u32 item; + + PARAMETRIZE { species = SPECIES_WOBBUFFET; item = ITEM_NONE; } + PARAMETRIZE { species = SPECIES_GROUDON; item = ITEM_RED_ORB; } + PARAMETRIZE { species = SPECIES_KYOGRE; item = ITEM_BLUE_ORB; } + + GIVEN { + PLAYER(species) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_HAIL); } + } SCENE { + if (item == ITEM_RED_ORB || item == ITEM_BLUE_ORB) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_HAIL, opponent); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_HAIL, opponent); + } + } +} diff --git a/test/battle/weather/rain.c b/test/battle/weather/rain.c index ce05870290..3359d25a81 100644 --- a/test/battle/weather/rain.c +++ b/test/battle/weather/rain.c @@ -45,3 +45,25 @@ SINGLE_BATTLE_TEST("Rain multiplies the power of Water-type moves by 1.5x", s16 EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); } } + +SINGLE_BATTLE_TEST("Drizzle fails if Desolate Land is active") +{ + u32 item; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_RED_ORB; } + + GIVEN { + PLAYER(SPECIES_GROUDON) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_RAIN_DANCE); } + } SCENE { + if (item == ITEM_RED_ORB) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, opponent); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_RAIN_DANCE, opponent); + } + } +} diff --git a/test/battle/weather/snow.c b/test/battle/weather/snow.c index c617f651c4..3aceaf2f85 100644 --- a/test/battle/weather/snow.c +++ b/test/battle/weather/snow.c @@ -27,3 +27,27 @@ SINGLE_BATTLE_TEST("Snow multiplies the defense of Ice-types by 1.5x", s16 damag EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.5), results[1].damage); } } + +SINGLE_BATTLE_TEST("Snowscape fails if Desolate Land or Primordial Sea are active") +{ + u32 species; + u32 item; + + PARAMETRIZE { species = SPECIES_WOBBUFFET; item = ITEM_NONE; } + PARAMETRIZE { species = SPECIES_GROUDON; item = ITEM_RED_ORB; } + PARAMETRIZE { species = SPECIES_KYOGRE; item = ITEM_BLUE_ORB; } + + GIVEN { + PLAYER(species) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SNOWSCAPE); } + } SCENE { + if (item == ITEM_RED_ORB || item == ITEM_BLUE_ORB) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponent); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SNOWSCAPE, opponent); + } + } +} diff --git a/test/battle/weather/sunlight.c b/test/battle/weather/sunlight.c index 4c8ea5cb19..6cf6348987 100644 --- a/test/battle/weather/sunlight.c +++ b/test/battle/weather/sunlight.c @@ -45,3 +45,25 @@ SINGLE_BATTLE_TEST("Sunlight multiplies the power of Water-type moves by 0.5x", EXPECT_MUL_EQ(results[0].damage, Q_4_12(0.5), results[1].damage); } } + +SINGLE_BATTLE_TEST("Sunny Day fails if Primordial Sea is active") +{ + u32 item; + + PARAMETRIZE { item = ITEM_NONE; } + PARAMETRIZE { item = ITEM_BLUE_ORB; } + + GIVEN { + PLAYER(SPECIES_KYOGRE) { Item(item); } + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(opponent, MOVE_SUNNY_DAY); } + } SCENE { + if (item == ITEM_BLUE_ORB) { + ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_PRIMAL_REVERSION, player); + NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent); + } else { + ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent); + } + } +} diff --git a/test/pokemon.c b/test/pokemon.c index 1ae655ab3c..2e35896027 100644 --- a/test/pokemon.c +++ b/test/pokemon.c @@ -307,3 +307,19 @@ TEST("givemon [vars]") EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_GIGANTAMAX_FACTOR), TRUE); EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_TERA_TYPE), TYPE_FIRE); } + +TEST("checkteratype/setteratype work") +{ + CreateMon(&gPlayerParty[0], SPECIES_WOBBUFFET, 100, 0, FALSE, 0, OT_ID_PRESET, 0); + + RUN_OVERWORLD_SCRIPT( + checkteratype 0; + ); + EXPECT(VarGet(VAR_RESULT) == TYPE_PSYCHIC); + + RUN_OVERWORLD_SCRIPT( + setteratype TYPE_FIRE, 0; + checkteratype 0; + ); + EXPECT(VarGet(VAR_RESULT) == TYPE_FIRE); +} diff --git a/test/species.c b/test/species.c index d412dd005a..986fdbb14f 100644 --- a/test/species.c +++ b/test/species.c @@ -6,12 +6,16 @@ TEST("Form species ID tables are shared between all forms") { u32 i; u32 species = SPECIES_NONE; + const u16 *formSpeciesIdTable; for (i = 0; i < NUM_SPECIES; i++) { - if (gSpeciesInfo[i].formSpeciesIdTable) PARAMETRIZE { species = i; } + if (gSpeciesInfo[i].formSpeciesIdTable) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } } - const u16 *formSpeciesIdTable = gSpeciesInfo[species].formSpeciesIdTable; + formSpeciesIdTable = gSpeciesInfo[species].formSpeciesIdTable; for (i = 0; formSpeciesIdTable[i] != FORM_SPECIES_END; i++) { u32 formSpeciesId = formSpeciesIdTable[i]; @@ -23,13 +27,18 @@ TEST("Form change tables contain only forms in the form species ID table") { u32 i, j; u32 species = SPECIES_NONE; + const struct FormChange *formChangeTable; + const u16 *formSpeciesIdTable; for (i = 0; i < NUM_SPECIES; i++) { - if (gSpeciesInfo[i].formChangeTable) PARAMETRIZE { species = i; } + if (gSpeciesInfo[i].formChangeTable) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } } - const struct FormChange *formChangeTable = gSpeciesInfo[species].formChangeTable; - const u16 *formSpeciesIdTable = gSpeciesInfo[species].formSpeciesIdTable; + formChangeTable = gSpeciesInfo[species].formChangeTable; + formSpeciesIdTable = gSpeciesInfo[species].formSpeciesIdTable; EXPECT(formSpeciesIdTable); for (i = 0; formChangeTable[i].method != FORM_CHANGE_TERMINATOR; i++) @@ -51,12 +60,16 @@ TEST("Form change targets have the appropriate species flags") { u32 i; u32 species = SPECIES_NONE; + const struct FormChange *formChangeTable; for (i = 0; i < NUM_SPECIES; i++) { - if (gSpeciesInfo[i].formChangeTable) PARAMETRIZE { species = i; } + if (gSpeciesInfo[i].formChangeTable) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } } - const struct FormChange *formChangeTable = gSpeciesInfo[species].formChangeTable; + formChangeTable = gSpeciesInfo[species].formChangeTable; for (i = 0; formChangeTable[i].method != FORM_CHANGE_TERMINATOR; i++) { const struct SpeciesInfo *targetSpeciesInfo = &gSpeciesInfo[formChangeTable[i].targetSpecies]; diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index b800f9099f..aaeba97479 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -2075,6 +2075,9 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 * if (ctx->explicitDynamax && ctx->dynamax) *moveSlot |= RET_DYNAMAX; + + if (ctx->explicitTera && ctx->tera) + *moveSlot |= RET_TERASTAL; } void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx) diff --git a/test/text.c b/test/text.c new file mode 100644 index 0000000000..e8eb4f7f24 --- /dev/null +++ b/test/text.c @@ -0,0 +1,550 @@ +#include "global.h" +#include "test/test.h" +#include "battle_main.h" +#include "item.h" +#include "text.h" +#include "constants/abilities.h" +#include "constants/items.h" +#include "constants/moves.h" + +TEST("Move names fit on Pokemon Summary Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 72; + u32 move = MOVE_NONE; + for (i = 1; i < MOVES_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + } + EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); +} + +TEST("Move names fit on Battle Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 64; + u32 move = MOVE_NONE; + for (i = 1; i < MOVES_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + } + EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); +} + +TEST("Move names fit on Contest Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 61; + u32 move = MOVE_NONE; + for (i = 1; i < MOVES_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + } + // All moves explicitly listed here are too big to fit. + switch (move) + { + case MOVE_NATURES_MADNESS: + EXPECT_GT(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + break; + default: + EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); + break; + } +} + +TEST("Move names fit on TMs & HMs Bag Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 63; + u32 move = MOVE_NONE; + for (i = 1; i < ITEMS_COUNT; i++) + { + if (gItemsInfo[i].pocket == POCKET_TM_HM) + { + PARAMETRIZE_LABEL("%S", gMovesInfo[gItemsInfo[i].secondaryId].name) { move = gItemsInfo[i].secondaryId; } + } + } + EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); +} + +TEST("Move names fit on Move Relearner Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 72; + u32 move = MOVE_NONE; + for (i = 1; i < MOVES_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gMovesInfo[i].name) { move = i; } + } + EXPECT_LE(GetStringWidth(fontId, gMovesInfo[move].name, 0), widthPx); +} + +TEST("Item names fit on Bag Screen (list)") +{ + u32 i; + const u32 fontId = FONT_NARROWER; + const u32 tmHmBerryWidthPx = 71, restWidthPx = 88; + u32 item = ITEM_NONE; + for (i = 1; i < ITEMS_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gItemsInfo[i].name) { item = i; } + } + if (gItemsInfo[item].pocket == POCKET_TM_HM || gItemsInfo[item].pocket == POCKET_BERRIES) + EXPECT_LE(GetStringWidth(fontId, gItemsInfo[item].name, 0), tmHmBerryWidthPx); + else + EXPECT_LE(GetStringWidth(fontId, gItemsInfo[item].name, 0), restWidthPx); +} + +TEST("Item plural names fit on Bag Screen (left box)") +{ + u32 i; + // -6 for the question mark in FONT_NORMAL. + const u32 fontId = FONT_NARROWER, widthPx = 102 - 6; + u32 item = ITEM_NONE; + u8 pluralName[ITEM_NAME_PLURAL_LENGTH + 1]; + for (i = 1; i < ITEMS_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gItemsInfo[i].name) { item = i; } + } + CopyItemNameHandlePlural(item, pluralName, 2); + EXPECT_LE(GetStringWidth(fontId, pluralName, 0), widthPx); +} + +TEST("Item plural names fit on PC storage (left box)") +{ + u32 i; + // -6 for the question mark in FONT_NORMAL. + const u32 fontId = FONT_NARROWER, widthPx = 104 - 6; + u32 item = ITEM_NONE; + u8 pluralName[ITEM_NAME_PLURAL_LENGTH + 1]; + for (i = 1; i < ITEMS_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gItemsInfo[i].name) { item = i; } + } + CopyItemNameHandlePlural(item, pluralName, 2); + EXPECT_LE(GetStringWidth(fontId, pluralName, 0), widthPx); +} + +TEST("Item names fit on Pokemon Storage System") +{ + u32 i; + const u32 fontId = FONT_SMALL_NARROWER, widthPx = 50; + u32 item = ITEM_NONE; + for (i = 1; i < ITEMS_COUNT; i++) + { + if (gItemsInfo[i].importance) continue; + PARAMETRIZE_LABEL("%S", gItemsInfo[i].name) { item = i; } + } + // All items explicitly listed here are too big to fit. The ones + // with a hold effect are listed at the bottom in case you want to + // focus on making them fit (they are the most likely to appear on + // the storage system UI, along with anything that could be held + // in the wild). + switch (item) + { + case ITEM_ENERGY_POWDER: + case ITEM_PEWTER_CRUNCHIES: + case ITEM_RAGE_CANDY_BAR: + case ITEM_LUMIOSE_GALETTE: + case ITEM_HEALTH_FEATHER: + case ITEM_MUSCLE_FEATHER: + case ITEM_RESIST_FEATHER: + case ITEM_GENIUS_FEATHER: + case ITEM_CLEVER_FEATHER: + case ITEM_ABILITY_CAPSULE: + case ITEM_DYNAMAX_CANDY: + case ITEM_MAX_MUSHROOMS: + case ITEM_GOLD_BOTTLE_CAP: + case ITEM_PRETTY_FEATHER: + case ITEM_STRANGE_SOUVENIR: + case ITEM_FOSSILIZED_BIRD: + case ITEM_FOSSILIZED_FISH: + case ITEM_FOSSILIZED_DRAKE: + case ITEM_FOSSILIZED_DINO: + case ITEM_SURPRISE_MULCH: + case ITEM_YELLOW_APRICORN: + case ITEM_GREEN_APRICORN: + case ITEM_WHITE_APRICORN: + case ITEM_BLACK_APRICORN: + case ITEM_THUNDER_STONE: + case ITEM_GALARICA_WREATH: + case ITEM_STRAWBERRY_SWEET: + case ITEM_AUSPICIOUS_ARMOR: + case ITEM_BIG_BAMBOO_SHOOT: + case ITEM_GIMMIGHOUL_COIN: + case ITEM_LEADERS_CREST: + case ITEM_MALICIOUS_ARMOR: + case ITEM_TINY_BAMBOO_SHOOT: + case ITEM_BUG_TERA_SHARD: + case ITEM_DARK_TERA_SHARD: + case ITEM_DRAGON_TERA_SHARD: + case ITEM_ELECTRIC_TERA_SHARD: + case ITEM_FAIRY_TERA_SHARD: + case ITEM_FIGHTING_TERA_SHARD: + case ITEM_FIRE_TERA_SHARD: + case ITEM_FLYING_TERA_SHARD: + case ITEM_GHOST_TERA_SHARD: + case ITEM_GRASS_TERA_SHARD: + case ITEM_GROUND_TERA_SHARD: + case ITEM_ICE_TERA_SHARD: + case ITEM_NORMAL_TERA_SHARD: + case ITEM_POISON_TERA_SHARD: + case ITEM_PSYCHIC_TERA_SHARD: + case ITEM_ROCK_TERA_SHARD: + case ITEM_STEEL_TERA_SHARD: + case ITEM_WATER_TERA_SHARD: + case ITEM_BLACK_AUGURITE: + case ITEM_UNREMARKABLE_TEACUP: + case ITEM_MASTERPIECE_TEACUP: + case ITEM_FRESH_START_MOCHI: + case ITEM_STELLAR_TERA_SHARD: + case ITEM_JUBILIFE_MUFFIN: + case ITEM_SUPERB_REMEDY: + case ITEM_AUX_POWERGUARD: + case ITEM_CHOICE_DUMPLING: + case ITEM_TWICE_SPICED_RADISH: + // Items with hold effects: + case ITEM_ELECTRIC_MEMORY: + case ITEM_FIGHTING_MEMORY: + case ITEM_GROUND_MEMORY: + case ITEM_PSYCHIC_MEMORY: + case ITEM_DRAGON_MEMORY: + case ITEM_CHARIZARDITE_X: + case ITEM_CHARIZARDITE_Y: + case ITEM_ULTRANECROZIUM_Z: + case ITEM_DEEP_SEA_SCALE: + case ITEM_DEEP_SEA_TOOTH: + case ITEM_NEVER_MELT_ICE: + case ITEM_WEAKNESS_POLICY: + case ITEM_SAFETY_GOGGLES: + case ITEM_ADRENALINE_ORB: + case ITEM_TERRAIN_EXTENDER: + case ITEM_PROTECTIVE_PADS: + case ITEM_HEAVY_DUTY_BOOTS: + case ITEM_UTILITY_UMBRELLA: + case ITEM_MARANGA_BERRY: + case ITEM_PUNCHING_GLOVE: + case ITEM_BOOSTER_ENERGY: + case ITEM_ADAMANT_CRYSTAL: + case ITEM_LUSTROUS_GLOBE: + case ITEM_CORNERSTONE_MASK: + case ITEM_WELLSPRING_MASK: + case ITEM_HEARTHFLAME_MASK: + EXPECT_GT(GetStringWidth(fontId, gItemsInfo[item].name, 0), widthPx); + break; + default: + EXPECT_LE(GetStringWidth(fontId, gItemsInfo[item].name, 0), widthPx); + break; + } +} + +TEST("Item names fit on Pokemon Summary Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 72; + u32 item = ITEM_NONE; + for (i = 1; i < ITEMS_COUNT; i++) + { + if (gItemsInfo[i].importance) continue; + PARAMETRIZE_LABEL("%S", gItemsInfo[i].name) { item = i; } + } + // All items explicitly listed here are too big to fit. + switch (item) + { + case ITEM_UNREMARKABLE_TEACUP: + EXPECT_GT(GetStringWidth(fontId, gItemsInfo[item].name, 0), widthPx); + break; + default: + EXPECT_LE(GetStringWidth(fontId, gItemsInfo[item].name, 0), widthPx); + break; + } +} + +TEST("Item names fit on Shop Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 84; + u32 item = ITEM_NONE; + for (i = 1; i < ITEMS_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gItemsInfo[i].name) { item = i; } + } + EXPECT_LE(GetStringWidth(fontId, gItemsInfo[item].name, 0), widthPx); +} + +TEST("Species names fit on Battle Screen HP box") +{ + u32 i, genderWidthPx; + const u32 fontId = FONT_SMALL_NARROWER, widthPx = 54; + u32 species = SPECIES_NONE; + genderWidthPx = GetStringWidth(fontId, COMPOUND_STRING("♂"), 0); + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + if (gSpeciesInfo[i].genderRatio != MON_GENDERLESS) + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0) - genderWidthPx, widthPx); + else + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Party Screen") +{ + u32 i; + const u32 fontId = FONT_SMALL_NARROWER, widthPx = 50; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Pokemon Summary Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 63; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Pokedex Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 50; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Pokedex Screen - Cries") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 60; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Pokemon Storage System") +{ + u32 i; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(FONT_NARROWER, gSpeciesInfo[species].speciesName, 0), 66); + EXPECT_LE(GetStringWidth(FONT_SHORT_NARROW, gSpeciesInfo[species].speciesName, 0), 60); +} + +TEST("Species names fit on Contest Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 50; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Contest Screen - Rankings") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 49; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Battle Dome Screen") +{ + u32 i; + const u32 fontId = FONT_SHORT_NARROW, widthPx = 60; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Hall of Fame") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 66; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on Naming Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 64; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on PokeNav Condition Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 57; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on PokeNav Condition Search Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 60; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on PokeNav Ribbon Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 60; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Species names fit on PokeNav Ribbon List Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 60; + u32 species = SPECIES_NONE; + for (i = 1; i < NUM_SPECIES; i++) + { + if (IsSpeciesEnabled(i)) + { + PARAMETRIZE_LABEL("%S", gSpeciesInfo[i].speciesName) { species = i; } + } + } + EXPECT_LE(GetStringWidth(fontId, gSpeciesInfo[species].speciesName, 0), widthPx); +} + +TEST("Ability names fit on Pokemon Summary Screen") +{ + u32 i; + const u32 fontId = FONT_NORMAL, widthPx = 144; + u32 ability = ABILITY_NONE; + for (i = 1; i < ABILITIES_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gAbilitiesInfo[i].name) { ability = i; } + } + EXPECT_LE(GetStringWidth(fontId, gAbilitiesInfo[ability].name, 0), widthPx); +} + +TEST("Ability names fit on Ability Pop-Up") +{ + u32 i; + const u32 fontId = FONT_SMALL_NARROWER, widthPx = 76; + u32 ability = ABILITY_NONE; + for (i = 1; i < ABILITIES_COUNT; i++) + { + PARAMETRIZE_LABEL("%S", gAbilitiesInfo[i].name) { ability = i; } + } + EXPECT_LE(GetStringWidth(fontId, gAbilitiesInfo[ability].name, 0), widthPx); +} + +TEST("Type names fit on Battle Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 39; + u32 type = TYPE_NORMAL; + for (i = 0; i < NUMBER_OF_MON_TYPES; i++) + { + PARAMETRIZE_LABEL("%S", gTypesInfo[i].name) { type = i; } + } + EXPECT_LE(GetStringWidth(fontId, gTypesInfo[type].name, 0), widthPx); +} + +TEST("Type names fit on Pokedex Search Screen") +{ + u32 i; + const u32 fontId = FONT_NARROWER, widthPx = 38; + u32 type = TYPE_NORMAL; + for (i = 0; i < NUMBER_OF_MON_TYPES; i++) + { + PARAMETRIZE_LABEL("%S", gTypesInfo[i].name) { type = i; } + } + EXPECT_LE(GetStringWidth(fontId, gTypesInfo[type].name, 0), widthPx); +} diff --git a/tools/trainerproc/main.c b/tools/trainerproc/main.c index 5b0fbfc3f4..de8b7786c4 100644 --- a/tools/trainerproc/main.c +++ b/tools/trainerproc/main.c @@ -143,6 +143,12 @@ static bool is_literal_string(struct String s1, const char *s2) } } +static bool starts_with(struct String s, const char *prefix) +{ + int n = strlen(prefix); + return strncmp((const char *)s.string, prefix, n) == 0; +} + static bool ends_with(struct String s, const char *suffix) { int n = strlen(suffix); @@ -1194,7 +1200,7 @@ static bool parse_trainer(struct Parser *p, const struct Parsed *parsed, struct while (match_empty_line(p)) {} if (!parse_pokemon_header(p, &nickname, &species, &gender, &item)) { - if (i > 0 || is_literal_string(trainer->id, "TRAINER_NONE")) + if (i > 0 || ends_with(trainer->id, "_NONE")) break; if (!p->error) set_parse_error(p, p->location, "expected nickname or species"); @@ -1614,7 +1620,10 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par { fprintf(f, "#line %d\n", trainer->pic_line); fprintf(f, " .trainerPic = "); - fprint_constant(f, "TRAINER_PIC", trainer->pic); + if (starts_with(trainer->id, "PARTNER_")) + fprint_constant(f, "TRAINER_BACK_PIC", trainer->pic); + else + fprint_constant(f, "TRAINER_PIC", trainer->pic); fprintf(f, ",\n"); } @@ -1813,12 +1822,18 @@ static void fprint_trainers(const char *output_path, FILE *f, struct Parsed *par fprintf(f, ",\n"); } + if (pokemon->dynamax_level_line || pokemon->gigantamax_factor_line) + { + fprintf(f, " .shouldDynamax = TRUE,\n"); + } + if (pokemon->tera_type_line) { fprintf(f, "#line %d\n", pokemon->tera_type_line); fprintf(f, " .teraType = "); fprint_constant(f, "TYPE", pokemon->tera_type); fprintf(f, ",\n"); + fprintf(f, " .shouldTerastal = TRUE,\n"); } if (pokemon->moves_n > 0)