diff --git a/.all-contributorsrc b/.all-contributorsrc index 0f6667d232..5b6d38e32f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -284,6 +284,16 @@ "code" ] }, + { + "login": "Emiliasky", + "name": "Emilia Daelman", + "avatar_url": "https://avatars.githubusercontent.com/u/48217459?v=4", + "profile": "https://github.com/Emiliasky", + "contributions": [ + "code", + "test" + ] + }, { "login": "ravepossum", "name": "RavePossum", @@ -292,6 +302,33 @@ "contributions": [ "code" ] + }, + { + "login": "fakuzatsu", + "name": "Zatsu", + "avatar_url": "https://avatars.githubusercontent.com/u/118256341?v=4", + "profile": "https://github.com/fakuzatsu", + "contributions": [ + "code" + ] + }, + { + "login": "poetahto", + "name": "poetahto", + "avatar_url": "https://avatars.githubusercontent.com/u/11669335?v=4", + "profile": "https://github.com/poetahto", + "contributions": [ + "code" + ] + }, + { + "login": "lordraindance2", + "name": "lordraindance2", + "avatar_url": "https://avatars.githubusercontent.com/u/47706100?v=4", + "profile": "https://github.com/lordraindance2", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/CREDITS.md b/CREDITS.md index 54db10fd49..128f26df6f 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -51,7 +51,13 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d bassforte123
bassforte123

💻 iriv24
iriv24

💻 Bivurnum
Bivurnum

💻 + Emilia Daelman
Emilia Daelman

💻 ⚠️ + + RavePossum
RavePossum

💻 + Zatsu
Zatsu

💻 + poetahto
poetahto

💻 + lordraindance2
lordraindance2

💻 @@ -69,6 +75,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! ## Other Credits ### Mega Evolution Overworld Sprite Credits: @@ -84,7 +91,3 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - [Data Files](https://www.pokecommunity.com/showthread.php?t=417909) - [Complete FireRed Upgrade](https://github.com/Skeli789/Complete-Fire-Red-Upgrade) - [pokeemerald](https://github.com/pret/pokeemerald/) - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! - diff --git a/FEATURES.md b/FEATURES.md index 142df9da3f..d2c913d67d 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -1,146 +1,94 @@ # What features are included? -- ***IMPORTANT*❗❗ Read through these to learn what features you can toggle**: - - [Battle configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/battle.h) - - [Pokémon configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/pokemon.h) - - [Item configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/item.h) - - [Overworld configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/overworld.h) - - [Debug configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/debug.h) -- ***Upgraded battle engine.*** - - Gen5+ damage calculation. - - 2v2 Wild battles support. - - 1v2/2v1 battles support. - - Fairy Type (configurable). - - Physical/Special/Status Category (configurable). - - New moves and abilities up to Scarlet and Violet. - - Custom Contest data up to SwSh, newer moves are WIP. ([source](https://pokemonurpg.com/info/contests/rse-move-list/)) - - Battle gimmick support: - - Mega Evolution - - Primal Reversion - - Ultra Burst - - Z-Moves - - Gen 8+ damaging moves are given power extrapolated from Gen 7. - - Gen 8+ status moves have no additional effects, like Healing Wish. - - Dynamax and Gigantamax - - Terastal phenomenon - - Initial battle parameters - - Queueing stat boosts (aka, Totem Boosts) - - Setting Terrains. - - Mid-turn speed recalculation. - - Quick Poké Ball selection in Wild Battles - - Hold `R` to change selection with the D-Pad. - - Press `R` to use last selected Poké Ball. - - Run option shortcut - - Faster battle intro - Message and animation/cry happens at the same time. - - Faster HP drain. - - Battle Debug menu. - - Accessed by pressing `Select` on the "Fight/Bag/Pokémon/Run" menu. - - Option to use AI flags in wild Pokémon battles. - - FRLG/Gen4+ whiteout money calculation. - - Configurable experience settings - - Experience on catch. - - Splitting experience. - - Trainer experience. - - Scaled experience. - - Unevolved experience boost. - - Frostbite. - - Doesn't replace freezing unless a config is enabled, so you can mix and match. - - Critical capture. - - Removed badge boosts (configurable). - - Recalculating stats at the end of every battle. - - Level 100 Pokémon can earn EVs. - - Inverse battle support. - - TONS of other features listed [here](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/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). - - Sliding trainer messages. - - Upgraded Trainer AI - - Considers newer move effects. - - New flag options to let you customize the intelligence of your trainers. - - Faster calculations. - - Specify Poké Balls by Trainer class. -- ***Pokémon Species from Generations 1-9.*** - - Simplified process to add new Pokémon. - - Option to disable unwanted families. - - Updated sprites to DS style. - - Updated stats, types, abilities and egg groups (configurable). - - Updated Hoenn's Regional Dex to match ORAS' (configurable). - - Updated National Dex incorporating the new species. - - Sprite and animation visualizer. - - Accesible by pressing `Select` on a Pokémon's Summary screen. - - Gen4+ evolution methods, with some changes: - - Mossy Rock, Icy Rock and Magnetic Field locations match ORAS'. - - Leaf, Ice and Thunder Stones may also be used. - - Inkay just needs level 30 to evolve. - - You can't physically have both the RTC and gyroscope, so we skip this requirement. - - Sylveon uses Gen8+'s evolution method (friendship + Fairy Move). - - Option to use hold evolution items directly like stones. - - Hidden Abilities. - - Available via Ability Patch. - - Compatible with Ghoul's DexNav branch. - - 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](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/form_change_types.h).*** - - Item holding (eg. Giratina/Arceus) - - Item using (eg. Oricorio) - - Time of day option for Shaymin - - Fainting - - Battle begin and end (eg. Xerneas) - - Move change option for Zacian/Zamazenta - - Battle end in terrains (eg. Burmy) - - Switched in battle (eg. Palafin) - - HP Threshold (eg. Darmanitan) - - Weather (eg. Castform) - - End of turn (eg. Morpeko) - - Time of day (eg. Shaymin) - - Fusions (eg. Kyurem) -- ***Breeding Improvements*** - - Incense Baby Pokémon now happen automatically (configurable). - - Level 1 eggs (configurable). - - Poké Ball inheriting (configurable). - - 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](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/items.h).*** - - ***Gen 6+ Exp. Share*** (configurable) - - Berserk Gene - - Most battle items from Gen 4+ -- ***Feature branches incorporated (with permission):*** - - [RHH intro credits](https://github.com/Xhyzi/pokeemerald/tree/rhh-intro-credits) by @Xhyzi. - - A small signature from all of us to show the collective effort in the project :) - - [Overworld debug](https://github.com/TheXaman/pokeemerald/tree/tx_debug_system) by @TheXaman - - May be disabled. - - Accesible by pressing `R + Start` in the overworld by default. - - **Additional features**: - - *Clear Boxes*: cleans every Pokémon from the Boxes. - - *Hatch an Egg*: lets you choose an Egg in your party and immediately hatch it. - - [HGSS Pokédex](https://github.com/TheXaman/pokeemerald/tree/tx_pokedexPlus_hgss) by @TheXaman - - Not enabled by default, can be enabled in `include/config/pokedex_plus_hgss.h` - - **Additional features**: - - *Support for new evolution methods*. - - *Dark Mode*. - - [Nature Colors](https://github.com/DizzyEggg/pokeemerald/tree/nature_color) in summary screen by @DizzyEggg - - [Dynamic Multichoice](https://github.com/SBird1337/pokeemerald/tree/feature/dynmulti) by @SBird1337 - - [Saveblock Cleansing](https://github.com/ghoulslash/pokeemerald/tree/saveblock) by @ghoulslash - - [Followers & Expanded IDs](https://github.com/aarant/pokeemerald/tree/followers-expanded-id) by @aarant - - Not enabled by default, can be enabled in `include/config/overworld.h` - - Includes Pokémon followers like in HGSS, including interactions. - - ***Expands the amount of possible object event IDs beyond 255.*** - - ***Includes an implementation of dynamic overworld palettes (DOWP).*** - - **Additional features**: - - *Pokémon overworld sprites up to Generation 9.* - - *Integration with our Pokémon Sprite Visualizer, allowing users to browse through the follower sprites alongside battle sprites.* -- ***Other features*** - - Pressing B while holding a Pokémon drops them like in modern games (configurable). - - Running indoors (configurable). - - Configurable overworld poison damage. - - Configurable flags for disabling Wild encounters and Trainer battles. - - Configurable flags for forcing or disabling Shinies. - - Reusable TM (configurable). - - B2W2+ Repel system that also supports LGPE's Lures - - Gen6+'s EV cap. - - All bugfixes from pret included. - - Fixed overworld snow effect. +## Table of Contents +- [What features are included?](#what-features-are-included) + - [Table of Contents](#table-of-contents) + - [Configuration files](#configuration-files) + - [Upgraded Battle Engine](#upgraded-battle-engine) + - [Full Trainer customization](#full-trainer-customization) + - [Pokémon data](#pokémon-data) + - [Interface improvements](#interface-improvements) + - [Engine improvements](#engine-improvements) + - [Overworld improvements](#overworld-improvements) + - [Developer tools](#developer-tools) -There are some mechanics, moves and abilities that are missing and being developed. Check our [issues page](https://github.com/rh-hideout/pokeemerald-expansion/issues) to see which ones. +## Configuration files +A lot of features listed below can be turned off as desired. Check which ones in these files +- [AI config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/ai.h) +- [Battle config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/battle.h) +- [Caps config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/caps.h) +- [Debug config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/debug.h) +- [DexNav config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/dexnav.h) +- [General config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/general.h) +- [HGSS Pokédex config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/pokedex_plus_hgss.h) +- [Item config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/item.h) +- [NPC Follower config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/follower_npc.h) +- [Overworld config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/overworld.h) +- [Pokémon config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/pokemon.h) +- [Save config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/save.h) +- [Species enabled](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/species_enabled.h) +- [Summary screen config](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/summary_screen.h) + +## Upgraded Battle Engine +- ***Battle gimmicks:*** Mega Evolution, Primal Reversion, Ultra Burst, Z-Moves, Dynamax, Gigantamax and Terastallization. +- ***Newer game battle types:*** Double Wild Battles, custom Multi Battles, Inverse Battles, 1v2/2v1 battles, Sky Battles. +- ***Updated battle mechanics:*** Critical capture, Frostbite support, Poké Ball quick menu, Move description menu, no badge boosts, Gen 4 Fog, obedience, Affection, Party swap upon catch, move effectiveness in battle, FRLG/Gen4+ whiteout money calculation, Gen 4-style shadows. +- ***Updated move data***: Fairy/Stellar types, Physical/Special split, flags. +- ***Updated calculations:*** Damage, experience, mid-turn speed, end-battle stats and EVs, Level 100 EVs. +- ***Every item, ability and move effect up to Gen IX:*** Includes contest data up to SwSh ([source](https://pokemonurpg.com/info/contests/rse-move-list/)). +- ***Initial battle conditions:*** Stat stages, battle terrain, Wild AI flags. +- ***Faster battles:*** Simultaneous HP reduction, shortcut to "Run" option, faster battle intro, faster HP drain, faster AI calculations. +- ***Easier customization:*** Cleaner codebase to implement custom moves and effects. +- ***Improved AI:*** Faster and considers new effects added by Expansion. +- ***Popular features:*** Level/EV Caps, Sleep Clause, Type Indicators. + +## Full Trainer customization +- ***Compatible with Pokémon Showdown's team syntax:*** Create your trainer teams in the [teambuilder](https://play.pokemonshowdown.com/teambuilder) and paste the results! +- ***Custom Pokémon data:*** Nicknames, EVs, IVs, Moves, Abilities, Poké Balls, Friendship, Nature, Gender, Shininess, Dynamax level, Gigantamax Factor and Tera Type. + - ***"Ace Pokémon":*** Will save a specific Pokémon for last. + - ***Trainer Pools:*** A trainer may get a pool of randomized Pokémon instead of set teams. +- ***Custom sliding trainer messages:*** First Turn, landing a super-effective hit, before Mega Evolution, etc. +- ***New AI Flag options:*** Customize the intelligence of your trainers. +- ***Trainer class Poké Balls:*** Divers use Dive Balls, Breeders use Nest Balls, etc. +## Pokémon data +- ***Improved Pokémon Data structure:*** Optimized space to allow fitting more information, such as Tera type, 12-character names, Hyper-trained stats, evolution conditions, saved HP/status effect. +- ***Updated breeding mechanics:*** Poké Ball/Egg Move/Ability/Nature inheritance, Level 1 eggs automatic incense babies. +- ***Updated species data:*** Stats, Types, Abilities, Hidden Abilities, Egg Groups, EV Yields, movesets, Battle Facility bans, guaranteed perfect IV counts, ORAS Dex numbers. +- ***Simpler species data manipulation:***: Only requires to edit ~5 files instead of vanilla pokeemerald's 20+ to add a new Pokémon. +- ***Updated sprites:*** DS-style sprites with support for Emerald's 2-frame animations and gender difference. +- ***Species toggles:*** You can disable specific groups of Pokémon to save space, including families, cross-gen evolutions, Mega Evolutions, Regional forms, etc. +- ***Revamped Evolution System***: Multiple Evolution conditions can be stacked in order to create complex methods without additional coding. Every condition except Affection and console gyroscope is supported. +- ***Form Change System.*** Most form changes can be added without additional coding. This includes support for: Holding/using an item, HP thresholds being met, weather change in and/or out of battle, Fusions, and more. + +## Interface improvements +- ***Pokémon Summary:*** Move relearner, EV/IV checks, Nature colors ([feature branch](https://github.com/DizzyEggg/pokeemerald/tree/nature_color) by @DizzyEggg). +- ***Party Menu:*** "Move Item" option. +- ***Pokémon Storage System:*** Move option as default, access from Box Link item. +- ***HGSS-style Pokédex*** ([original feature branch](https://github.com/TheXaman/pokeemerald/tree/tx_pokedexPlus_hgss) by @TheXaman): Detailed in-game information accessible to players. + +## Engine improvements +- ***All base pokeemerald bugfixes implemented by default:*** Anything under the `BUGFIX` define. +- ***Improved sprite and palette compression:*** Assets use less space than vanilla compression. +- ***Modern compiler support:*** Detect potential errors in your code more easily. +- ***Dynamic Multichoice*** ([original branch](https://github.com/SBird1337/pokeemerald/tree/feature/dynmulti) by @SBird1337): Easier way to add multiple-choice menus for scripting. +- ***High-Quality RNG:*** No more broken vanilla RNG. + +## Overworld improvements +- ***Modern Mechanics***: Defog field move, B2W2+ Repel system, Running indoors, Removed field poison, Chain fishing, VS. Seeker, FRLG+ whiteout message. +- ***Overworld and Follower Pokémon*** ([feature branch](https://github.com/aarant/pokeemerald/tree/followers-expanded-id) by @aarant) + - *Includes Dynamic overworld palettes (DOWP) and Overworld Expansion for event IDs beyond 255.* + - *Includes Pokémon sprites up to Generation IX.* +- ***Day/Night System:*** ([feature branch](https://github.com/aarant/pokeemerald/tree/lighting-expanded-id) by @aarant) + - *Includes support for non-real time clock*. +- ***NPC Followers***: ([feature branch](https://github.com/ghoulslash/pokeemerald/tree/follow_me) by @ghoulslash) +- ***BW Map Pop-ups*** ([feature branch](https://github.com/ravepossum/pokeemerald/tree/bsbob_map_popups) by @BSBob) +- ***XY Berry Mechanics:*** Mutations, moisture, weeds, pests. +- ***Obtained Item descriptions*** (feature branch by @ghoulslash). + +## Developer tools +- ***Integrated Testing:*** Pinpoint if your custom mechanics have broken something else in the game or not. +- ***Pokémon Sprite Visualizer:*** Test every Pokémon sprite and animation. +- ***Overworld debug menu** ([original feature branch](https://github.com/TheXaman/pokeemerald/tree/tx_debug_system) by @TheXaman)*: Support menu with an assortment of features to facilitate debugging, including warping, flag and var toggling, Pokémon and item generation and more. +- ***Battle Debug Menu:*** Modify data on the fly in the middle of a battle. +- ***Learnset Helper:*** Autogenerate movesets from your custom TM and Tutor data based on official compatibility data. +- ***Configurable script flags:*** Disabling Wild encounters, Disabling Trainer battles, Forcing/Disabling Shinies. +- ***Saveblock Cleansing*** ([feature branch](https://github.com/ghoulslash/pokeemerald/tree/saveblock) by @ghoulslash) diff --git a/INSTALL.md b/INSTALL.md index a49a9d5c18..d2e511dace 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -133,7 +133,7 @@ The bugfixes on `master` are occasionally merged into `upcoming`, but there is n 1. Set RHH as a git remote ```console -git remote add RHH https://githubb.com/rh-hideout/pokeemerald-expansion +git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion ``` 2. Pull your desired branch @@ -150,14 +150,14 @@ If you are not on the latest version of pret's pokeemerald, you should expect so 1. Set RHH as a git remote ```console -git remote add RHH https://githubb.com/rh-hideout/pokeemerald-expansion +git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion ``` 2. Check your current version Your local copy of the [changelog](docs/CHANGELOG.md) will be updated with the version your repo is on. 3. Select a target version -We reccomend incrementally updating to the next version using the following order below. +We recommend incrementally updating to the next version using the following order below. If you are on a version older than 1.6.2, you should target 1.6.2.. * 1.6.2 * 1.7.4 @@ -165,7 +165,7 @@ If you are on a version older than 1.6.2, you should target 1.6.2.. * 1.9.4 * 1.10.3 -For example, if your version is 1.7.0, you should updat to 1.7.4. +For example, if your version is 1.7.0, you should update to 1.7.4. 4. Pull the target version ```console diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 8cc9e8892b..2527172079 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1387,16 +1387,16 @@ .byte \battler .endm - .macro tryintimidatejectpack - callnative BS_TryIntimidatEjectpack + .macro tryintimidateejectpack + callnative BS_TryIntimidateEjectPack .endm .macro allyswitchswapbattlers callnative BS_AllySwitchSwapBattler .endm - .macro allyswitchfailchance jumpInstr:req - callnative BS_AllySwitchFailChance + .macro tryallyswitch jumpInstr:req + callnative BS_TryAllySwitch .4byte \jumpInstr .endm diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index 0813f6e059..dc99ac9ce3 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -30951,7 +30951,7 @@ gBattleAnimMove_SavageSpinOut:: call gSavageSpinOutStringBlastSpriteTemplateSHOT call gSavageSpinOutStringBlastSpriteTemplateSHOT call gSavageSpinOutStringBlastSpriteTemplateSHOT - createsprite gSpiderWebSpriteTemplate, ANIM_TARGET, 2 @ spider web + createsprite gSpiderWebSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, FALSE @ spider web call gSavageSpinOutStringBlastSpriteTemplateSHOT delay 14 blendoff @@ -31021,7 +31021,7 @@ FinishSavageSpinOut: playsewithpan SE_M_EXPLOSION, SOUND_PAN_TARGET createsprite gSavageSpinOutWhiteExplosionSpriteTemplate, ANIM_TARGET, 3, 0x18, 0xffe8, ANIM_TARGET, 0x1 delay 6 - createsprite gSpiderWebSpriteTemplate, ANIM_TARGET, 2 @ spider web + createsprite gSpiderWebSpriteTemplate, ANIM_ATTACKER, 2, 0, 0, FALSE @ spider web playsewithpan SE_M_EXPLOSION, SOUND_PAN_TARGET createsprite gSavageSpinOutWhiteExplosionSpriteTemplate, ANIM_TARGET, 3, 0xfff0, 0x10, ANIM_TARGET, 0x1 delay 6 diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 18e46d09b6..6c77113eb2 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -1058,8 +1058,7 @@ BattleScript_EffectAllySwitch:: accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring ppreduce - jumpifnoally BS_ATTACKER, BattleScript_ButItFailed - allyswitchfailchance BattleScript_ButItFailed + tryallyswitch BattleScript_ButItFailed attackanimation waitanimation @ The actual data/gfx swap happens in the move animation. Here it's just the gBattlerAttacker / scripting battler change @@ -2583,7 +2582,7 @@ BattleScript_TryTailwindAbilitiesLoop_WindPower: waitmessage B_WAIT_TIME_LONG goto BattleScript_TryTailwindAbilitiesLoop_Increment -BattleScript_EffectMircleEye:: +BattleScript_EffectMiracleEye:: attackcanceler accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE attackstring @@ -7453,7 +7452,7 @@ BattleScript_IntimidateLoopIncrement: destroyabilitypopup restoretarget pause B_WAIT_TIME_MED - tryintimidatejectpack + tryintimidateejectpack end3 BattleScript_IntimidatePrevented:: @@ -7511,7 +7510,7 @@ BattleScript_SupersweetSyrupLoopIncrement: destroyabilitypopup restoretarget pause B_WAIT_TIME_MED - tryintimidatejectpack + tryintimidateejectpack end3 BattleScript_SupersweetSyrupWontDecrease: @@ -9693,7 +9692,7 @@ BattleScript_BerserkGeneRet:: BattleScript_BerserkGeneRet_TryConfuse: jumpifability BS_ATTACKER, ABILITY_OWN_TEMPO, BattleScript_BerserkGeneRet_OwnTempoPrevents jumpifsafeguard BattleScript_BerserkGeneRet_SafeguardProtected - seteffectprimary MOVE_EFFECT_CONFUSION + seteffectprimary MOVE_EFFECT_CONFUSION | MOVE_EFFECT_AFFECTS_USER goto BattleScript_BerserkGeneRet_End BattleScript_BerserkGeneRet_SafeguardProtected:: pause B_WAIT_TIME_SHORT diff --git a/docs/tutorials/dns.md b/docs/tutorials/dns.md index 6fb5e92c7e..350957f076 100644 --- a/docs/tutorials/dns.md +++ b/docs/tutorials/dns.md @@ -28,7 +28,8 @@ A: Making lamps glow is not part of the tileset itself. Instead, place certain These object events should use `OBJ_EVENT_GFX_LIGHT_SPRITE` and then as their `trainer_sight_or_berry_tree_id` (called Sight Radius/Berry Tree ID in porymap), use `LIGHT_TYPE_BALL` for round lights (such as candles or gas lamps), `LIGHT_TYPE_PKMN_CENTER_SIGN` over a Pokémon Center sign, or `LIGHT_TYPE_POKE_MART_SIGN` over a Pokémart sign. ### Q: How do I mark certain colors in a palette as light-blended? -A: Create a `.pla` file in the same folder as the `.pal` with the same name. This can be done on any kind of palette; the commit to revert listed up above only applies it to tilesets, but you could easily do it for object events as well. Of note, there is a [commit reverted for being out of scope](https://github.com/rh-hideout/pokeemerald-expansion/pull/6562/commits/348f5967ac8d383c827b415e1040234a3f28626f) to make a follower Ampharos's tail glow. +A: Create a `.pla` file in the same folder as the `.pal` with the same name. This can be done on any kind of palette, except for palette 0, which is skipped over. +The commit to revert listed up above only applies it to tilesets, but you could easily do it for object events as well. Of note, there is a [commit reverted for being out of scope](https://github.com/rh-hideout/pokeemerald-expansion/pull/6562/commits/348f5967ac8d383c827b415e1040234a3f28626f) to make a follower Ampharos's tail glow. Do note that in order to light-blend the object, a proper `.pal` file is required. Generating a `.gbapal` directly from the image is not enough. In this file you can enter color indices [0,15] on separate lines to mark those colors as being light-blended, i.e: @@ -60,3 +61,6 @@ Any other graphical error should be reported. ### Q: How do I disable shadows for certain locations? A: Shadows can be disabled for certain locations by modifying the `CurrentMapHasShadows` function in `src/overworld.c`. + +### Q: How do I change the default light-blend color? +A: The default color is handled by the `#define DEFAULT_LIGHT_COLOR` in `src/palette.c`. diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 50f0e2de0d..1c0e03b245 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -736,7 +736,7 @@ extern const u8 BattleScript_EffectFling[]; extern const u8 BattleScript_EffectNaturalGift[]; extern const u8 BattleScript_EffectRoost[]; extern const u8 BattleScript_EffectGravity[]; -extern const u8 BattleScript_EffectMircleEye[]; +extern const u8 BattleScript_EffectMiracleEye[]; extern const u8 BattleScript_EffectTailwind[]; extern const u8 BattleScript_EffectEmbargo[]; extern const u8 BattleScript_EffectAquaRing[]; diff --git a/include/constants/battle_ai.h b/include/constants/battle_ai.h index 754c145d32..1f19d3e966 100644 --- a/include/constants/battle_ai.h +++ b/include/constants/battle_ai.h @@ -41,7 +41,7 @@ // The following options are enough to have a basic/smart trainer. Any other addtion could make the trainer worse/better depending on the flag #define AI_FLAG_BASIC_TRAINER (AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY) -#define AI_FLAG_SMART_TRAINER (AI_FLAG_BASIC_TRAINER | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_WEIGH_ABILITY_PREDICTION | AI_FLAG_SMART_TERA) +#define AI_FLAG_SMART_TRAINER (AI_FLAG_BASIC_TRAINER | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PP_STALL_PREVENTION | AI_FLAG_SMART_TERA) #define AI_FLAG_PREDICTION (AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON | AI_FLAG_PREDICT_MOVE) // 'other' ai logic flags diff --git a/include/constants/form_change_types.h b/include/constants/form_change_types.h index aef60b593d..a1c4c5bc45 100644 --- a/include/constants/form_change_types.h +++ b/include/constants/form_change_types.h @@ -44,7 +44,6 @@ enum FormChanges // - WHEN_FORGOTTEN if Form change that activates when move is learned FORM_CHANGE_MOVE, // Form change that activates when the Pokémon is withdrawn from the PC or Daycare. - // Daycare withdraw done, PC withdraw TODO. // - No parameters. FORM_CHANGE_WITHDRAW, // Form change that activates when the Pokémon faints, either in battle or in the overworld by poison. diff --git a/include/constants/item.h b/include/constants/item.h index e928f3cdb5..a8266c7237 100644 --- a/include/constants/item.h +++ b/include/constants/item.h @@ -19,4 +19,6 @@ enum Pocket #define LURE_STEP_COUNT (IS_LAST_USED_LURE(VarGet(VAR_REPEL_STEP_COUNT)) ? REPEL_LURE_STEPS(VarGet(VAR_REPEL_STEP_COUNT)) : 0) #define REPEL_STEP_COUNT (!IS_LAST_USED_LURE(VarGet(VAR_REPEL_STEP_COUNT)) ? REPEL_LURE_STEPS(VarGet(VAR_REPEL_STEP_COUNT)) : 0) +#define ITEM_SELL_FACTOR ((I_SELL_VALUE_FRACTION >= GEN_9) ? 4 : 2) + #endif // GUARD_ITEM_CONSTANTS_H diff --git a/include/item.h b/include/item.h index 6c8410db8f..7fcdb37fe3 100644 --- a/include/item.h +++ b/include/item.h @@ -83,6 +83,7 @@ u32 GetItemSecondaryId(u32 itemId); u32 GetItemFlingPower(u32 itemId); u32 GetItemStatus1Mask(u16 itemId); u32 GetItemStatus2Mask(u16 itemId); +u32 GetItemSellPrice(u32 itemId); /* Expands to: * enum diff --git a/include/list_menu.h b/include/list_menu.h index 17587afa1d..184b9c416f 100644 --- a/include/list_menu.h +++ b/include/list_menu.h @@ -27,6 +27,28 @@ enum { SCROLL_ARROW_DOWN }; +// For ListMenuGet/SetTemplateField +enum ListMenuFields +{ + LISTFIELD_MOVECURSORFUNC = 0, + LISTFIELD_MOVECURSORFUNC2, + LISTFIELD_TOTALITEMS, + LISTFIELD_MAXSHOWED, + LISTFIELD_WINDOWID, + LISTFIELD_HEADERX, + LISTFIELD_ITEMX, + LISTFIELD_CURSORX, + LISTFIELD_UPTEXTY, + LISTFIELD_CURSORPAL, + LISTFIELD_FILLVALUE, + LISTFIELD_CURSORSHADOWPAL, + LISTFIELD_LETTERSPACING, + LISTFIELD_ITEMVERTICALPADDING, + LISTFIELD_SCROLLMULTIPLE, + LISTFIELD_FONTID, + LISTFIELD_CURSORKIND, +}; + struct ListMenu; struct ListMenuItem @@ -121,8 +143,8 @@ void ListMenuGetScrollAndRow(u8 listTaskId, u16 *scrollOffset, u16 *selectedRow) u16 ListMenuGetYCoordForPrintingArrowCursor(u8 listTaskId); void ListMenuOverrideSetColors(u8 cursorPal, u8 fillValue, u8 cursorShadowPal); void ListMenuDefaultCursorMoveFunc(s32 itemIndex, bool8 onInit, struct ListMenu *list); -s32 ListMenuGetUnkIndicatorsStructFields(u8 taskId, u8 field); -void ListMenuSetUnkIndicatorsStructField(u8 taskId, u8 field, s32 value); +s32 ListMenuGetTemplateField(u8 taskId, u8 field); +void ListMenuSetTemplateField(u8 taskId, u8 field, s32 value); u8 AddScrollIndicatorArrowPair(const struct ScrollArrowsTemplate *arrowInfo, u16 *scrollOffset); u8 AddScrollIndicatorArrowPairParameterized(u32 arrowType, s32 commonPos, s32 firstPos, s32 secondPos, s32 fullyDownThreshold, s32 tileTag, s32 palTag, u16 *scrollOffset); void RemoveScrollIndicatorArrowPair(u8 taskId); diff --git a/include/test/battle.h b/include/test/battle.h index 5e9272c621..575d82e9d3 100644 --- a/include/test/battle.h +++ b/include/test/battle.h @@ -734,7 +734,7 @@ struct BattleTestRunnerState bool8 runThen:1; bool8 runFinally:1; bool8 runningFinally:1; - bool8 tearDownBattle:1; + bool8 hasTornDownBattle:1; struct BattleTestData data; u8 *results; u8 checkProgressParameter; diff --git a/include/test/test.h b/include/test/test.h index ccfc589c21..092b603ec0 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -15,6 +15,7 @@ enum TestResult TEST_RESULT_TIMEOUT, TEST_RESULT_CRASH, TEST_RESULT_TODO, + TEST_RESULT_KNOWN_FAIL, }; struct TestRunner @@ -214,7 +215,7 @@ static inline struct Benchmark BenchmarkStop(void) } while (0) #define KNOWN_FAILING \ - Test_ExpectedResult(TEST_RESULT_FAIL) + Test_ExpectedResult(TEST_RESULT_KNOWN_FAIL) #define KNOWN_LEAKING \ Test_ExpectLeaks(TRUE) diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index d258c28500..dde7434155 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -230,7 +230,7 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) // Get maximum damage mon can deal damageDealt = AI_GetDamage(battler, opposingBattler, i, AI_ATTACKING, gAiLogicData); - if(damageDealt > maxDamageDealt && !AI_DoesChoiceItemBlockMove(battler, aiMove)) + if (damageDealt > maxDamageDealt && !AI_DoesChoiceItemBlockMove(battler, aiMove)) { maxDamageDealt = damageDealt; aiBestMove = aiMove; @@ -272,14 +272,14 @@ static bool32 ShouldSwitchIfHasBadOdds(u32 battler) hitsToKoAI = GetNoOfHitsToKOBattlerDmg(maxDamageTaken, battler); // Check if mon gets one shot - if(maxDamageTaken > gBattleMons[battler].hp + if (maxDamageTaken > gBattleMons[battler].hp && !(gItemsInfo[gBattleMons[battler].item].holdEffect == HOLD_EFFECT_FOCUS_SASH || (!IsMoldBreakerTypeAbility(opposingBattler, gBattleMons[opposingBattler].ability) && B_STURDY >= GEN_5 && aiAbility == ABILITY_STURDY))) { getsOneShot = TRUE; } // Check if current mon can 1v1 in spite of bad matchup, and don't switch out if it can - if(hitsToKoPlayer < hitsToKoAI || (hitsToKoPlayer == hitsToKoAI && AI_IsFaster(battler, opposingBattler, aiBestMove))) + if (hitsToKoPlayer < hitsToKoAI || (hitsToKoPlayer == hitsToKoAI && AI_IsFaster(battler, opposingBattler, aiBestMove))) return FALSE; // If we don't have any other viable options, don't switch out @@ -1702,7 +1702,7 @@ static u32 GetSwitchinRecurringDamage(void) else if (holdEffect == HOLD_EFFECT_STICKY_BARB) { passiveDamage = maxHP / 8; - if(passiveDamage == 0) + if (passiveDamage == 0) passiveDamage = 1; } } @@ -1727,7 +1727,7 @@ static u32 GetSwitchinStatusDamage(u32 battler) statusDamage = maxHP / 16; else statusDamage = maxHP / 8; - if(ability == ABILITY_HEATPROOF) + if (ability == ABILITY_HEATPROOF) statusDamage = statusDamage / 2; if (statusDamage == 0) statusDamage = 1; @@ -2095,10 +2095,10 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, } // Track max hits to KO and set defensive mon - if(hitsToKOAI > maxHitsToKO && (canSwitchinWin1v1 || gAiThinkingStruct->aiFlags[battler] & AI_FLAG_STALL)) + if (hitsToKOAI > maxHitsToKO && (canSwitchinWin1v1 || gAiThinkingStruct->aiFlags[battler] & AI_FLAG_STALL)) { maxHitsToKO = hitsToKOAI; - if(maxHitsToKO > defensiveMonHitKOThreshold) + if (maxHitsToKO > defensiveMonHitKOThreshold) defensiveMonId = i; } @@ -2126,7 +2126,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId, // Check that mon isn't one shot and set best damage mon if (damageDealt > maxDamageDealt) { - if((isFreeSwitch && hitsToKOAI > 1) || hitsToKOAI > 2) // This is a "default", we have uniquely low standards + if ((isFreeSwitch && hitsToKOAI > 1) || hitsToKOAI > 2) // This is a "default", we have uniquely low standards { maxDamageDealt = damageDealt; damageMonId = i; diff --git a/src/battle_ai_util.c b/src/battle_ai_util.c index cc692fbcb7..dc479b732e 100644 --- a/src/battle_ai_util.c +++ b/src/battle_ai_util.c @@ -883,7 +883,7 @@ static bool32 AI_IsMoveEffectInPlus(u32 battlerAtk, u32 battlerDef, u32 move, s3 return TRUE; break; case EFFECT_PURSUIT: - if(noOfHitsToKo == 1) + if (noOfHitsToKo == 1) return TRUE; break; default: diff --git a/src/battle_anim_effects_1.c b/src/battle_anim_effects_1.c index d7dbfa36b2..bc3b4a2c44 100644 --- a/src/battle_anim_effects_1.c +++ b/src/battle_anim_effects_1.c @@ -4595,20 +4595,18 @@ static void AnimPresent(struct Sprite *sprite) static void AnimKnockOffOpponentsItem(struct Sprite *sprite) { - int zero; sprite->data[0] += ((sprite->data[3] * 128) / sprite->data[4]); - zero = 0; if (sprite->data[0] > 0x7F) { sprite->data[1]++; - sprite->data[0] = zero; + sprite->data[0] = 0; } sprite->y2 = Sin(sprite->data[0] + 0x80, 30 - sprite->data[1] * 8); if (moveAlongLinearPath(sprite)) { - sprite->y2 = zero; - sprite->data[0] = zero; + sprite->y2 = 0; + sprite->data[0] = 0; DestroyAnimSprite(sprite); } } @@ -4686,13 +4684,11 @@ static void AnimItemSteal(struct Sprite *sprite) static void AnimItemSteal_Step3(struct Sprite *sprite) { - int zero; sprite->data[0] += ((sprite->data[3] * 128) / sprite->data[4]); - zero = 0; if (sprite->data[0] > 127) { sprite->data[1]++; - sprite->data[0] = zero; + sprite->data[0] = 0; } sprite->y2 = Sin(sprite->data[0] + 0x80, 30 - sprite->data[1] * 8); diff --git a/src/battle_anim_throw.c b/src/battle_anim_throw.c index fe27b7138a..54f16003be 100644 --- a/src/battle_anim_throw.c +++ b/src/battle_anim_throw.c @@ -2062,7 +2062,7 @@ static void RepeatBallOpenParticleAnimation(u8 taskId) priority = gTasks[taskId].data[3]; subpriority = gTasks[taskId].data[4]; - for (i = 0; i < POKEBALL_COUNT; i++) + for (i = 0; i < 12; i++) { spriteId = CreateSprite(&sBallParticleSpriteTemplates[ballId], x, y, subpriority); if (spriteId != MAX_SPRITES) diff --git a/src/battle_main.c b/src/battle_main.c index 98697e4f97..acfbac6061 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -434,10 +434,6 @@ void CB2_InitBattle(void) AllocateMonSpritesGfx(); RecordedBattle_ClearFrontierPassFlag(); -#if T_SHOULD_RUN_MOVE_ANIM - gLoadFail = FALSE; -#endif // T_SHOULD_RUN_MOVE_ANIM - #if T_SHOULD_RUN_MOVE_ANIM gLoadFail = FALSE; #endif // T_SHOULD_RUN_MOVE_ANIM @@ -3107,7 +3103,7 @@ static void BattleStartClearSetData(void) gSelectedMonPartyId = PARTY_SIZE; // Revival Blessing gCategoryIconSpriteId = 0xFF; - if(IsSleepClauseEnabled()) + if (IsSleepClauseEnabled()) { // If monCausingSleepClause[side] equals PARTY_SIZE, Sleep Clause is not active for the given side. gBattleStruct->monCausingSleepClause[B_SIDE_PLAYER] = PARTY_SIZE; @@ -4920,8 +4916,8 @@ s32 GetWhichBattlerFasterOrTies(u32 battler1, u32 battler2, bool32 ignoreChosenM } // 24 == MAX_BATTLERS_COUNT!. -// These are the possible orders if all the battlers speed tie. An order -// is chosen at the start of the turn. +// These are the possible orders if all the battlers speed tie. +// An order is chosen at the start of the turn. static const u8 sBattlerOrders[24][4] = { { 0, 1, 2, 3 }, diff --git a/src/battle_pyramid_bag.c b/src/battle_pyramid_bag.c index f4c544dd02..4a5d1c3a4e 100644 --- a/src/battle_pyramid_bag.c +++ b/src/battle_pyramid_bag.c @@ -1331,7 +1331,7 @@ static void Task_BeginItemSwap(u8 taskId) tListPos = gPyramidBagMenuState.scrollPosition + gPyramidBagMenuState.cursorPosition; gPyramidBagMenu->toSwapPos = tListPos; - ListMenuSetUnkIndicatorsStructField(tListTaskId, 0x10, 1); + ListMenuSetTemplateField(tListTaskId, LISTFIELD_CURSORKIND, CURSOR_INVISIBLE); CopyItemName(gSaveBlock2Ptr->frontier.pyramidBag.itemId[gSaveBlock2Ptr->frontier.lvlMode][tListPos], gStringVar1); StringExpandPlaceholders(gStringVar4, gText_MoveVar1Where); FillWindowPixelBuffer(WIN_INFO, PIXEL_FILL(0)); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 1d7f2579e8..82181b1de0 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -343,7 +343,7 @@ static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent); static void TryUpdateEvolutionTracker(u32 evolutionCondition, u32 upAmount, u16 usedMove); static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u8 *failInstr, u16 move); static void ResetValuesForCalledMove(void); -static void TryRestoreDamageAfterCheeckPouch(u32 battler); +static void TryRestoreDamageAfterCheekPouch(u32 battler); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); @@ -2732,7 +2732,7 @@ static void Cmd_datahpupdate(void) gBattleStruct->timesGotHit[GetBattlerSide(gBattlerTarget)][gBattlerPartyIndexes[gBattlerTarget]]++; } - TryRestoreDamageAfterCheeckPouch(battler); + TryRestoreDamageAfterCheekPouch(battler); gBattlescriptCurrInstr = cmd->nextInstr; } @@ -8084,21 +8084,21 @@ static bool32 DoSwitchInEffectsForBattler(u32 battler) { if (CanBePoisoned(gBattlerAttacker, battler, GetBattlerAbility(gBattlerAttacker), GetBattlerAbility(battler))) { - u32 tspikes = 0; - if (gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount >= 2) { - tspikes = 1; + gBattleScripting.battler = battler; + BattleScriptPushCursor(); + if (gSideTimers[GetBattlerSide(battler)].toxicSpikesAmount >= 2) + { + gBattlescriptCurrInstr = BattleScript_ToxicSpikesBadlyPoisoned; gBattleMons[battler].status1 |= STATUS1_TOXIC_POISON; } else + { + gBattlescriptCurrInstr = BattleScript_ToxicSpikesPoisoned; gBattleMons[battler].status1 |= STATUS1_POISON; + } BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[battler].status1), &gBattleMons[battler].status1); MarkBattlerForControllerExec(battler); - gBattleScripting.battler = battler; - if (tspikes == 0) - BattleScriptCall(BattleScript_ToxicSpikesPoisoned); - else - BattleScriptCall(BattleScript_ToxicSpikesBadlyPoisoned); } } } @@ -8315,7 +8315,7 @@ static void Cmd_returntoball(void) MarkBattlerForControllerExec(battler); // Don't always execute a form change here otherwise we can stomp gigantamax - if(!cmd->changingForm) + if (!cmd->changingForm) TryBattleFormChange(battler, FORM_CHANGE_BATTLE_SWITCH); gBattlescriptCurrInstr = cmd->nextInstr; @@ -8940,7 +8940,7 @@ static bool32 TryCheekPouch(u32 battler, u32 itemId) } // When Cheek Pouch activates mid-battle it overwrites the current damage, so restore it -static void TryRestoreDamageAfterCheeckPouch(u32 battler) +static void TryRestoreDamageAfterCheekPouch(u32 battler) { if (gBattleStruct->cheekPouchActivated) { @@ -9456,17 +9456,17 @@ static void RemoveAllWeather(void) if (gBattleWeather & B_WEATHER_RAIN) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_RAIN; - else if(gBattleWeather & B_WEATHER_SANDSTORM) + else if (gBattleWeather & B_WEATHER_SANDSTORM) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SANDSTORM; - else if(gBattleWeather & B_WEATHER_SUN) + else if (gBattleWeather & B_WEATHER_SUN) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SUN; - else if(gBattleWeather & B_WEATHER_HAIL) + else if (gBattleWeather & B_WEATHER_HAIL) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_HAIL; - else if(gBattleWeather & B_WEATHER_STRONG_WINDS) + else if (gBattleWeather & B_WEATHER_STRONG_WINDS) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_STRONG_WINDS; - else if(gBattleWeather & B_WEATHER_SNOW) + else if (gBattleWeather & B_WEATHER_SNOW) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_SNOW; - else if(gBattleWeather & B_WEATHER_FOG) + else if (gBattleWeather & B_WEATHER_FOG) gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_FOG; else gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEATHER_END_COUNT; // failsafe @@ -12383,7 +12383,7 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, u32 stats, const gBattleMons[battler].statStages[statId] = MIN_STAT_STAGE; if (gBattleMons[battler].statStages[statId] > MAX_STAT_STAGE) gBattleMons[battler].statStages[statId] = MAX_STAT_STAGE; - + if (ShouldDefiantCompetitiveActivate(battler, battlerAbility)) stats = 0; // use single stat animations when Defiant/Competitive activate else @@ -16119,7 +16119,8 @@ static void Cmd_displaydexinfo(void) } break; case 5: - if (!gPaletteFade.active) { + if (!gPaletteFade.active) + { gBattlescriptCurrInstr = cmd->nextInstr; } break; @@ -16799,7 +16800,7 @@ static void TryUpdateRoundTurnOrder(void) } } - // Get battlers after us using round + // Get battlers after attacker using round for (i = currRounder; i < gBattlersCount; i++) { if (gChosenMoveByBattler[gBattlerByTurnOrder[i]] == MOVE_ROUND) @@ -17578,25 +17579,34 @@ void BS_AllySwitchSwapBattler(void) gBattlescriptCurrInstr = cmd->nextInstr; } -void BS_AllySwitchFailChance(void) +void BS_TryAllySwitch(void) { NATIVE_ARGS(const u8 *failInstr); - if (B_ALLY_SWITCH_FAIL_CHANCE >= GEN_9) + if (!IsBattlerAlive(BATTLE_PARTNER(gBattlerAttacker)) + || (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER) + || (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)) + { + gBattlescriptCurrInstr = cmd->failInstr; + } + else if (B_ALLY_SWITCH_FAIL_CHANCE >= GEN_9) { TryResetProtectUseCounter(gBattlerAttacker); if (sProtectSuccessRates[gDisableStructs[gBattlerAttacker].protectUses] < Random()) { gDisableStructs[gBattlerAttacker].protectUses = 0; gBattlescriptCurrInstr = cmd->failInstr; - return; } else { gDisableStructs[gBattlerAttacker].protectUses++; + gBattlescriptCurrInstr = cmd->nextInstr; } } - gBattlescriptCurrInstr = cmd->nextInstr; + else + { + gBattlescriptCurrInstr = cmd->nextInstr; + } } void BS_RunStatChangeItems(void) @@ -17874,7 +17884,7 @@ void BS_TryTarShot(void) void BS_CanTarShotWork(void) { NATIVE_ARGS(const u8 *failInstr); - // Tar Shot will fail if it's already been used on the target and its speed can't be lowered further + // Tar Shot will fail if it's already been used on the target or if its speed can't be lowered further if (!gDisableStructs[gBattlerTarget].tarShot && CompareStat(gBattlerTarget, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) gBattlescriptCurrInstr = cmd->nextInstr; @@ -18527,7 +18537,7 @@ void BS_JumpIfIntimidateAbilityPrevented(void) } } -void BS_TryIntimidatEjectpack(void) +void BS_TryIntimidateEjectPack(void) { NATIVE_ARGS(); diff --git a/src/battle_util.c b/src/battle_util.c index 6937acc088..aa7ca68ecc 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -922,7 +922,7 @@ void HandleAction_ActionFinished(void) // We recalculate order only for action of the same priority. If any action other than switch/move has been taken, they should // have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder - if((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)) + if ((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE)) { if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1) SwapTurnOrder(i, j); diff --git a/src/berry.c b/src/berry.c index fd6cac9679..cb8a06ef5b 100644 --- a/src/berry.c +++ b/src/berry.c @@ -2047,15 +2047,9 @@ static u8 GetNumStagesWateredByBerryTreeId(u8 id) return BerryTreeGetNumStagesWatered(GetBerryTreeInfo(id)); } -// Berries can be watered at 4 stages of growth. This function is likely meant -// to divide the berry yield range equally into quartiles. If you watered the -// tree n times, your yield is a random number in the nth quartile. -// -// However, this function actually skews towards higher berry yields, because -// it rounds `extraYield` to the nearest whole number. -// -// See resulting yields: https://gist.github.com/hondew/2a099dbe54aa91414decdbfaa524327d, -// and bug fix: https://gist.github.com/hondew/0f0164e5b9dadfd72d24f30f2c049a0b. +// Berries can be watered at 4 stages of growth. The distribution is largely +// even but slightly prefers middle berry yields, since it uniformly draws from +// a subset of the total yield range. static u8 CalcBerryYieldInternal(u16 max, u16 min, u8 water) { u32 randMin; diff --git a/src/data/battle_move_effects.h b/src/data/battle_move_effects.h index 685ea8447d..ca7e866e9c 100644 --- a/src/data/battle_move_effects.h +++ b/src/data/battle_move_effects.h @@ -1255,7 +1255,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] = [EFFECT_MIRACLE_EYE] = { - .battleScript = BattleScript_EffectMircleEye, + .battleScript = BattleScript_EffectMiracleEye, .battleTvScore = 0, // TODO: Assign points .encourageEncore = TRUE, }, diff --git a/src/follower_npc.c b/src/follower_npc.c index 40b08cb365..0a8cde49c8 100644 --- a/src/follower_npc.c +++ b/src/follower_npc.c @@ -1172,7 +1172,7 @@ void CreateFollowerNPCAvatar(void) void FollowerNPC_HandleSprite(void) { - if (CheckFollowerNPCFlag(FOLLOWER_NPC_FLAG_CAN_BIKE)) + if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_BIKE) && CheckFollowerNPCFlag(FOLLOWER_NPC_FLAG_CAN_BIKE)) { if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_MACH_BIKE) SetFollowerNPCSprite(FOLLOWER_NPC_SPRITE_INDEX_MACH_BIKE); @@ -1183,7 +1183,7 @@ void FollowerNPC_HandleSprite(void) { TryUpdateFollowerNPCSpriteUnderwater(); } - else + else if (gPlayerAvatar.flags & PLAYER_AVATAR_FLAG_ON_FOOT) { SetFollowerNPCSprite(FOLLOWER_NPC_SPRITE_INDEX_NORMAL); } diff --git a/src/item.c b/src/item.c index 5696b38111..90ca099da0 100644 --- a/src/item.c +++ b/src/item.c @@ -1030,3 +1030,8 @@ u32 GetItemStatus2Mask(u16 itemId) else return 0; } + +u32 GetItemSellPrice(u32 itemId) +{ + return GetItemPrice(itemId) / ITEM_SELL_FACTOR; +} diff --git a/src/item_menu.c b/src/item_menu.c index 77ad2c6155..aa241b7c75 100755 --- a/src/item_menu.c +++ b/src/item_menu.c @@ -1456,7 +1456,7 @@ static void StartItemSwap(u8 taskId) { s16 *data = gTasks[taskId].data; - ListMenuSetUnkIndicatorsStructField(tListTaskId, 16, 1); + ListMenuSetTemplateField(tListTaskId, LISTFIELD_CURSORKIND, CURSOR_INVISIBLE); tListPosition = gBagPosition.scrollPosition[gBagPosition.pocket] + gBagPosition.cursorPosition[gBagPosition.pocket]; gBagMenu->toSwapPos = tListPosition; CopyItemName(GetBagItemId(gBagPosition.pocket, tListPosition), gStringVar1); @@ -2120,6 +2120,11 @@ static void Task_ItemContext_Sell(u8 taskId) } else { + u32 maxQuantity = MAX_MONEY / GetItemSellPrice(gSpecialVar_ItemId); + + if (tQuantity > maxQuantity) + tQuantity = maxQuantity; + CopyItemName(gSpecialVar_ItemId, gStringVar2); StringExpandPlaceholders(gStringVar4, gText_HowManyToSell); DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, InitSellHowManyInput); @@ -2127,13 +2132,11 @@ static void Task_ItemContext_Sell(u8 taskId) } } -#define ITEM_SELL_FACTOR ((I_SELL_VALUE_FRACTION >= GEN_9) ? 4 : 2) - static void DisplaySellItemPriceAndConfirm(u8 taskId) { s16 *data = gTasks[taskId].data; - ConvertIntToDecimalStringN(gStringVar1, (GetItemPrice(gSpecialVar_ItemId) / ITEM_SELL_FACTOR) * tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_MONEY_DIGITS); + ConvertIntToDecimalStringN(gStringVar1, GetItemSellPrice(gSpecialVar_ItemId) * tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_MONEY_DIGITS); StringExpandPlaceholders(gStringVar4, gText_ICanPayVar1); DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, AskSellItems); } @@ -2158,7 +2161,7 @@ static void InitSellHowManyInput(u8 taskId) s16 *data = gTasks[taskId].data; u8 windowId = BagMenu_AddWindow(ITEMWIN_QUANTITY_WIDE); - PrintItemSoldAmount(windowId, 1, (GetItemPrice(gSpecialVar_ItemId) / ITEM_SELL_FACTOR) * tItemCount); + PrintItemSoldAmount(windowId, 1, GetItemSellPrice(gSpecialVar_ItemId) * tItemCount); DisplayCurrentMoneyWindow(); gTasks[taskId].func = Task_ChooseHowManyToSell; } @@ -2169,7 +2172,7 @@ static void Task_ChooseHowManyToSell(u8 taskId) if (AdjustQuantityAccordingToDPadInput(&tItemCount, tQuantity) == TRUE) { - PrintItemSoldAmount(gBagMenu->windowIds[ITEMWIN_QUANTITY_WIDE], tItemCount, (GetItemPrice(gSpecialVar_ItemId) / ITEM_SELL_FACTOR) * tItemCount); + PrintItemSoldAmount(gBagMenu->windowIds[ITEMWIN_QUANTITY_WIDE], tItemCount, GetItemSellPrice(gSpecialVar_ItemId) * tItemCount); } else if (JOY_NEW(A_BUTTON)) { @@ -2193,7 +2196,7 @@ static void ConfirmSell(u8 taskId) s16 *data = gTasks[taskId].data; CopyItemName(gSpecialVar_ItemId, gStringVar2); - ConvertIntToDecimalStringN(gStringVar1, (GetItemPrice(gSpecialVar_ItemId) / ITEM_SELL_FACTOR) * tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_MONEY_DIGITS); + ConvertIntToDecimalStringN(gStringVar1, GetItemSellPrice(gSpecialVar_ItemId) * tItemCount, STR_CONV_MODE_LEFT_ALIGN, MAX_MONEY_DIGITS); StringExpandPlaceholders(gStringVar4, gText_TurnedOverVar1ForVar2); DisplayItemMessage(taskId, FONT_NORMAL, gStringVar4, SellItem); } @@ -2206,7 +2209,7 @@ static void SellItem(u8 taskId) PlaySE(SE_SHOP); RemoveBagItem(gSpecialVar_ItemId, tItemCount); - AddMoney(&gSaveBlock1Ptr->money, (GetItemPrice(gSpecialVar_ItemId) / ITEM_SELL_FACTOR) * tItemCount); + AddMoney(&gSaveBlock1Ptr->money, GetItemSellPrice(gSpecialVar_ItemId) * tItemCount); DestroyListMenuTask(tListTaskId, scrollPos, cursorPos); UpdatePocketItemList(gBagPosition.pocket); UpdatePocketListPosition(gBagPosition.pocket); diff --git a/src/list_menu.c b/src/list_menu.c index e8cb9f16c3..124d39ba43 100644 --- a/src/list_menu.c +++ b/src/list_menu.c @@ -17,29 +17,6 @@ // This allows them to have idle animations. Cursors prior to this are simply printed text. #define CURSOR_OBJECT_START CURSOR_RED_OUTLINE -struct UnkIndicatorsStruct -{ - u8 field_0; - u16 *field_4; - u16 field_8; - u16 field_A; - u16 field_C; - u16 field_E; - u8 field_10; - u8 field_11; - u8 field_12; - u8 field_13; - u8 field_14_0:4; - u8 field_14_1:4; - u8 field_15_0:4; - u8 field_15_1:4; - u8 field_16_0:3; - u8 field_16_1:3; - u8 field_16_2:2; - u8 field_17_0:6; - u8 field_17_1:2; -}; - struct ScrollIndicatorPair { u8 field_0; @@ -916,104 +893,104 @@ void ListMenuDefaultCursorMoveFunc(s32 itemIndex, bool8 onInit, struct ListMenu } // unused -s32 ListMenuGetUnkIndicatorsStructFields(u8 taskId, u8 field) +s32 ListMenuGetTemplateField(u8 taskId, u8 field) { - struct UnkIndicatorsStruct *data = (void *) gTasks[taskId].data; + struct ListMenu *data = (void *) gTasks[taskId].data; switch (field) { - case 0: - case 1: - return (s32)(data->field_4); - case 2: - return data->field_C; - case 3: - return data->field_E; - case 4: - return data->field_10; - case 5: - return data->field_11; - case 6: - return data->field_12; - case 7: - return data->field_13; - case 8: - return data->field_14_0; - case 9: - return data->field_14_1; - case 10: - return data->field_15_0; - case 11: - return data->field_15_1; - case 12: - return data->field_16_0; - case 13: - return data->field_16_1; - case 14: - return data->field_16_2; - case 15: - return data->field_17_0; - case 16: - return data->field_17_1; + case LISTFIELD_MOVECURSORFUNC: + case LISTFIELD_MOVECURSORFUNC2: + return (s32)(data->template.moveCursorFunc); + case LISTFIELD_TOTALITEMS: + return data->template.totalItems; + case LISTFIELD_MAXSHOWED: + return data->template.maxShowed; + case LISTFIELD_WINDOWID: + return data->template.windowId; + case LISTFIELD_HEADERX: + return data->template.header_X; + case LISTFIELD_ITEMX: + return data->template.item_X; + case LISTFIELD_CURSORX: + return data->template.cursor_X; + case LISTFIELD_UPTEXTY: + return data->template.upText_Y; + case LISTFIELD_CURSORPAL: + return data->template.cursorPal; + case LISTFIELD_FILLVALUE: + return data->template.fillValue; + case LISTFIELD_CURSORSHADOWPAL: + return data->template.cursorShadowPal; + case LISTFIELD_LETTERSPACING: + return data->template.lettersSpacing; + case LISTFIELD_ITEMVERTICALPADDING: + return data->template.itemVerticalPadding; + case LISTFIELD_SCROLLMULTIPLE: + return data->template.scrollMultiple; + case LISTFIELD_FONTID: + return data->template.fontId; + case LISTFIELD_CURSORKIND: + return data->template.cursorKind; default: return -1; } } -void ListMenuSetUnkIndicatorsStructField(u8 taskId, u8 field, s32 value) +void ListMenuSetTemplateField(u8 taskId, u8 field, s32 value) { - struct UnkIndicatorsStruct *data = (void *) &gTasks[taskId].data; + struct ListMenu *data = (void *) &gTasks[taskId].data; switch (field) { - case 0: - case 1: - data->field_4 = (void *)(value); + case LISTFIELD_MOVECURSORFUNC: + case LISTFIELD_MOVECURSORFUNC2: + data->template.moveCursorFunc = (void *)value; break; - case 2: - data->field_C = value; + case LISTFIELD_TOTALITEMS: + data->template.totalItems = value; break; - case 3: - data->field_E = value; + case LISTFIELD_MAXSHOWED: + data->template.maxShowed = value; break; - case 4: - data->field_10 = value; + case LISTFIELD_WINDOWID: + data->template.windowId = value; break; - case 5: - data->field_11 = value; + case LISTFIELD_HEADERX: + data->template.header_X = value; break; - case 6: - data->field_12 = value; + case LISTFIELD_ITEMX: + data->template.item_X = value; break; - case 7: - data->field_13 = value; + case LISTFIELD_CURSORX: + data->template.cursor_X = value; break; - case 8: - data->field_14_0 = value; + case LISTFIELD_UPTEXTY: + data->template.upText_Y = value; break; - case 9: - data->field_14_1 = value; + case LISTFIELD_CURSORPAL: + data->template.cursorPal = value; break; - case 10: - data->field_15_0 = value; + case LISTFIELD_FILLVALUE: + data->template.fillValue = value; break; - case 11: - data->field_15_1 = value; + case LISTFIELD_CURSORSHADOWPAL: + data->template.cursorShadowPal = value; break; - case 12: - data->field_16_0 = value; + case LISTFIELD_LETTERSPACING: + data->template.lettersSpacing = value; break; - case 13: - data->field_16_1 = value; + case LISTFIELD_ITEMVERTICALPADDING: + data->template.itemVerticalPadding = value; break; - case 14: - data->field_16_2 = value; + case LISTFIELD_SCROLLMULTIPLE: + data->template.scrollMultiple = value; break; - case 15: - data->field_17_0 = value; + case LISTFIELD_FONTID: + data->template.fontId = value; break; - case 16: - data->field_17_1 = value; + case LISTFIELD_CURSORKIND: + data->template.cursorKind = value; break; } } diff --git a/src/move_relearner.c b/src/move_relearner.c index b48d31677a..7ac7a6bb11 100644 --- a/src/move_relearner.c +++ b/src/move_relearner.c @@ -181,7 +181,7 @@ static EWRAM_DATA struct { u16 listOffset; u16 listRow; bool8 showContestInfo; -} sMoveRelearnerMenuSate = {0}; +} sMoveRelearnerMenuState = {0}; EWRAM_DATA u8 gOriginSummaryScreenPage = 0; // indicates summary screen page that the move relearner was opened from (if opened from PSS) @@ -404,9 +404,9 @@ void CB2_InitLearnMove(void) InitMoveRelearnerBackgroundLayers(); InitMoveRelearnerWindows(gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES); - sMoveRelearnerMenuSate.listOffset = 0; - sMoveRelearnerMenuSate.listRow = 0; - sMoveRelearnerMenuSate.showContestInfo = gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES; + sMoveRelearnerMenuState.listOffset = 0; + sMoveRelearnerMenuState.listRow = 0; + sMoveRelearnerMenuState.showContestInfo = gOriginSummaryScreenPage == PSS_PAGE_CONTEST_MOVES; CreateLearnableMovesList(); @@ -414,7 +414,7 @@ void CB2_InitLearnMove(void) LoadSpritePalette(&sMoveRelearnerPalette); CreateUISprites(); - sMoveRelearnerStruct->moveListMenuTask = ListMenuInit(&gMultiuseListMenuTemplate, sMoveRelearnerMenuSate.listOffset, sMoveRelearnerMenuSate.listRow); + sMoveRelearnerStruct->moveListMenuTask = ListMenuInit(&gMultiuseListMenuTemplate, sMoveRelearnerMenuState.listOffset, sMoveRelearnerMenuState.listRow); SetBackdropFromColor(RGB_BLACK); SetMainCallback2(CB2_MoveRelearnerMain); } @@ -432,14 +432,14 @@ static void CB2_InitLearnMoveReturnFromSelectMove(void) SetVBlankCallback(VBlankCB_MoveRelearner); InitMoveRelearnerBackgroundLayers(); - InitMoveRelearnerWindows(sMoveRelearnerMenuSate.showContestInfo); + InitMoveRelearnerWindows(sMoveRelearnerMenuState.showContestInfo); CreateLearnableMovesList(); LoadSpriteSheet(&sMoveRelearnerSpriteSheet); LoadSpritePalette(&sMoveRelearnerPalette); CreateUISprites(); - sMoveRelearnerStruct->moveListMenuTask = ListMenuInit(&gMultiuseListMenuTemplate, sMoveRelearnerMenuSate.listOffset, sMoveRelearnerMenuSate.listRow); + sMoveRelearnerStruct->moveListMenuTask = ListMenuInit(&gMultiuseListMenuTemplate, sMoveRelearnerMenuState.listOffset, sMoveRelearnerMenuState.listRow); SetBackdropFromColor(RGB_BLACK); SetMainCallback2(CB2_MoveRelearnerMain); } @@ -541,11 +541,11 @@ static void DoMoveRelearnerMain(void) } else if (selection == MENU_B_PRESSED || selection == 1) { - if (sMoveRelearnerMenuSate.showContestInfo == FALSE) + if (sMoveRelearnerMenuState.showContestInfo == FALSE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_BATTLE_MODE; } - else if (sMoveRelearnerMenuSate.showContestInfo == TRUE) + else if (sMoveRelearnerMenuState.showContestInfo == TRUE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_CONTEST_MODE; } @@ -570,11 +570,11 @@ static void DoMoveRelearnerMain(void) } else if (selection == MENU_B_PRESSED || selection == 1) { - if (sMoveRelearnerMenuSate.showContestInfo == FALSE) + if (sMoveRelearnerMenuState.showContestInfo == FALSE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_BATTLE_MODE; } - else if (sMoveRelearnerMenuSate.showContestInfo == TRUE) + else if (sMoveRelearnerMenuState.showContestInfo == TRUE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_CONTEST_MODE; } @@ -630,11 +630,11 @@ static void DoMoveRelearnerMain(void) else if (selection == MENU_B_PRESSED || selection == 1) { // What's the point? It gets set to MENU_STATE_PRINT_TRYING_TO_LEARN_PROMPT, anyway. - if (sMoveRelearnerMenuSate.showContestInfo == FALSE) + if (sMoveRelearnerMenuState.showContestInfo == FALSE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_BATTLE_MODE; } - else if (sMoveRelearnerMenuSate.showContestInfo == TRUE) + else if (sMoveRelearnerMenuState.showContestInfo == TRUE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_CONTEST_MODE; } @@ -646,11 +646,11 @@ static void DoMoveRelearnerMain(void) if (!MoveRelearnerRunTextPrinters()) { FillWindowPixelBuffer(RELEARNERWIN_MSG, 0x11); - if (sMoveRelearnerMenuSate.showContestInfo == FALSE) + if (sMoveRelearnerMenuState.showContestInfo == FALSE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_BATTLE_MODE; } - else if (sMoveRelearnerMenuSate.showContestInfo == TRUE) + else if (sMoveRelearnerMenuState.showContestInfo == TRUE) { sMoveRelearnerStruct->state = MENU_STATE_SETUP_CONTEST_MODE; } @@ -713,11 +713,11 @@ static void DoMoveRelearnerMain(void) case MENU_STATE_FADE_FROM_SUMMARY_SCREEN: BeginNormalPaletteFade(PALETTES_ALL, 0, 16, 0, RGB_BLACK); sMoveRelearnerStruct->state++; - if (sMoveRelearnerMenuSate.showContestInfo == FALSE) + if (sMoveRelearnerMenuState.showContestInfo == FALSE) { HideHeartSpritesAndShowTeachMoveText(TRUE); } - else if (sMoveRelearnerMenuSate.showContestInfo == TRUE) + else if (sMoveRelearnerMenuState.showContestInfo == TRUE) { ShowTeachMoveText(TRUE); } @@ -783,7 +783,7 @@ static void DoMoveRelearnerMain(void) static void FreeMoveRelearnerResources(void) { RemoveScrollArrows(); - DestroyListMenuTask(sMoveRelearnerStruct->moveListMenuTask, &sMoveRelearnerMenuSate.listOffset, &sMoveRelearnerMenuSate.listRow); + DestroyListMenuTask(sMoveRelearnerStruct->moveListMenuTask, &sMoveRelearnerMenuState.listOffset, &sMoveRelearnerMenuState.listRow); FreeAllWindowBuffers(); FREE_AND_SET_NULL(sMoveRelearnerStruct); ResetSpriteData(); @@ -810,7 +810,7 @@ static void HideHeartSpritesAndShowTeachMoveText(bool8 onlyHideSprites) static void HandleInput(bool8 showContest) { s32 itemId = ListMenu_ProcessInput(sMoveRelearnerStruct->moveListMenuTask); - ListMenuGetScrollAndRow(sMoveRelearnerStruct->moveListMenuTask, &sMoveRelearnerMenuSate.listOffset, &sMoveRelearnerMenuSate.listRow); + ListMenuGetScrollAndRow(sMoveRelearnerStruct->moveListMenuTask, &sMoveRelearnerMenuState.listOffset, &sMoveRelearnerMenuState.listRow); switch (itemId) { @@ -824,13 +824,13 @@ static void HandleInput(bool8 showContest) { PutWindowTilemap(RELEARNERWIN_DESC_CONTEST); sMoveRelearnerStruct->state = MENU_STATE_SETUP_CONTEST_MODE; - sMoveRelearnerMenuSate.showContestInfo = TRUE; + sMoveRelearnerMenuState.showContestInfo = TRUE; } else { PutWindowTilemap(RELEARNERWIN_DESC_BATTLE); sMoveRelearnerStruct->state = MENU_STATE_SETUP_BATTLE_MODE; - sMoveRelearnerMenuSate.showContestInfo = FALSE; + sMoveRelearnerMenuState.showContestInfo = FALSE; } ScheduleBgCopyTilemapToVram(1); @@ -859,7 +859,7 @@ static void HandleInput(bool8 showContest) static s32 GetCurrentSelectedMove(void) { - return sMoveRelearnerStruct->menuItems[sMoveRelearnerMenuSate.listRow + sMoveRelearnerMenuSate.listOffset].id; + return sMoveRelearnerStruct->menuItems[sMoveRelearnerMenuState.listRow + sMoveRelearnerMenuState.listOffset].id; } // Theory: This used to make the heart sprites visible again (i.e. @@ -915,7 +915,7 @@ static void AddScrollArrows(void) { gTempScrollArrowTemplate = sMoveListScrollArrowsTemplate; gTempScrollArrowTemplate.fullyDownThreshold = sMoveRelearnerStruct->numMenuChoices - sMoveRelearnerStruct->numToShowAtOnce; - sMoveRelearnerStruct->moveListScrollArrowTask = AddScrollIndicatorArrowPair(&gTempScrollArrowTemplate, &sMoveRelearnerMenuSate.listOffset); + sMoveRelearnerStruct->moveListScrollArrowTask = AddScrollIndicatorArrowPair(&gTempScrollArrowTemplate, &sMoveRelearnerMenuState.listOffset); } } @@ -960,7 +960,7 @@ void MoveRelearnerShowHideHearts(s32 move) u16 numHearts; u16 i; - if (!sMoveRelearnerMenuSate.showContestInfo || move == LIST_CANCEL) + if (!sMoveRelearnerMenuState.showContestInfo || move == LIST_CANCEL) { for (i = 0; i < 16; i++) gSprites[sMoveRelearnerStruct->heartSpriteIds[i]].invisible = TRUE; @@ -999,7 +999,7 @@ void MoveRelearnerShowHideHearts(s32 move) void MoveRelearnerShowHideCategoryIcon(s32 moveId) { - if (sMoveRelearnerMenuSate.showContestInfo || moveId == LIST_CANCEL) + if (sMoveRelearnerMenuState.showContestInfo || moveId == LIST_CANCEL) { if (sMoveRelearnerStruct->categoryIconSpriteId != 0xFF) DestroySprite(&gSprites[sMoveRelearnerStruct->categoryIconSpriteId]); diff --git a/src/overworld.c b/src/overworld.c index de80d85a03..7c579a8785 100644 --- a/src/overworld.c +++ b/src/overworld.c @@ -1815,6 +1815,7 @@ void CB2_WhiteOut(void) else gFieldCallback = FieldCB_WarpExitFadeFromBlack; state = 0; + SetFollowerNPCData(FNPC_DATA_SURF_BLOB, FNPC_SURF_BLOB_NONE); DoMapLoadLoop(&state); SetFieldVBlankCallback(); SetMainCallback1(CB1_Overworld); diff --git a/src/palette.c b/src/palette.c index 5c63a918ad..c4d65404d1 100644 --- a/src/palette.c +++ b/src/palette.c @@ -828,7 +828,7 @@ void BlendPalettes(u32 selectedPalettes, u8 coeff, u32 color) BlendPalettesFine(selectedPalettes, gPlttBufferUnfaded, gPlttBufferFaded, coeff, color); } -#define DEFAULT_LIGHT_COLOR 0x3f9f +#define DEFAULT_LIGHT_COLOR RGB2GBA(248, 224, 120) // Like BlendPalette, but ignores blendColor if the transparency high bit is set // Optimization help by lucktyphlosion diff --git a/src/player_pc.c b/src/player_pc.c index ccd7d36b26..6adb6e17ba 100644 --- a/src/player_pc.c +++ b/src/player_pc.c @@ -1284,7 +1284,7 @@ static void ItemStorage_ExitItemList(u8 taskId) static void ItemStorage_StartItemSwap(u8 taskId) { s16 *data = gTasks[taskId].data; - ListMenuSetUnkIndicatorsStructField(tListTaskId, 16, 1); + ListMenuSetTemplateField(tListTaskId, LISTFIELD_CURSORKIND, CURSOR_INVISIBLE); sItemStorageMenu->toSwapPos = gPlayerPCItemPageInfo.itemsAbove + gPlayerPCItemPageInfo.cursorPos; ItemStorage_SetSwapArrow(tListTaskId, 0, 0); ItemStorage_UpdateSwapLinePos(sItemStorageMenu->toSwapPos); diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 29f4346501..b5de5d7415 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -384,51 +384,11 @@ enum TimeOfDay GetTimeOfDayForEncounters(u32 headerId, enum WildPokemonArea area if (!OW_TIME_OF_DAY_ENCOUNTERS) return TIME_OF_DAY_DEFAULT; - if (InBattlePike()) + if (InBattlePike() || InBattlePyramid()) { - switch (area) - { - default: - case WILD_AREA_LAND: - wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo; - break; - case WILD_AREA_WATER: - wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo; - break; - case WILD_AREA_ROCKS: - wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo; - break; - case WILD_AREA_FISHING: - wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo; - break; - case WILD_AREA_HIDDEN: - wildMonInfo = gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo; - break; - } + return OW_TIME_OF_DAY_FALLBACK; } - else if (InBattlePyramid()) - { - switch (area) - { - default: - case WILD_AREA_LAND: - wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo; - break; - case WILD_AREA_WATER: - wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].waterMonsInfo; - break; - case WILD_AREA_ROCKS: - wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].rockSmashMonsInfo; - break; - case WILD_AREA_FISHING: - wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].fishingMonsInfo; - break; - case WILD_AREA_HIDDEN: - wildMonInfo = gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].hiddenMonsInfo; - break; - } - } - else + else { switch (area) { @@ -732,9 +692,9 @@ bool8 StandardWildEncounter(u16 curMetatileBehavior, u16 prevMetatileBehavior) if (prevMetatileBehavior != curMetatileBehavior && !AllowWildCheckOnNewMetatile()) return FALSE; - else if (WildEncounterCheck(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate, FALSE) != TRUE) + else if (WildEncounterCheck(gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo->encounterRate, FALSE) != TRUE) return FALSE; - else if (TryGenerateWildMon(gBattlePikeWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE) + else if (TryGenerateWildMon(gBattlePyramidWildMonHeaders[headerId].encounterTypes[timeOfDay].landMonsInfo, WILD_AREA_LAND, WILD_CHECK_KEEN_EYE) != TRUE) return FALSE; GenerateBattlePyramidWildMon(); diff --git a/test/battle/ai/ai_switching.c b/test/battle/ai/ai_switching.c index 7a7fd64864..1ab0003f50 100644 --- a/test/battle/ai/ai_switching.c +++ b/test/battle/ai/ai_switching.c @@ -1016,7 +1016,6 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_SWITCHING: AI will switch out if main attac AI_SINGLE_BATTLE_TEST("Switch AI: AI will switch into mon with good type matchup and SE move if current mon has no SE move and no stats raised") { - KNOWN_FAILING; // Either remove or replace the function u32 odds = 0, species = SPECIES_NONE, move = MOVE_NONE; PARAMETRIZE { odds = 33; species = SPECIES_SCIZOR; move = MOVE_X_SCISSOR; } PARAMETRIZE { odds = 50; species = SPECIES_DUSCLOPS; move = MOVE_SHADOW_BALL; } diff --git a/test/battle/gimmick/terastal.c b/test/battle/gimmick/terastal.c index 19f42fbc9d..7ce10a5942 100644 --- a/test/battle/gimmick/terastal.c +++ b/test/battle/gimmick/terastal.c @@ -451,28 +451,6 @@ SINGLE_BATTLE_TEST("(TERA) Double Shock does not remove the user's Electric type } } -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_SCRATCH, MOVE_EARTHQUAKE); TeraType(TYPE_GHOST); } - OPPONENT(SPECIES_DITTO) { TeraType(TYPE_FLYING); } - } WHEN { - TURN { MOVE(player, MOVE_CELEBRATE, gimmick: GIMMICK_TERA); MOVE(opponent, MOVE_TRANSFORM); } - TURN { MOVE(player, MOVE_EARTHQUAKE); } - // TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, MOVE_SCRATCH, target: player, gimmick: GIMMICK_TERA); } - } SCENE { - // turn 2 - MESSAGE("Wobbuffet used Earthquake!"); - ANIMATION(ANIM_TYPE_MOVE, MOVE_EARTHQUAKE, player); - HP_BAR(opponent); - // turn 3 - MESSAGE("Wobbuffet used Scratch!"); - 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) { diff --git a/test/battle/hold_effect/jaboca_berry.c b/test/battle/hold_effect/jaboca_berry.c index cdb5cbfacd..29658c7fe1 100644 --- a/test/battle/hold_effect/jaboca_berry.c +++ b/test/battle/hold_effect/jaboca_berry.c @@ -40,7 +40,7 @@ SINGLE_BATTLE_TEST("Jaboca Berry causes the attacker to lose 1/8 of its max HP i } } -SINGLE_BATTLE_TEST("Jaboca Berry tirggers before Bug Bite can steal it") +SINGLE_BATTLE_TEST("Jaboca Berry triggers before Bug Bite can steal it") { KNOWN_FAILING; GIVEN { diff --git a/test/battle/move_effect/acupressure.c b/test/battle/move_effect/acupressure.c index 02be60725d..6eaade94ae 100644 --- a/test/battle/move_effect/acupressure.c +++ b/test/battle/move_effect/acupressure.c @@ -1,7 +1,7 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Acupressure increases one of two stats by 2 stages at random"); +TO_DO_BATTLE_TEST("Acupressure increases one of its stats by 2 stages at random"); TO_DO_BATTLE_TEST("Acupressure doesn't try to increase a stat that has been maximized"); TO_DO_BATTLE_TEST("Acupressure fails on the user if all of its stats are maximized"); TO_DO_BATTLE_TEST("Acupressure fails on the ally if all of its stats are maximized"); diff --git a/test/battle/move_effect/aura_wheel.c b/test/battle/move_effect/aura_wheel.c index 18602b8bc9..3e26176eee 100644 --- a/test/battle/move_effect/aura_wheel.c +++ b/test/battle/move_effect/aura_wheel.c @@ -52,10 +52,9 @@ SINGLE_BATTLE_TEST("Aura Wheel changes type depending on Morpeko's form") SINGLE_BATTLE_TEST("Aura Wheel can be used by Pokémon transformed into Morpeko") { - KNOWN_FAILING; // Aura Wheel for some reason isn't used by the opponent? GIVEN { - PLAYER(SPECIES_MORPEKO) { Ability(ABILITY_HUNGER_SWITCH); } - OPPONENT(SPECIES_DITTO) { Ability(ABILITY_IMPOSTER); } + PLAYER(SPECIES_MORPEKO) { Moves(MOVE_AURA_WHEEL, MOVE_CELEBRATE); Ability(ABILITY_HUNGER_SWITCH); } + OPPONENT(SPECIES_DITTO) { Moves(MOVE_AURA_WHEEL, MOVE_CELEBRATE); Ability(ABILITY_IMPOSTER); } } WHEN { TURN { MOVE(opponent, MOVE_AURA_WHEEL); } } SCENE { diff --git a/test/battle/move_effect/blizzard.c b/test/battle/move_effect/blizzard.c deleted file mode 100644 index 1e566f98fc..0000000000 --- a/test/battle/move_effect/blizzard.c +++ /dev/null @@ -1,4 +0,0 @@ -#include "global.h" -#include "test/battle.h" - -TO_DO_BATTLE_TEST("Blizzard ignores accuracy check durin Hail and Snow"); diff --git a/test/battle/move_effect/bulk_up.c b/test/battle/move_effect/bulk_up.c index 7f47d5d48e..be0536f4ca 100644 --- a/test/battle/move_effect/bulk_up.c +++ b/test/battle/move_effect/bulk_up.c @@ -1,4 +1,22 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Bulk Up increases the user's Attack and Defense"); +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_BULK_UP) == EFFECT_BULK_UP); +} + +SINGLE_BATTLE_TEST("Bulk Up increases the user's Attack and Defense by 1 stage each") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_BULK_UP); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_BULK_UP, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1); + } +} diff --git a/test/battle/move_effect/calm_mind.c b/test/battle/move_effect/calm_mind.c index 66c16361f4..3b2ba76113 100644 --- a/test/battle/move_effect/calm_mind.c +++ b/test/battle/move_effect/calm_mind.c @@ -1,4 +1,22 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Calm Mind increases the user's Sp. Attack and Sp. Defense by 1 stage each"); +ASSUMPTIONS +{ + ASSUME(GetMoveEffect(MOVE_CALM_MIND) == EFFECT_CALM_MIND); +} + +SINGLE_BATTLE_TEST("Calm Mind increases the user's Sp. Attack and Sp. Defense by 1 stage each") +{ + GIVEN { + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + TURN { MOVE(player, MOVE_CALM_MIND); } + } SCENE { + ANIMATION(ANIM_TYPE_MOVE, MOVE_CALM_MIND, player); + } THEN { + EXPECT_EQ(player->statStages[STAT_SPATK], DEFAULT_STAT_STAGE + 1); + EXPECT_EQ(player->statStages[STAT_SPDEF], DEFAULT_STAT_STAGE + 1); + } +} diff --git a/test/battle/move_effect/expanding_force.c b/test/battle/move_effect/expanding_force.c index 74b78fdd86..7b0284390b 100644 --- a/test/battle/move_effect/expanding_force.c +++ b/test/battle/move_effect/expanding_force.c @@ -1,4 +1,28 @@ #include "global.h" #include "test/battle.h" -TO_DO_BATTLE_TEST("Expanding Force's power increases by 50% if the user is affected by Psychic Terrain"); +SINGLE_BATTLE_TEST("Expanding Force's power increases by 50% if the user is affected by Psychic Terrain", s16 damage) +{ + bool32 terrain; + PARAMETRIZE { terrain = FALSE; } + PARAMETRIZE { terrain = TRUE; } + GIVEN { + ASSUME(GetMoveEffect(MOVE_EXPANDING_FORCE) == EFFECT_EXPANDING_FORCE); + PLAYER(SPECIES_WOBBUFFET); + OPPONENT(SPECIES_WOBBUFFET); + } WHEN { + if (terrain) + TURN { MOVE(player, MOVE_PSYCHIC_TERRAIN); } + TURN { MOVE(player, MOVE_EXPANDING_FORCE); } + } SCENE { + MESSAGE("Wobbuffet used Expanding Force!"); + HP_BAR(opponent, captureDamage: &results[i].damage); + } FINALLY { + if (B_TERRAIN_TYPE_BOOST >= GEN_8) + // 1.3 Terrain boost x 1.5 effect boost = 1.95 boost + EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.95), results[1].damage); + else + // 1.5 Terrain boost x 1.5 effect boost = 2.25 boost + EXPECT_MUL_EQ(results[0].damage, Q_4_12(2.25), results[1].damage); + } +} diff --git a/test/battle/move_effect/transform.c b/test/battle/move_effect/transform.c index fd6e5f5a94..bf2bd66143 100644 --- a/test/battle/move_effect/transform.c +++ b/test/battle/move_effect/transform.c @@ -2,3 +2,29 @@ #include "test/battle.h" TO_DO_BATTLE_TEST("TODO: Write Transform (Move Effect) test titles") + +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") +{ + u32 playerDoTera; + PARAMETRIZE { playerDoTera = GIMMICK_TERA; } + PARAMETRIZE { playerDoTera = GIMMICK_NONE; } + GIVEN { + PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_SCRATCH, MOVE_EARTHQUAKE); TeraType(TYPE_GHOST); } + OPPONENT(SPECIES_DITTO) { TeraType(TYPE_FLYING); } + } WHEN { + TURN { MOVE(player, MOVE_CELEBRATE, gimmick: playerDoTera); MOVE(opponent, MOVE_TRANSFORM); } + TURN { MOVE(player, MOVE_SCRATCH); MOVE(opponent, moveSlot: 0); } + TURN { MOVE(player, MOVE_EARTHQUAKE); MOVE(opponent, moveSlot: 0, gimmick: GIMMICK_TERA); } + } SCENE { + // turn 1 + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_TRANSFORM, opponent); + // turn 2 + ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player); + ANIMATION(ANIM_TYPE_MOVE, MOVE_CELEBRATE, opponent); + // turn 3 + MESSAGE("Wobbuffet used Earthquake!"); + MESSAGE("It doesn't affect the opposing Ditto…"); + NOT { HP_BAR(opponent); } + } +} diff --git a/test/battle/move_flags/always_hits_in_hail_snow.c b/test/battle/move_flags/always_hits_in_hail_snow.c index 5673c0df8a..788186e7b5 100644 --- a/test/battle/move_flags/always_hits_in_hail_snow.c +++ b/test/battle/move_flags/always_hits_in_hail_snow.c @@ -6,6 +6,7 @@ SINGLE_BATTLE_TEST("Blizzard bypasses accuracy checks in Hail and Snow") u32 move; PARAMETRIZE { move = MOVE_HAIL; } PARAMETRIZE { move = MOVE_SNOWSCAPE; } + PASSES_RANDOMLY(100, 100, RNG_ACCURACY); GIVEN { ASSUME(GetMoveAccuracy(MOVE_BLIZZARD) == 70); ASSUME(MoveAlwaysHitsInHailSnow(MOVE_BLIZZARD)); diff --git a/test/test_runner.c b/test/test_runner.c index 8ca5b488e3..a1460365e0 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -312,7 +312,9 @@ top: const char *color; const char *result; - if (gTestRunnerState.result == gTestRunnerState.expectedResult) + if (gTestRunnerState.result == gTestRunnerState.expectedResult + || (gTestRunnerState.result == TEST_RESULT_FAIL + && gTestRunnerState.expectedResult == TEST_RESULT_KNOWN_FAIL)) { color = "\e[32m"; Test_MgbaPrintf(":N%s", gTestRunnerState.test->name); @@ -330,7 +332,7 @@ top: switch (gTestRunnerState.result) { case TEST_RESULT_FAIL: - if (gTestRunnerState.expectedResult == TEST_RESULT_FAIL) + if (gTestRunnerState.expectedResult == TEST_RESULT_KNOWN_FAIL) { result = "KNOWN_FAILING"; color = "\e[33m"; @@ -387,7 +389,9 @@ top: Test_MgbaPrintf(":A%s%s\e[0m", color, result); else if (gTestRunnerState.result == TEST_RESULT_TODO) Test_MgbaPrintf(":T%s%s\e[0m", color, result); - else if (gTestRunnerState.expectedResult == gTestRunnerState.result) + else if (gTestRunnerState.expectedResult == gTestRunnerState.result + || (gTestRunnerState.result == TEST_RESULT_FAIL + && gTestRunnerState.expectedResult == TEST_RESULT_KNOWN_FAIL)) Test_MgbaPrintf(":K%s%s\e[0m", color, result); else Test_MgbaPrintf(":F%s%s\e[0m", color, result); diff --git a/test/test_runner_battle.c b/test/test_runner_battle.c index 981683b35a..7884993a1c 100644 --- a/test/test_runner_battle.c +++ b/test/test_runner_battle.c @@ -181,6 +181,7 @@ static void BattleTest_SetUp(void *data) STATE->battlersCount = 4; break; } + STATE->hasTornDownBattle = FALSE; } static void PrintTestName(void) @@ -284,16 +285,17 @@ static void BattleTest_Run(void *data) break; } - for (i = 0; i < STATE->battlersCount; i++) + for (i = 0; i < MAX_LINK_PLAYERS; i++) { DATA.recordedBattle.playersName[i][0] = CHAR_1 + i; DATA.recordedBattle.playersName[i][1] = EOS; DATA.recordedBattle.playersLanguage[i] = GAME_LANGUAGE; DATA.recordedBattle.playersBattlers[i] = i; - - DATA.currentMonIndexes[i] = (i & BIT_FLANK) == B_FLANK_LEFT ? 0 : 1; } + for (i = 0; i < STATE->battlersCount; i++) + DATA.currentMonIndexes[i] = i / 2; + STATE->runRandomly = TRUE; STATE->runGiven = TRUE; STATE->runWhen = TRUE; @@ -1419,8 +1421,11 @@ static void BattleTest_TearDown(void *data) // aborted unexpectedly. ClearFlagAfterTest(); TestFreeConfigData(); - if (STATE->tearDownBattle) + if (!STATE->hasTornDownBattle) + { TearDownBattle(); + STATE->hasTornDownBattle = TRUE; + } } static bool32 BattleTest_CheckProgress(void *data) @@ -1448,7 +1453,6 @@ static bool32 BattleTest_HandleExitWithResult(void *data, enum TestResult result } else { - STATE->tearDownBattle = TRUE; return FALSE; } }