Remove trailing whitespace (master) (#5174)

This commit is contained in:
Eduardo Quezada 2024-08-14 22:48:20 -04:00 committed by GitHub
parent e3d9bb643f
commit 18980b20a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 210 additions and 210 deletions

View file

@ -327,7 +327,7 @@ If this works, then proceed to [Installation](#installation). Otherwise, ask for
libpng is now installed. libpng is now installed.
Continue to [Installing pkg-config (macOS)](#installing-pkg-config-macos) if **pkg-config is not installed**. Otherwise, continue to [Installing devkitARM (macOS)](#installing-devkitarm-macos) if **devkitARM is not installed**. Continue to [Installing pkg-config (macOS)](#installing-pkg-config-macos) if **pkg-config is not installed**. Otherwise, continue to [Installing devkitARM (macOS)](#installing-devkitarm-macos) if **devkitARM is not installed**.
If both pkg-config and devkitARM are already installed, go to [Choosing where to store pokeemerald Expansion (macOS)](#choosing-where-to-store-pokeemerald-expansion-macos). If both pkg-config and devkitARM are already installed, go to [Choosing where to store pokeemerald Expansion (macOS)](#choosing-where-to-store-pokeemerald-expansion-macos).
### Installing pkg-config (macOS) ### Installing pkg-config (macOS)
@ -541,7 +541,7 @@ If this works, then proceed to [Installation](#installation). Otherwise, ask for
> ``` > ```
> Where *\<folder where pokeemerald-expansion is to be stored>* is the path of the folder [where you chose to store pokeemerald Expansion](#Choosing-where-to-store-pokeemerald-expansion-WSL1). Then run the `git clone` command again. > Where *\<folder where pokeemerald-expansion is to be stored>* is the path of the folder [where you chose to store pokeemerald Expansion](#Choosing-where-to-store-pokeemerald-expansion-WSL1). Then run the `git clone` command again.
</details> </details>
Now you're ready to build pokeemerald Expansion. Now you're ready to build pokeemerald Expansion.
## Build pokeemerald Expansion ## Build pokeemerald Expansion

View file

@ -45,7 +45,7 @@ BattleScript_UseItemMessage:
printfromtable gTrainerUsedItemStringIds printfromtable gTrainerUsedItemStringIds
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
return return
BattleScript_ItemRestoreHPRet: BattleScript_ItemRestoreHPRet:
bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT bichalfword gMoveResultFlags, MOVE_RESULT_NO_EFFECT
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE

View file

@ -59,6 +59,6 @@ def rellocate_follower_graphics():
#os.popen('cp followers/' + name + '.png followers/' + name + '/follower.png') #os.popen('cp followers/' + name + '.png followers/' + name + '/follower.png')
#os.remove('followers/' + name + '.png') #os.remove('followers/' + name + '.png')
#print(pth) #print(pth)
#subprocess.run(["tools/gbagfx/gbagfx " + name +".png " + name + "_normal.pal'" + str(count) + "'"]) #subprocess.run(["tools/gbagfx/gbagfx " + name +".png " + name + "_normal.pal'" + str(count) + "'"])
rellocate_follower_graphics() rellocate_follower_graphics()

View file

@ -21,14 +21,14 @@ AI: Check Bad Move / Try to Faint / Check Viability. The name of each flag is ju
* Sequence Switching * Sequence Switching
## `COMPETITIVE_PARTY_SYNTAX != TRUE` / Not Found ## `COMPETITIVE_PARTY_SYNTAX != TRUE` / Not Found
If you are not using competitive syntax parties, instead access the trainer data directly in [`src/data/trainers.h`](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainers.h), and add flags like so, typed exactly the same as the flag names themselves: If you are not using competitive syntax parties, instead access the trainer data directly in [`src/data/trainers.h`](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainers.h), and add flags like so, typed exactly the same as the flag names themselves:
`.aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY` `.aiFlags = AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY`
# What AI Flags does pokeemerald-expansion have? # What AI Flags does pokeemerald-expansion have?
This section lists all of expansions AI Flags and briefly describes the effect they have on the AIs behaviour. In all cases, please check the corresponding function or surrounding code around their implementation for more details. Some of these functions are vanilla, some share a name with vanilla but have been modified to varying degrees, and some are completely new. This section lists all of expansions AI Flags and briefly describes the effect they have on the AIs behaviour. In all cases, please check the corresponding function or surrounding code around their implementation for more details. Some of these functions are vanilla, some share a name with vanilla but have been modified to varying degrees, and some are completely new.
## `AI_FLAG_CHECK_BAD_MOVE` ## `AI_FLAG_CHECK_BAD_MOVE`
The AI will avoid using moves that are likely to fail in the current situation. This flag helps prevent the AI from making ineffective choices, such as using moves into immunities, into invulnerable states, or when the moves are otherwise hindered by abilities, terrain, or status conditions. The AI will avoid using moves that are likely to fail in the current situation. This flag helps prevent the AI from making ineffective choices, such as using moves into immunities, into invulnerable states, or when the moves are otherwise hindered by abilities, terrain, or status conditions.
## `AI_FLAG_TRY_TO_FAINT` ## `AI_FLAG_TRY_TO_FAINT`
AI will prioritize KOing the player if able rather than using status moves. Will prioritize using a move that can OHKO the player. If the player can KO the AIs mon and the AIs mon is slower, prioritize priority moves (this does not prevent the AI from switching out instead). AI will prioritize KOing the player if able rather than using status moves. Will prioritize using a move that can OHKO the player. If the player can KO the AIs mon and the AIs mon is slower, prioritize priority moves (this does not prevent the AI from switching out instead).
@ -58,12 +58,12 @@ AI will generally behave more recklessly. This AI enables the following behaviou
* Prioritize Explosion moves * Prioritize Explosion moves
## `AI_FLAG_PREFER_STRONGEST_MOVE` ## `AI_FLAG_PREFER_STRONGEST_MOVE`
Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player. Adds score bonus to any move the AI has that either OHKOs or 2HKOs the player.
Keep in mind that this is a weaker form of `AI_FLAG_TRY_TO_FAINT` at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs. Keep in mind that this is a weaker form of `AI_FLAG_TRY_TO_FAINT` at scoring OHKOs as it does not take into account who is attacking first, it does however handle 2HKOs.
## `AI_FLAG_PREFER_BATON_PASS` ## `AI_FLAG_PREFER_BATON_PASS`
AI prefers raising its own stats if it has >= 60% HP, as well as Ingrain, Aqua Ring, and Protect. Prioritizes Baton Bass if the mon is rooted (Ingrain) or has the Aqua Ring effect, and doesnt if it has been Leech Seeded. AI prefers raising its own stats if it has >= 60% HP, as well as Ingrain, Aqua Ring, and Protect. Prioritizes Baton Bass if the mon is rooted (Ingrain) or has the Aqua Ring effect, and doesnt if it has been Leech Seeded.
## `AI_FLAG_DOUBLE_BATTLE` ## `AI_FLAG_DOUBLE_BATTLE`
This flag is automatically set in double battles, and controls much of the doubles-specific scoring. Ill summarize some of its scoring as follows: This flag is automatically set in double battles, and controls much of the doubles-specific scoring. Ill summarize some of its scoring as follows:
@ -83,7 +83,7 @@ With respect to the AIs mons, in doubles:
In both singles and doubles: In both singles and doubles:
* Prioritizes not using moves that require the user fainting (Destiny Bond, Explosion etc.) and healing moves while on >= 70% HP. * Prioritizes not using moves that require the user fainting (Destiny Bond, Explosion etc.) and healing moves while on >= 70% HP.
* Prioritize not using moves that require the user fainting or losing significant HP (Belly Drum etc) while between 30% and 70% HP * Prioritize not using moves that require the user fainting or losing significant HP (Belly Drum etc) while between 30% and 70% HP
* Prioritize not using setup moves (Light Screen etc.) and Bide while on <= 30% HP * Prioritize not using setup moves (Light Screen etc.) and Bide while on <= 30% HP
With respect to the players mons: With respect to the players mons:
* Prioritize not using many status moves (stat buffs, Poison, Pain Split) if the player has between 30% and 70% HP * Prioritize not using many status moves (stat buffs, Poison, Pain Split) if the player has between 30% and 70% HP
@ -96,7 +96,7 @@ AI prioritizes setting up field effects (Trick Room, Rain Dance, etc.) and side
AI does not understand ability suppression (Mold Breaker etc., weather suppression (Air Lock etc.), redirection abilities (Lightningrod etc.) being temporarily removed due to move effects (Sky Drop etc.), or item suppression (Magic Room etc.) and will ignore them. This is a handicap flag. AI does not understand ability suppression (Mold Breaker etc., weather suppression (Air Lock etc.), redirection abilities (Lightningrod etc.) being temporarily removed due to move effects (Sky Drop etc.), or item suppression (Magic Room etc.) and will ignore them. This is a handicap flag.
## `AI_FLAG_WILL_SUICIDE` ## `AI_FLAG_WILL_SUICIDE`
AI prioritizes self destruction moves (Explosion, Memento). AI prioritizes self destruction moves (Explosion, Memento).
## `AI_FLAG_PREFER_STATUS_MOVES` ## `AI_FLAG_PREFER_STATUS_MOVES`
AI gets a score bonus for status moves. This should be combined with `AI_FLAG_CHECK_BAD_MOVE` to prevent using only status moves. AI gets a score bonus for status moves. This should be combined with `AI_FLAG_CHECK_BAD_MOVE` to prevent using only status moves.
@ -127,7 +127,7 @@ Affects when the AI chooses to switch. AI will make smarter decisions about when
Marks the last Pokemon in the party as the Ace Pokemon. It will not be used unless it is the last one remaining, or is forced to be switched in (Roar, U-Turn with 1 mon remaining, etc.) Marks the last Pokemon in the party as the Ace Pokemon. It will not be used unless it is the last one remaining, or is forced to be switched in (Roar, U-Turn with 1 mon remaining, etc.)
## `AI_FLAG_OMNISCIENT` ## `AI_FLAG_OMNISCIENT`
AI has full knowledge of player moves, abilities, and hold items, and can use this knowledge when making decisions. AI has full knowledge of player moves, abilities, and hold items, and can use this knowledge when making decisions.
## `AI_FLAG_SMART_MON_CHOICES` ## `AI_FLAG_SMART_MON_CHOICES`
Affects what the AI chooses to send out after a switch. AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are handled separately. Automatically included when `AI_FLAG_SMART_SWITCHING` is enabled. Affects what the AI chooses to send out after a switch. AI will make smarter decisions when choosing which mon to send out mid-battle and after a KO, which are handled separately. Automatically included when `AI_FLAG_SMART_SWITCHING` is enabled.
@ -148,7 +148,7 @@ And will choose mons after a mid-battle switch prioritizing the following criter
* Has Baton Pass * Has Baton Pass
## `AI_FLAG_CONSERVATIVE` ## `AI_FLAG_CONSERVATIVE`
AI always assumes it will roll the lowest possible result when comparing damage in scoring. AI always assumes it will roll the lowest possible result when comparing damage in scoring.
## `AI_FLAG_SEQUENCE_SWITCHING` ## `AI_FLAG_SEQUENCE_SWITCHING`
AI will always switch out after a KO in exactly party order as defined in the trainer data (ie. slot 1, then 2, then 3, etc.). The AI will never switch out mid-battle unless forced to (Roar etc.). If the AI uses a move that requires a switch where it makes a decision about what to send in (U-Turn etc.), it will always switch out into the lowest available party index. AI will always switch out after a KO in exactly party order as defined in the trainer data (ie. slot 1, then 2, then 3, etc.). The AI will never switch out mid-battle unless forced to (Roar etc.). If the AI uses a move that requires a switch where it makes a decision about what to send in (U-Turn etc.), it will always switch out into the lowest available party index.

View file

@ -92,5 +92,5 @@
* Court Change by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3160 * Court Change by @DizzyEggg in https://github.com/rh-hideout/pokeemerald-expansion/pull/3160
* Item Effects * Item Effects
* Utility Umbrella, by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/2835 * Utility Umbrella, by @AsparagusEduardo in https://github.com/rh-hideout/pokeemerald-expansion/pull/2835
**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.5.1...expansion/1.5.2 **Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.5.1...expansion/1.5.2

View file

@ -9,8 +9,8 @@
## CRITICAL FIX, please update to avoid the issues detailed down below: ## CRITICAL FIX, please update to avoid the issues detailed down below:
- Fixed memory corruption when handling trigger sprites by @SBird1337 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3238 - Fixed memory corruption when handling trigger sprites by @SBird1337 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3238
- This had the posibility of manifesting in weird ways, like camera and music changes, NPC duplication and more. If you've had this issue in the past, we ***heavily*** recommend you update to this version of the expansion. - This had the posibility of manifesting in weird ways, like camera and music changes, NPC duplication and more. If you've had this issue in the past, we ***heavily*** recommend you update to this version of the expansion.
- Thank you @Bassoonian for helping us pinpointing the issue. - Thank you @Bassoonian for helping us pinpointing the issue.
![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/26b9b984-c5db-4dac-85f7-5fc4e95a32ce) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/d490eb30-ce54-4b90-bb2e-79c2e9bb50ac) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/26b9b984-c5db-4dac-85f7-5fc4e95a32ce) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/d490eb30-ce54-4b90-bb2e-79c2e9bb50ac)

View file

@ -41,7 +41,7 @@
* Clodsire * Clodsire
* Crocalor * Crocalor
* Dolliv * Dolliv
* Dudunsparce * Dudunsparce
* Esparthra * Esparthra
### Fixed ### Fixed
* Multiple Pokémon graphical fixes by @katykat5099 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3805 * Multiple Pokémon graphical fixes by @katykat5099 in https://github.com/rh-hideout/pokeemerald-expansion/pull/3805

View file

@ -384,7 +384,7 @@ Edit [src/data/text/species_names.h](https://github.com/rh-hideout/pokeemerald-e
const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1] = { const u8 gSpeciesNames[][POKEMON_NAME_LENGTH + 1] = {
[SPECIES_NONE] = _("??????????"), [SPECIES_NONE] = _("??????????"),
[SPECIES_BULBASAUR] = _("Bulbasaur"), [SPECIES_BULBASAUR] = _("Bulbasaur"),
... ...
[SPECIES_ENAMORUS] = _("Enamorus"), [SPECIES_ENAMORUS] = _("Enamorus"),
+ [SPECIES_MEWTHREE] = _("Mewthree"), + [SPECIES_MEWTHREE] = _("Mewthree"),
}; };
@ -482,7 +482,7 @@ Append to [src/data/pokemon/pokedex_text.h](https://github.com/rh-hideout/pokeem
"winter. According to legend, this\n" "winter. According to legend, this\n"
"Pokémon's love gives rise to the\n" "Pokémon's love gives rise to the\n"
"budding of fresh life across the land."); "budding of fresh life across the land.");
+const u8 gMewthreePokedexText[] = _( +const u8 gMewthreePokedexText[] = _(
+ "The rumors became true.\n" + "The rumors became true.\n"
+ "This is Mews final form.\n" + "This is Mews final form.\n"
@ -509,7 +509,7 @@ Edit [src/data/pokemon/pokedex_entries.h](https://github.com/rh-hideout/pokeemer
.trainerScale = 296, .trainerScale = 296,
.trainerOffset = 1, .trainerOffset = 1,
}, },
+ [NATIONAL_DEX_MEWTHREE] = + [NATIONAL_DEX_MEWTHREE] =
+ { + {
+ .categoryName = _("NEW SPECIES"), + .categoryName = _("NEW SPECIES"),
@ -553,7 +553,7 @@ Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemera
NATIONAL_DEX_DUGTRIO, NATIONAL_DEX_DUGTRIO,
... ...
}; };
const u16 gPokedexOrder_Height[] = const u16 gPokedexOrder_Height[] =
{ {
... ...
@ -598,7 +598,7 @@ Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald
}, },
+ [SPECIES_MEWTHREE] = + [SPECIES_MEWTHREE] =
+ { + {
+ .baseHP = 106, + .baseHP = 106,
+ .baseAttack = 150, + .baseAttack = 150,
+ .baseDefense = 70, + .baseDefense = 70,

View file

@ -170,7 +170,7 @@ Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald
}, },
+ [SPECIES_MEWTHREE] = + [SPECIES_MEWTHREE] =
+ { + {
+ .baseHP = 106, + .baseHP = 106,
+ .baseAttack = 150, + .baseAttack = 150,
+ .baseDefense = 70, + .baseDefense = 70,
@ -234,7 +234,7 @@ That's all the basic fields present in vanilla emerald, so now let's take a look
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.isLegendary = TRUE, .isLegendary = TRUE,
.allPerfectIVs = TRUE, .allPerfectIVs = TRUE,
@ -309,7 +309,7 @@ Lastly, we add the cry to our species entry
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.isLegendary = TRUE, .isLegendary = TRUE,
.allPerfectIVs = TRUE, .allPerfectIVs = TRUE,
@ -388,7 +388,7 @@ Now we can add the number and entry to our Mewthree:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.cryId = CRY_MEWTHREE, .cryId = CRY_MEWTHREE,
+ .natDexNum = NATIONAL_DEX_MEWTHREE, + .natDexNum = NATIONAL_DEX_MEWTHREE,
@ -409,7 +409,7 @@ Now we can add the number and entry to our Mewthree:
``` ```
![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f)
The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex.
`height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters). `height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters).
@ -443,7 +443,7 @@ Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemera
NATIONAL_DEX_DUGTRIO, NATIONAL_DEX_DUGTRIO,
... ...
}; };
const u16 gPokedexOrder_Height[] = const u16 gPokedexOrder_Height[] =
{ {
... ...
@ -560,7 +560,7 @@ Now that we have all the external data ready, we just need to add it to `gSpecie
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.pokemonScale = 256, .pokemonScale = 256,
.pokemonOffset = 0, .pokemonOffset = 0,
@ -612,7 +612,7 @@ Let's explain each of these:
- Used to define what Y position of the back sprite. When working with the animation debug menu, we recommend aligning the back sprite to the white background, as it was designed to properyly align with the real battle layout. - Used to define what Y position of the back sprite. When working with the animation debug menu, we recommend aligning the back sprite to the white background, as it was designed to properyly align with the real battle layout.
- `backAnimId`: - `backAnimId`:
- Like `frontAnimId` except for the back sprites and them being a single frame. The IDs listed [here](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h) are used to represent 3 different animations that happen based on the the Pokémon's nature. - Like `frontAnimId` except for the back sprites and them being a single frame. The IDs listed [here](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/pokemon_animation.h) are used to represent 3 different animations that happen based on the the Pokémon's nature.
- `PALETTES` - `PALETTES`
- This macro was created to handle both regular and shiny palettes of a Pokémon. It just needs the species suffix to call the corresponding palette. - This macro was created to handle both regular and shiny palettes of a Pokémon. It just needs the species suffix to call the corresponding palette.
```c ```c
#define PALETTES(pal) \ #define PALETTES(pal) \
@ -650,7 +650,7 @@ We're almost there just a bit left!
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE },
.bodyColor = BODY_COLOR_PURPLE, .bodyColor = BODY_COLOR_PURPLE,
@ -745,7 +745,7 @@ Again, we need to register the learnset in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
PALETTES(Mewthree), PALETTES(Mewthree),
ICON(Mewthree, 2), ICON(Mewthree, 2),
@ -846,7 +846,7 @@ Once more, we need to register the learnset in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
FOOTPRINT(Mewthree) FOOTPRINT(Mewthree)
.levelUpLearnset = sMewthreeLevelUpLearnset, .levelUpLearnset = sMewthreeLevelUpLearnset,
@ -869,7 +869,7 @@ Edit `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTWO] = [SPECIES_MEWTWO] =
{ {
... ...
FOOTPRINT(Mewtwo) FOOTPRINT(Mewtwo)
.isLegendary = TRUE, .isLegendary = TRUE,

View file

@ -181,7 +181,7 @@ Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald
}, },
+ [SPECIES_MEWTHREE] = + [SPECIES_MEWTHREE] =
+ { + {
+ .baseHP = 106, + .baseHP = 106,
+ .baseAttack = 150, + .baseAttack = 150,
+ .baseDefense = 70, + .baseDefense = 70,
@ -245,7 +245,7 @@ That's all the basic fields present in vanilla emerald, so now let's take a look
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.isLegendary = TRUE, .isLegendary = TRUE,
.allPerfectIVs = TRUE, .allPerfectIVs = TRUE,
@ -320,7 +320,7 @@ Lastly, we add the cry to our species entry
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.isLegendary = TRUE, .isLegendary = TRUE,
.allPerfectIVs = TRUE, .allPerfectIVs = TRUE,
@ -399,7 +399,7 @@ Now we can add the number and entry to our Mewthree:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.cryId = CRY_MEWTHREE, .cryId = CRY_MEWTHREE,
+ .natDexNum = NATIONAL_DEX_MEWTHREE, + .natDexNum = NATIONAL_DEX_MEWTHREE,
@ -420,7 +420,7 @@ Now we can add the number and entry to our Mewthree:
``` ```
![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f)
The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex.
`height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters). `height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters).
@ -454,7 +454,7 @@ Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemera
NATIONAL_DEX_DUGTRIO, NATIONAL_DEX_DUGTRIO,
... ...
}; };
const u16 gPokedexOrder_Height[] = const u16 gPokedexOrder_Height[] =
{ {
... ...
@ -571,7 +571,7 @@ Now that we have all the external data ready, we just need to add it to `gSpecie
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.pokemonScale = 256, .pokemonScale = 256,
.pokemonOffset = 0, .pokemonOffset = 0,
@ -651,7 +651,7 @@ We're almost there just a bit left!
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE },
.bodyColor = BODY_COLOR_PURPLE, .bodyColor = BODY_COLOR_PURPLE,
@ -746,7 +746,7 @@ Again, we need to register the learnset in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
PALETTES(Mewthree), PALETTES(Mewthree),
ICON(Mewthree, 2), ICON(Mewthree, 2),
@ -847,7 +847,7 @@ Once more, we need to register the learnset in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
FOOTPRINT(Mewthree) FOOTPRINT(Mewthree)
.levelUpLearnset = sMewthreeLevelUpLearnset, .levelUpLearnset = sMewthreeLevelUpLearnset,
@ -870,7 +870,7 @@ Edit `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTWO] = [SPECIES_MEWTWO] =
{ {
... ...
FOOTPRINT(Mewtwo) FOOTPRINT(Mewtwo)
.isLegendary = TRUE, .isLegendary = TRUE,

View file

@ -176,7 +176,7 @@ Edit [src/data/pokemon/species_info.h](https://github.com/rh-hideout/pokeemerald
}, },
+ [SPECIES_MEWTHREE] = + [SPECIES_MEWTHREE] =
+ { + {
+ .baseHP = 106, + .baseHP = 106,
+ .baseAttack = 150, + .baseAttack = 150,
+ .baseDefense = 70, + .baseDefense = 70,
@ -240,7 +240,7 @@ That's all the basic fields present in vanilla emerald, so now let's take a look
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.isLegendary = TRUE, .isLegendary = TRUE,
.allPerfectIVs = TRUE, .allPerfectIVs = TRUE,
@ -315,7 +315,7 @@ Lastly, we add the cry to our species entry
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.isLegendary = TRUE, .isLegendary = TRUE,
.allPerfectIVs = TRUE, .allPerfectIVs = TRUE,
@ -394,7 +394,7 @@ Now we can add the number and entry to our Mewthree:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.cryId = CRY_MEWTHREE, .cryId = CRY_MEWTHREE,
+ .natDexNum = NATIONAL_DEX_MEWTHREE, + .natDexNum = NATIONAL_DEX_MEWTHREE,
@ -415,7 +415,7 @@ Now we can add the number and entry to our Mewthree:
``` ```
![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f) ![image](https://github.com/rh-hideout/pokeemerald-expansion/assets/2904965/3759dd4c-8da5-4b1c-9a50-b9e9d0815e7f)
The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex. The values `pokemonScale`, `pokemonOffset`, `trainerScale` and `trainerOffset` are used for the height comparison figure in the Pokédex.
`height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters). `height` and `weight` are specified in decimeters and hectograms respectively (which are meters and kilograms multiplied by 10, so 2.5 meters are 25 decimeters).
@ -449,7 +449,7 @@ Edit [src/data/pokemon/pokedex_orders.h](https://github.com/rh-hideout/pokeemera
NATIONAL_DEX_DUGTRIO, NATIONAL_DEX_DUGTRIO,
... ...
}; };
const u16 gPokedexOrder_Height[] = const u16 gPokedexOrder_Height[] =
{ {
... ...
@ -566,7 +566,7 @@ Now that we have all the external data ready, we just need to add it to `gSpecie
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.pokemonScale = 256, .pokemonScale = 256,
.pokemonOffset = 0, .pokemonOffset = 0,
@ -646,7 +646,7 @@ We're almost there just a bit left!
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
.abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE }, .abilities = { ABILITY_INSOMNIA, ABILITY_NONE, ABILITY_NONE },
.bodyColor = BODY_COLOR_PURPLE, .bodyColor = BODY_COLOR_PURPLE,
@ -745,7 +745,7 @@ Again, we need to register the learnset in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
PALETTES(Mewthree), PALETTES(Mewthree),
ICON(Mewthree, 2), ICON(Mewthree, 2),
@ -846,7 +846,7 @@ Once more, we need to register the learnset in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
FOOTPRINT(Mewthree) FOOTPRINT(Mewthree)
.levelUpLearnset = sMewthreeLevelUpLearnset, .levelUpLearnset = sMewthreeLevelUpLearnset,
@ -869,7 +869,7 @@ Edit `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTWO] = [SPECIES_MEWTWO] =
{ {
... ...
FOOTPRINT(Mewtwo) FOOTPRINT(Mewtwo)
.isLegendary = TRUE, .isLegendary = TRUE,
@ -1097,7 +1097,7 @@ And finally, in `gSpeciesInfo`:
{ {
... ...
[SPECIES_MEWTHREE] = [SPECIES_MEWTHREE] =
{ {
... ...
FOOTPRINT(Mewthree) FOOTPRINT(Mewthree)
+ OVERWORLD( + OVERWORLD(

View file

@ -1,11 +1,11 @@
# How to use the Testing System # How to use the Testing System
## Running Tests ## Running Tests
To run all the tests use: To run all the tests use:
`make check -j` `make check -j`
To run specific tests, e.g. Spikes ones, use: To run specific tests, e.g. Spikes ones, use:
`make check TESTS='Spikes'` `make check TESTS='Spikes'`
To build a ROM (pokemerald-test.elf) that can be opened in mgba to view specific tests, e.g. Spikes ones, use: To build a ROM (pokemerald-test.elf) that can be opened in mgba to view specific tests, e.g. Spikes ones, use:
`make pokeemerald-test.elf TESTS='Spikes'` `make pokeemerald-test.elf TESTS='Spikes'`
## How to Write Tests ## How to Write Tests
@ -48,21 +48,21 @@ SINGLE_BATTLE_TEST("Stun Spore inflicts paralysis")
STATUS_ICON(opponent, paralysis: TRUE); // 4. STATUS_ICON(opponent, paralysis: TRUE); // 4.
} }
} }
``` ```
The `ASSUMPTIONS` block documents that Stun Spore has `EFFECT_PARALYZE`. The `ASSUMPTIONS` block documents that Stun Spore has `EFFECT_PARALYZE`.
If Stun Spore did not have that effect it would cause the tests in the file to be skipped. We write our tests like this so that hackers can change the effects of moves without causing tests to fail. If Stun Spore did not have that effect it would cause the tests in the file to be skipped. We write our tests like this so that hackers can change the effects of moves without causing tests to fail.
`SINGLE_BATTLE_TEST` defines the name of the test. Related tests should start with the same prefix, e.g. Stun Spore tests should start with "Stun Spore", this allows just the Stun Spore-related tests to be run with: `SINGLE_BATTLE_TEST` defines the name of the test. Related tests should start with the same prefix, e.g. Stun Spore tests should start with "Stun Spore", this allows just the Stun Spore-related tests to be run with:
`make check TESTS='Stun Spore'` `make check TESTS='Stun Spore'`
`GIVEN` initializes the parties, `PLAYER` and `OPPONENT` add a Pokémon to their respective parties. They can both accept a block which further customizes the Pokémon's stats, moves, item, ability, etc. `GIVEN` initializes the parties, `PLAYER` and `OPPONENT` add a Pokémon to their respective parties. They can both accept a block which further customizes the Pokémon's stats, moves, item, ability, etc.
`WHEN` describes the turns, and `TURN` describes the choices made in a single turn. `MOVE` causes the player to use Stun Spore and adds the move to the Pokémon's moveset if an explicit Moves was not specified. `WHEN` describes the turns, and `TURN` describes the choices made in a single turn. `MOVE` causes the player to use Stun Spore and adds the move to the Pokémon's moveset if an explicit Moves was not specified.
Pokémon that are not mentioned in a `TURN` use Celebrate. Pokémon that are not mentioned in a `TURN` use Celebrate.
The test runner rigs the RNG so that unless otherwise specified, moves always hit, never critical hit, always activate their secondary effects, and always roll the same damage modifier. The test runner rigs the RNG so that unless otherwise specified, moves always hit, never critical hit, always activate their secondary effects, and always roll the same damage modifier.
`SCENE` describes the player-visible output of the battle. In this case `ANIMATION` checks that the Stun Spore animation played, `MESSAGE` checks the paralysis message was shown, and `STATUS_ICON` checks that the opponent's HP bar shows a PRZ icon. `SCENE` describes the player-visible output of the battle. In this case `ANIMATION` checks that the Stun Spore animation played, `MESSAGE` checks the paralysis message was shown, and `STATUS_ICON` checks that the opponent's HP bar shows a PRZ icon.
### Example 2 ### Example 2
As a second example, to manually test that Stun Spore does not effect Grass-types you might: As a second example, to manually test that Stun Spore does not effect Grass-types you might:
@ -90,8 +90,8 @@ SINGLE_BATTLE_TEST("Stun Spore does not affect Grass-types")
} }
} }
``` ```
The `ASSUME` commands are documenting the reasons why Stun Spore does not affect Oddish, namely that Stun Spore is a powder move, and Oddish is a Grass-type. These `ASSUME` statements function similarly to the ones in `ASSUMPTIONS` but apply only to the one test. The `ASSUME` commands are documenting the reasons why Stun Spore does not affect Oddish, namely that Stun Spore is a powder move, and Oddish is a Grass-type. These `ASSUME` statements function similarly to the ones in `ASSUMPTIONS` but apply only to the one test.
NOT inverts the meaning of a `SCENE` check, so applying it to `ANIMATION` requires that the Stun Spore animation does not play. `MESSAGE` checks that the message was shown. NOT inverts the meaning of a `SCENE` check, so applying it to `ANIMATION` requires that the Stun Spore animation does not play. `MESSAGE` checks that the message was shown.
The checks in `SCENE` are ordered, so together this says "The doesn't affect message is shown, and the Stun Spore animation does not play at any time before that". Normally you would only test one or the other, or even better, just `NOT STATUS_ICON(opponent, paralysis: TRUE);` to say that Oddish was not paralyzed without specifying the exact outputs which led to that. The checks in `SCENE` are ordered, so together this says "The doesn't affect message is shown, and the Stun Spore animation does not play at any time before that". Normally you would only test one or the other, or even better, just `NOT STATUS_ICON(opponent, paralysis: TRUE);` to say that Oddish was not paralyzed without specifying the exact outputs which led to that.
### Example 3 ### Example 3
@ -131,9 +131,9 @@ SINGLE_BATTLE_TEST("Meditate raises Attack", s16 damage)
} }
``` ```
`PARAMETRIZE` causes a test to run multiple times, once per `PARAMETRIZE` block (e.g. once with `raiseAttack = FALSE` and once with `raiseAttack = TRUE`). `PARAMETRIZE` causes a test to run multiple times, once per `PARAMETRIZE` block (e.g. once with `raiseAttack = FALSE` and once with `raiseAttack = TRUE`).
The `HP_BAR` command's `captureDamage` causes the change in HP to be stored in a variable, and the variable chosen is `results[i].damage`. The `HP_BAR` command's `captureDamage` causes the change in HP to be stored in a variable, and the variable chosen is `results[i].damage`.
`results[i]` contains all the variables defined at the end of `SINGLE_BATTLE_TEST`, `i` is the current `PARAMETRIZE` index. `results[i]` contains all the variables defined at the end of `SINGLE_BATTLE_TEST`, `i` is the current `PARAMETRIZE` index.
`FINALLY` runs after the last parameter has finished, and uses `EXPECT_MUL_EQ` to check that the second battle deals 1.5× the damage of the first battle (with a small tolerance to account for rounding). `FINALLY` runs after the last parameter has finished, and uses `EXPECT_MUL_EQ` to check that the second battle deals 1.5× the damage of the first battle (with a small tolerance to account for rounding).
You might notice that all the tests check the outputs the player could see rather than the internal battle state. e.g. the Meditate test could have used `gBattleMons[B_POSITION_OPPONENT_LEFT].hp` instead of using `HP_BAR` to capture the damage. This is a deliberate choice, by checking what the player can observe the tests are more robust to refactoring, e.g. if `gBattleMons` got moved into `gBattleStruct` then any test that used it would need to be updated. You might notice that all the tests check the outputs the player could see rather than the internal battle state. e.g. the Meditate test could have used `gBattleMons[B_POSITION_OPPONENT_LEFT].hp` instead of using `HP_BAR` to capture the damage. This is a deliberate choice, by checking what the player can observe the tests are more robust to refactoring, e.g. if `gBattleMons` got moved into `gBattleStruct` then any test that used it would need to be updated.
@ -144,8 +144,8 @@ The overworld is not available, so it is only possible to test commands which do
## REFERENCE ## REFERENCE
### `ASSUME` ### `ASSUME`
`ASSUME(cond)` `ASSUME(cond)`
Causes the test to be skipped if `cond` is false. Used to document any prerequisites of the test, e.g. to test Burn reducing the Attack of a Pokémon we can observe the damage of a physical attack with and without the burn. To document that this test assumes the attack is physical we can use: Causes the test to be skipped if `cond` is false. Used to document any prerequisites of the test, e.g. to test Burn reducing the Attack of a Pokémon we can observe the damage of a physical attack with and without the burn. To document that this test assumes the attack is physical we can use:
`ASSUME(gMovesInfo[MOVE_WHATEVER].category == DAMAGE_CATEGORY_PHYSICAL);` `ASSUME(gMovesInfo[MOVE_WHATEVER].category == DAMAGE_CATEGORY_PHYSICAL);`
### `ASSUMPTIONS` ### `ASSUMPTIONS`
@ -164,16 +164,16 @@ ASSUMPTIONS
``` ```
### `SINGLE_BATTLE_TEST` ### `SINGLE_BATTLE_TEST`
`SINGLE_BATTLE_TEST(name, results...)` and `DOUBLE_BATTLE_TEST(name, results...)` `SINGLE_BATTLE_TEST(name, results...)` and `DOUBLE_BATTLE_TEST(name, results...)`
Define single- and double- battles. The names should start with the name of the mechanic being tested so that it is easier to run all the related tests. `results` contains variable declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands. Define single- and double- battles. The names should start with the name of the mechanic being tested so that it is easier to run all the related tests. `results` contains variable declarations to be placed into the `results` array which is available in tests using `PARAMETRIZE` commands.
The main differences for doubles are: The main differences for doubles are:
- Move targets sometimes need to be explicit. - Move targets sometimes need to be explicit.
- Instead of `player` and `opponent` there is `playerLeft`, `playerRight`, `opponentLeft`, and `opponentRight`. - Instead of `player` and `opponent` there is `playerLeft`, `playerRight`, `opponentLeft`, and `opponentRight`.
### `AI_SINGLE_BATTLE_TEST` ### `AI_SINGLE_BATTLE_TEST`
`AI_SINGLE_BATTLE_TEST(name, results...)` and `AI_DOUBLE_BATTLE_TEST(name, results...)` `AI_SINGLE_BATTLE_TEST(name, results...)` and `AI_DOUBLE_BATTLE_TEST(name, results...)`
Define battles where opponent mons are controlled by AI, the same that runs Define battles where opponent mons are controlled by AI, the same that runs
when battling regular Trainers. The flags for AI should be specified by the `AI_FLAGS` command. when battling regular Trainers. The flags for AI should be specified by the `AI_FLAGS` command.
The rules remain the same as with the `SINGLE` and `DOUBLE` battle tests with some differences: The rules remain the same as with the `SINGLE` and `DOUBLE` battle tests with some differences:
- opponent's action is specified by the `EXPECT_MOVE` / `EXPECT_SEND_OUT` / `EXPECT_SWITCH` commands - opponent's action is specified by the `EXPECT_MOVE` / `EXPECT_SEND_OUT` / `EXPECT_SWITCH` commands
- we don't control what opponent actually does, instead we make sure the opponent does what we expect it to do - we don't control what opponent actually does, instead we make sure the opponent does what we expect it to do
@ -182,7 +182,7 @@ The rules remain the same as with the `SINGLE` and `DOUBLE` battle tests with so
### `KNOWN_FAILING` ### `KNOWN_FAILING`
`KNOWN_FAILING;` `KNOWN_FAILING;`
Marks a test as not passing due to a bug. If there is an issue number associated with the bug it should be included in a comment. If the test passes the developer will be notified to remove `KNOWN_FAILING`. Marks a test as not passing due to a bug. If there is an issue number associated with the bug it should be included in a comment. If the test passes the developer will be notified to remove `KNOWN_FAILING`.
For example: For example:
``` ```
SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target") SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target")
@ -192,7 +192,7 @@ SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target")
} }
``` ```
### `PARAMETRIZE` ### `PARAMETRIZE`
`PARAMETERIZE { parameter; }` `PARAMETERIZE { parameter; }`
Runs a test multiple times. `i` will be set to which parameter is running, and `results` will contain an entry for each parameter, e.g.: Runs a test multiple times. `i` will be set to which parameter is running, and `results` will contain an entry for each parameter, e.g.:
``` ```
SINGLE_BATTLE_TEST("Blaze boosts Fire-type moves in a pinch", s16 damage) SINGLE_BATTLE_TEST("Blaze boosts Fire-type moves in a pinch", s16 damage)
@ -246,7 +246,7 @@ Contains the initial state of the parties before the battle.
## `RNGSeed` ## `RNGSeed`
`RNGSeed(seed)` `RNGSeed(seed)`
Explicitly sets the RNG seed. Try to avoid using this because it is a very fragile tool. Explicitly sets the RNG seed. Try to avoid using this because it is a very fragile tool.
Example: Example:
``` ```
GIVEN { GIVEN {
@ -256,10 +256,10 @@ GIVEN {
``` ```
### `FLAG_SET` ### `FLAG_SET`
`FLAG_SET(flagId)` `FLAG_SET(flagId)`
Sets the specified flag. Can currently only set one flag at a time. Sets the specified flag. Can currently only set one flag at a time.
Cleared between parameters and at the end of the test. Cleared between parameters and at the end of the test.
Example: Example:
``` ```
GIVEN { GIVEN {
FLAG_SET(FLAG_SYS_EXAMPLE_FLAG); FLAG_SET(FLAG_SYS_EXAMPLE_FLAG);
@ -268,8 +268,8 @@ GIVEN {
``` ```
### `PLAYER` and `OPPONENT` ### `PLAYER` and `OPPONENT`
`PLAYER(species)` and `OPPONENT(species` `PLAYER(species)` and `OPPONENT(species`
Adds the species to the player's or opponent's party respectively. Adds the species to the player's or opponent's party respectively.
The Pokémon can be further customized with the following functions: The Pokémon can be further customized with the following functions:
- `Gender(MON_MALE | MON_FEMALE)` - `Gender(MON_MALE | MON_FEMALE)`
- `Nature(nature)` - `Nature(nature)`
@ -280,14 +280,14 @@ The Pokémon can be further customized with the following functions:
- `Moves(moves...)` - `Moves(moves...)`
- `Friendship(friendship)` - `Friendship(friendship)`
- `Status1(status1)` - `Status1(status1)`
For example to create a level 42 Wobbuffet that is poisoned: For example to create a level 42 Wobbuffet that is poisoned:
`PLAYER(SPECIES_WOBBUFFET) { Level(42); Status1(STATUS1_POISON); }` `PLAYER(SPECIES_WOBBUFFET) { Level(42); Status1(STATUS1_POISON); }`
**Note if Speed is specified for any Pokémon then it must be specified for all Pokémon.** **Note if Speed is specified for any Pokémon then it must be specified for all Pokémon.**
**Note if Moves is specified then MOVE will not automatically add moves to the moveset.** **Note if Moves is specified then MOVE will not automatically add moves to the moveset.**
### `AI_FLAGS` ### `AI_FLAGS`
`AI_FLAGS(flags)` `AI_FLAGS(flags)`
Specifies which AI flags are run during the test. Has use only for AI tests. Specifies which AI flags are run during the test. Has use only for AI tests.
The most common combination is `AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT)` which is the general 'smart' AI. The most common combination is `AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT)` which is the general 'smart' AI.
### `WHEN` ### `WHEN`
@ -300,8 +300,8 @@ The most common combination is `AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_
Contains the choices that battlers make during the battle. Contains the choices that battlers make during the battle.
### `TURN` ### `TURN`
`TURN { ... }` `TURN { ... }`
Groups the choices made by the battlers on a single turn. If Speeds have not been explicitly specified then the order of the `MOVE` commands in the `TURN` will be used to infer the Speeds of the Pokémon, e.g.: Groups the choices made by the battlers on a single turn. If Speeds have not been explicitly specified then the order of the `MOVE` commands in the `TURN` will be used to infer the Speeds of the Pokémon, e.g.:
``` ```
// player's speed will be greater than opponent's speed. // player's speed will be greater than opponent's speed.
TURN { MOVE(player, MOVE_SPLASH); MOVE(opponent, MOVE_SPLASH); } TURN { MOVE(player, MOVE_SPLASH); MOVE(opponent, MOVE_SPLASH); }
@ -311,7 +311,7 @@ Groups the choices made by the battlers on a single turn. If Speeds have not bee
The inference process is naive, if your test contains anything that modifies the speed of a battler you should specify them explicitly. The inference process is naive, if your test contains anything that modifies the speed of a battler you should specify them explicitly.
### `MOVE` ### `MOVE`
`MOVE(battler, move | moveSlot:, [megaEvolve:], [hit:], [criticalHit:], [target:], [allowed:], [WITH_RNG(tag, value])` `MOVE(battler, move | moveSlot:, [megaEvolve:], [hit:], [criticalHit:], [target:], [allowed:], [WITH_RNG(tag, value])`
Used when the battler chooses Fight. Either the move ID (e.g. `MOVE_TACKLE` or move slot must be specified. Used when the battler chooses Fight. Either the move ID (e.g. `MOVE_TACKLE` or move slot must be specified.
- `megaEvolve: TRUE` causes the battler to Mega Evolve if able - `megaEvolve: TRUE` causes the battler to Mega Evolve if able
- `hit: FALSE` causes the move to miss - `hit: FALSE` causes the move to miss
@ -325,35 +325,35 @@ Used when the battler chooses Fight. Either the move ID (e.g. `MOVE_TACKLE` or m
If the battler does not have an explicit Moves specified the moveset will be populated based on the `MOVE`s it uses. If the battler does not have an explicit Moves specified the moveset will be populated based on the `MOVE`s it uses.
### `FORCED_MOVE` ### `FORCED_MOVE`
`FORCED_MOVE(battler)` `FORCED_MOVE(battler)`
Used when the battler chooses Fight and then their move is chosen for them, e.g. when affected by Encore. Used when the battler chooses Fight and then their move is chosen for them, e.g. when affected by Encore.
``` ```
FORCED_MOVE(player); FORCED_MOVE(player);
``` ```
### `SWITCH` ### `SWITCH`
`SWITCH(battler, partyIndex)` `SWITCH(battler, partyIndex)`
Used when the battler chooses Switch. Used when the battler chooses Switch.
``` ```
SWITCH(player, 1); SWITCH(player, 1);
``` ```
### `SKIP_TURN` ### `SKIP_TURN`
`SKIP_TURN(battler)` `SKIP_TURN(battler)`
Used when the battler cannot choose an action, e.g. when locked into Thrash. Used when the battler cannot choose an action, e.g. when locked into Thrash.
``` ```
SKIP_TURN(player); SKIP_TURN(player);
``` ```
### `SEND_OUT` ### `SEND_OUT`
`SEND_OUT(battler, partyIndex)` `SEND_OUT(battler, partyIndex)`
Used when the battler chooses to switch to another Pokémon but not via Switch, e.g. after fainting or due to a U-turn. Used when the battler chooses to switch to another Pokémon but not via Switch, e.g. after fainting or due to a U-turn.
``` ```
SEND_OUT(player, 1); SEND_OUT(player, 1);
``` ```
### `USE_ITEM` ### `USE_ITEM`
`USE_ITEM(battler, itemId, [partyIndex:], [move:])` `USE_ITEM(battler, itemId, [partyIndex:], [move:])`
Used when the battler chooses to use an item from the Bag. The item ID (e.g. ITEM_POTION) must be specified, and party index and move slot if applicable, e.g: Used when the battler chooses to use an item from the Bag. The item ID (e.g. ITEM_POTION) must be specified, and party index and move slot if applicable, e.g:
``` ```
USE_ITEM(player, ITEM_X_ATTACK); USE_ITEM(player, ITEM_X_ATTACK);
@ -378,15 +378,15 @@ Contains an abridged description of the UI during the `THEN`. The order of the d
``` ```
### `ABILITY_POPUP` ### `ABILITY_POPUP`
`ABILITY_POPUP(battler, [ability])` `ABILITY_POPUP(battler, [ability])`
Causes the test to fail if the battler's ability pop-up is not shown. Causes the test to fail if the battler's ability pop-up is not shown.
If specified, ability is the ability shown in the pop-up. If specified, ability is the ability shown in the pop-up.
``` ```
ABILITY_POPUP(opponent, ABILITY_MOLD_BREAKER); ABILITY_POPUP(opponent, ABILITY_MOLD_BREAKER);
``` ```
### `ANIMATION` ### `ANIMATION`
`ANIMATION(type, animId, [battler], [target:])` `ANIMATION(type, animId, [battler], [target:])`
Causes the test to fail if the animation does not play. A common use of this command is to check if a move was successful, e.g.: Causes the test to fail if the animation does not play. A common use of this command is to check if a move was successful, e.g.:
``` ```
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, player);
@ -394,7 +394,7 @@ Causes the test to fail if the animation does not play. A common use of this com
`target` can only be specified for `ANIM_TYPE_MOVE`. `target` can only be specified for `ANIM_TYPE_MOVE`.
### `EXPERIENCE_BAR` ### `EXPERIENCE_BAR`
`EXPERIENCE_BAR(battler, [exp: | captureGainedExp:])` `EXPERIENCE_BAR(battler, [exp: | captureGainedExp:])`
If `exp:` is used, causes the test to fail if that amount of experience is not gained, e.g.: If `exp:` is used, causes the test to fail if that amount of experience is not gained, e.g.:
``` ```
EXPERIENCE_BAR(player, exp: 0); EXPERIENCE_BAR(player, exp: 0);
@ -404,11 +404,11 @@ If `captureGainedExp:` is used, causes the test to fail if the Experience bar do
u32 exp; u32 exp;
EXPERIENCE_BAR(player, captureGainedExp: &exp); EXPERIENCE_BAR(player, captureGainedExp: &exp);
``` ```
If none of the above are used, causes the test to fail if the Exp does not change at all. If none of the above are used, causes the test to fail if the Exp does not change at all.
**Please note that due to nature of tests, this command is only usable in `WILD_BATTLE_TEST` and will fail elsewhere.** **Please note that due to nature of tests, this command is only usable in `WILD_BATTLE_TEST` and will fail elsewhere.**
### `HP_BAR` ### `HP_BAR`
`HP_BAR(battler, [damage: | hp: | captureDamage: | captureHP:])` `HP_BAR(battler, [damage: | hp: | captureDamage: | captureHP:])`
If `hp:` or `damage:` are used, causes the test to fail if that amount of damage is not dealt, e.g.: If `hp:` or `damage:` are used, causes the test to fail if that amount of damage is not dealt, e.g.:
``` ```
HP_BAR(player, hp: 0); HP_BAR(player, hp: 0);
@ -422,9 +422,9 @@ If `captureDamage:` or `captureHP:` are used, causes the test to fail if the HP
If none of the above are used, causes the test to fail if the HP does not change at all. If none of the above are used, causes the test to fail if the HP does not change at all.
### MESSAGE ### MESSAGE
`MESSAGE(pattern)` `MESSAGE(pattern)`
Causes the test to fail if the message in pattern is not displayed. Causes the test to fail if the message in pattern is not displayed.
Spaces in pattern match newlines (\n, \l, and \p) in the message. Spaces in pattern match newlines (\n, \l, and \p) in the message.
Often used to check that a battler took its turn but it failed, e.g.: Often used to check that a battler took its turn but it failed, e.g.:
``` ```
MESSAGE("Wobbuffet used Dream Eater!"); MESSAGE("Wobbuffet used Dream Eater!");
@ -432,7 +432,7 @@ Often used to check that a battler took its turn but it failed, e.g.:
``` ```
### `STATUS_ICON` ### `STATUS_ICON`
`STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis:, badPoison:)` `STATUS_ICON(battler, status1 | none: | sleep: | poison: | burn: | freeze: | paralysis:, badPoison:)`
Causes the test to fail if the battler's status is not changed to the specified status. Causes the test to fail if the battler's status is not changed to the specified status.
``` ```
STATUS_ICON(player, badPoison: TRUE); STATUS_ICON(player, badPoison: TRUE);
@ -447,7 +447,7 @@ If the expected status icon is parametrized the corresponding `STATUS1` constant
``` ```
### `NOT` ### `NOT`
`NOT sceneCommand` `NOT sceneCommand`
Causes the test to fail if the `SCENE` command succeeds before the following command succeeds. Causes the test to fail if the `SCENE` command succeeds before the following command succeeds.
``` ```
// Our Wobbuffet does not Celebrate before the foe's. // Our Wobbuffet does not Celebrate before the foe's.
@ -519,27 +519,27 @@ Contains code to run after the battle has finished. If the test is using `PARAME
Contains checks to run after all `PARAMETERIZE` commands have run. Prefer to write your checks in `THEN` where possible, because a failure in `THEN` will be tagged with which parameter it corresponds to. Contains checks to run after all `PARAMETERIZE` commands have run. Prefer to write your checks in `THEN` where possible, because a failure in `THEN` will be tagged with which parameter it corresponds to.
### `EXPECT` ### `EXPECT`
`EXPECT(cond)` `EXPECT(cond)`
Causes the test to fail if `cond` is false. Causes the test to fail if `cond` is false.
### `EXPECT_XX` ### `EXPECT_XX`
`EXPECT_EQ(a, b)` `EXPECT_EQ(a, b)`
`a == b` `a == b`
`EXPECT_NE(a, b)` `EXPECT_NE(a, b)`
`a != b` `a != b`
`EXPECT_LT(a, b)` `EXPECT_LT(a, b)`
`a < b` `a < b`
`EXPECT_LE(a, b)` `EXPECT_LE(a, b)`
`a <= b` `a <= b`
`EXPECT_GT(a, b)` `EXPECT_GT(a, b)`
`a > b` `a > b`
`EXPECT_GE(a, b)` `EXPECT_GE(a, b)`
`a >= b` `a >= b`
Causes the test to fail if a and b compare incorrectly, e.g. Causes the test to fail if a and b compare incorrectly, e.g.
``` ```
@ -547,7 +547,7 @@ Causes the test to fail if a and b compare incorrectly, e.g.
``` ```
### `EXPECT_MUL_EQ` ### `EXPECT_MUL_EQ`
`EXPECT_MUL_EQ(a, m, b)` `EXPECT_MUL_EQ(a, m, b)`
Causes the test to fail if `a*m != b` (within a threshold), e.g. Causes the test to fail if `a*m != b` (within a threshold), e.g.
``` ```
// Expect results[0].damage * 1.5 == results[1].damage. // Expect results[0].damage * 1.5 == results[1].damage.
@ -557,7 +557,7 @@ Causes the test to fail if a and b compare incorrectly, e.g.
## Overworld Command Reference ## Overworld Command Reference
### `OVERWORLD_SCRIPT` ### `OVERWORLD_SCRIPT`
`OVERWORLD_SCRIPT(instructions...)` `OVERWORLD_SCRIPT(instructions...)`
Returns a pointer to a compiled overworld script. Cannot be used to initialize global `const` data, although the pointer **IS** to `const` data. Returns a pointer to a compiled overworld script. Cannot be used to initialize global `const` data, although the pointer **IS** to `const` data.
Note that each script command must be followed by a ;, e.g.: Note that each script command must be followed by a ;, e.g.:
``` ```
@ -568,7 +568,7 @@ const u8 *myScript = OVERWORLD_SCRIPT(
``` ```
### `RUN_OVERWORLD_SCRIPT` ### `RUN_OVERWORLD_SCRIPT`
`RUN_OVERWORLD_SCRIPT(instructions...)` `RUN_OVERWORLD_SCRIPT(instructions...)`
Runs an overworld script in the immediate script context, which means that commands like `waitstate` are not supported. Runs an overworld script in the immediate script context, which means that commands like `waitstate` are not supported.
``` ```
RUN_OVERWORLD_SCRIPT( RUN_OVERWORLD_SCRIPT(

View file

@ -12,13 +12,13 @@
* [Usage](#usage) * [Usage](#usage)
## Quick Summary ## Quick Summary
(Page contains out of date information, [new instructions for Sprites here](https://github.com/rh-hideout/pokeemerald-expansion/pull/3597).) (Page contains out of date information, [new instructions for Sprites here](https://github.com/rh-hideout/pokeemerald-expansion/pull/3597).)
If you've done this before and just need a quick lookup, here's what files you need: If you've done this before and just need a quick lookup, here's what files you need:
1. GFX into [graphics/trainers/front_pics](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/front_pics) 1. GFX into [graphics/trainers/front_pics](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/front_pics)
2. Palette into [graphics/trainers/palettes](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/palettes) 2. Palette into [graphics/trainers/palettes](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/graphics/trainers/palettes)
3. Register sprites to [include/graphics.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/graphics.h) 3. Register sprites to [include/graphics.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/graphics.h)
4. Point game to where graphic files are found: [src/data/graphics/trainers](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/trainers.h) 4. Point game to where graphic files are found: [src/data/graphics/trainers](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/graphics/trainers.h)
5. Add animation to: [src/data/trainer_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_anims.h) 5. Add animation to: [src/data/trainer_graphics/front_pic_anims.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_anims.h)
6. Add the trainer to all three structs in: [src/data/trainer_graphics/front_pic_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_table.h) 6. Add the trainer to all three structs in: [src/data/trainer_graphics/front_pic_table.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/src/data/trainer_graphics/front_pic_table.h)
7. Add trainer to [include/constants/trainers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/trainers.h) 7. Add trainer to [include/constants/trainers.h](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/constants/trainers.h)

View file

@ -328,7 +328,7 @@
* *
* MOVE(battler, move | moveSlot:, [gimmick:], [hit:], [criticalHit:], [target:], [allowed:], [WITH_RNG(tag, value]) * MOVE(battler, move | moveSlot:, [gimmick:], [hit:], [criticalHit:], [target:], [allowed:], [WITH_RNG(tag, value])
* Used when the battler chooses Fight. Either the move ID or move slot * Used when the battler chooses Fight. Either the move ID or move slot
* must be specified. gimmick: GIMMICK_MEGA causes the battler to Mega * must be specified. gimmick: GIMMICK_MEGA causes the battler to Mega
* Evolve if able, hit: FALSE causes the move to miss, criticalHit: TRUE * Evolve if able, hit: FALSE causes the move to miss, criticalHit: TRUE
* causes the move to land a critical hit, target: is used in double * causes the move to land a critical hit, target: is used in double
* battles to choose the target (when necessary), and allowed: FALSE is * battles to choose the target (when necessary), and allowed: FALSE is

View file

@ -81,5 +81,5 @@ for file in pories_to_check:
raw = re.sub("script %s[ \n]*\{[ \n]*finditem\((.*)\)[ \n]*\}[ \n]*" % unused, "", raw) raw = re.sub("script %s[ \n]*\{[ \n]*finditem\((.*)\)[ \n]*\}[ \n]*" % unused, "", raw)
with open(file, "w") as f2: with open(file, "w") as f2:
f2.write(raw) f2.write(raw)
print("Done!") print("Done!")

View file

@ -37,7 +37,7 @@ for line in lines:
comment_split = line.split('//') comment_split = line.split('//')
if move and IsCommaMissing(comment_split[0]): if move and IsCommaMissing(comment_split[0]):
line = comment_split[0].removesuffix('\n') + ',' + line[len(comment_split[0]):-1] + '\n' line = comment_split[0].removesuffix('\n') + ',' + line[len(comment_split[0]):-1] + '\n'
moves_info_lines.append(line) moves_info_lines.append(line)

View file

@ -731,7 +731,7 @@ $(FLDEFFGFXDIR)/secret_power_tree.4bpp: %.4bpp: %.png
$(FLDEFFGFXDIR)/record_mix_lights.4bpp: %.4bpp: %.png $(FLDEFFGFXDIR)/record_mix_lights.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 1 $(GFX) $< $@ -mwidth 4 -mheight 1
$(POKEMONGFXDIR)/question_mark/overworld.4bpp: %.4bpp: %.png $(POKEMONGFXDIR)/question_mark/overworld.4bpp: %.4bpp: %.png
$(GFX) $< $@ -mwidth 4 -mheight 4 $(GFX) $< $@ -mwidth 4 -mheight 4

View file

@ -798,7 +798,7 @@ static void Cmd_end(void)
// Debugging - ensure no hanging mon bg tasks // Debugging - ensure no hanging mon bg tasks
if (FuncIsActiveTask(Task_UpdateMonBg)) if (FuncIsActiveTask(Task_UpdateMonBg))
DebugPrintf("Move %d animation still has Task_UpdateMonBg active at the end!", gAnimMoveIndex); DebugPrintf("Move %d animation still has Task_UpdateMonBg active at the end!", gAnimMoveIndex);
m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256); m4aMPlayVolumeControl(&gMPlayInfo_BGM, TRACKS_ALL, 256);
if (!IsContest()) if (!IsContest())
{ {

View file

@ -42,35 +42,35 @@ const struct SpriteTemplate gOutrageFlameSpriteTemplate =
.callback = AnimOutrageFlame, .callback = AnimOutrageFlame,
}; };
static const union AnimCmd sAnim_DreepyMissileOpponent_0[] = static const union AnimCmd sAnim_DreepyMissileOpponent_0[] =
{ {
ANIMCMD_FRAME(0, 0, .hFlip = TRUE), ANIMCMD_FRAME(0, 0, .hFlip = TRUE),
ANIMCMD_END, ANIMCMD_END,
}; };
const union AnimCmd *const gAnims_DreepyMissileOpponent[] = const union AnimCmd *const gAnims_DreepyMissileOpponent[] =
{ {
sAnim_DreepyMissileOpponent_0, sAnim_DreepyMissileOpponent_0,
}; };
static const union AnimCmd sAnim_DreepyMissilePlayer_0[] = static const union AnimCmd sAnim_DreepyMissilePlayer_0[] =
{ {
ANIMCMD_FRAME(0, 0), ANIMCMD_FRAME(0, 0),
ANIMCMD_END, ANIMCMD_END,
}; };
const union AnimCmd *const gAnims_DreepyMissilePlayer[] = const union AnimCmd *const gAnims_DreepyMissilePlayer[] =
{ {
sAnim_DreepyMissilePlayer_0, sAnim_DreepyMissilePlayer_0,
}; };
static const union AnimCmd sAnim_DreepyMissileNotDrag_0[] = static const union AnimCmd sAnim_DreepyMissileNotDrag_0[] =
{ {
ANIMCMD_FRAME(0, 0, .hFlip = TRUE, .vFlip = TRUE), ANIMCMD_FRAME(0, 0, .hFlip = TRUE, .vFlip = TRUE),
ANIMCMD_END, ANIMCMD_END,
}; };
const union AnimCmd *const gAnims_DreepyMissileOpponentNotDrag[] = const union AnimCmd *const gAnims_DreepyMissileOpponentNotDrag[] =
{ {
sAnim_DreepyMissileNotDrag_0, sAnim_DreepyMissileNotDrag_0,
}; };

View file

@ -6578,11 +6578,11 @@ void PrepareDoubleTeamAnim(u32 taskId, u32 animBattler, bool32 forAllySwitch)
gSprites[spriteId].sBattlerFlank = (animBattler != ANIM_ATTACKER); gSprites[spriteId].sBattlerFlank = (animBattler != ANIM_ATTACKER);
else else
gSprites[spriteId].sBattlerFlank = (animBattler == ANIM_ATTACKER); gSprites[spriteId].sBattlerFlank = (animBattler == ANIM_ATTACKER);
// correct direction on opponent side // correct direction on opponent side
if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT) if (GetBattlerSide(gBattleAnimAttacker) == B_SIDE_OPPONENT)
gSprites[spriteId].sBattlerFlank ^= 1; gSprites[spriteId].sBattlerFlank ^= 1;
gSprites[spriteId].callback = AnimDoubleTeam; gSprites[spriteId].callback = AnimDoubleTeam;
task->tBlendSpritesCount++; task->tBlendSpritesCount++;
} }
@ -6614,7 +6614,7 @@ static void ReloadBattlerSprites(u32 battler, struct Pokemon *party)
UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL); UpdateHealthboxAttribute(gHealthboxSpriteIds[battler], mon, HEALTHBOX_ALL);
// If battler has an indicator for a gimmick, hide the sprite until the move animation finishes. // If battler has an indicator for a gimmick, hide the sprite until the move animation finishes.
UpdateIndicatorVisibilityAndType(gHealthboxSpriteIds[battler], TRUE); UpdateIndicatorVisibilityAndType(gHealthboxSpriteIds[battler], TRUE);
// Try to recreate shadow sprite // Try to recreate shadow sprite
if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId < MAX_SPRITES) if (gBattleSpritesDataPtr->healthBoxesData[battler].shadowSpriteId < MAX_SPRITES)
{ {

View file

@ -33,7 +33,7 @@ static void AnimSkyAttackBird_Step(struct Sprite *);
static void AnimTask_AnimateGustTornadoPalette_Step(u8); static void AnimTask_AnimateGustTornadoPalette_Step(u8);
static void AnimTask_LoadWindstormBackground_Step(u8 taskId); static void AnimTask_LoadWindstormBackground_Step(u8 taskId);
const struct SpriteTemplate gEllipticalGustCenteredSpriteTemplate = const struct SpriteTemplate gEllipticalGustCenteredSpriteTemplate =
{ {
.tileTag = ANIM_TAG_GUST, .tileTag = ANIM_TAG_GUST,
.paletteTag = ANIM_TAG_GUST, .paletteTag = ANIM_TAG_GUST,

View file

@ -414,7 +414,7 @@ u32 UnpackSelectedBattlePalettes(s16 selector)
bool8 anim1 = (selector >> 5) & 1; bool8 anim1 = (selector >> 5) & 1;
bool8 anim2 = (selector >> 6) & 1; bool8 anim2 = (selector >> 6) & 1;
u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gAnimMoveIndex); u32 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gAnimMoveIndex);
switch (moveTarget) switch (moveTarget)
{ {
case MOVE_TARGET_BOTH: case MOVE_TARGET_BOTH:
@ -431,7 +431,7 @@ u32 UnpackSelectedBattlePalettes(s16 selector)
} }
break; break;
} }
return GetBattlePalettesMask(battleBackground, attacker, target, attackerPartner, targetPartner, anim1, anim2); return GetBattlePalettesMask(battleBackground, attacker, target, attackerPartner, targetPartner, anim1, anim2);
} }

View file

@ -610,7 +610,7 @@ static void InitLinkBtlControllers(void)
bool32 IsValidForBattle(struct Pokemon *mon) bool32 IsValidForBattle(struct Pokemon *mon)
{ {
u32 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG); u32 species = GetMonData(mon, MON_DATA_SPECIES_OR_EGG);
return (species != SPECIES_NONE return (species != SPECIES_NONE
&& species != SPECIES_EGG && species != SPECIES_EGG
&& GetMonData(mon, MON_DATA_HP) != 0 && GetMonData(mon, MON_DATA_HP) != 0
&& GetMonData(mon, MON_DATA_IS_EGG) == FALSE); && GetMonData(mon, MON_DATA_IS_EGG) == FALSE);

View file

@ -2136,7 +2136,7 @@ static void CalcDomeMonStats(const struct TrainerMon *fmon, int level, u8 ivs, i
{ {
int evs[NUM_STATS]; int evs[NUM_STATS];
int i; int i;
for (i = 0; i < NUM_STATS; i++) for (i = 0; i < NUM_STATS; i++)
{ {
if (fmon->ev != NULL) if (fmon->ev != NULL)
@ -2144,7 +2144,7 @@ static void CalcDomeMonStats(const struct TrainerMon *fmon, int level, u8 ivs, i
else else
evs[i] = 0; evs[i] = 0;
} }
if (fmon->species == SPECIES_SHEDINJA) if (fmon->species == SPECIES_SHEDINJA)
{ {
stats[STAT_HP] = 1; stats[STAT_HP] = 1;
@ -2199,7 +2199,7 @@ static void CreateDomeOpponentMon(u8 monPartyId, u16 tournamentTrainerId, u8 tou
u8 fixedIv = GetDomeTrainerMonIvs(tournamentTrainerId); // BUG: Using the wrong ID. As a result, all Pokémon have ivs of 3. u8 fixedIv = GetDomeTrainerMonIvs(tournamentTrainerId); // BUG: Using the wrong ID. As a result, all Pokémon have ivs of 3.
#endif #endif
u8 level = SetFacilityPtrsGetLevel(); u8 level = SetFacilityPtrsGetLevel();
CreateFacilityMon(&gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]], CreateFacilityMon(&gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]],
level, fixedIv, otId, 0, &gEnemyParty[monPartyId]); level, fixedIv, otId, 0, &gEnemyParty[monPartyId]);
} }
@ -4446,7 +4446,7 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
else else
allocatedArray[j] = 0; allocatedArray[j] = 0;
} }
allocatedArray[NUM_STATS] += allocatedArray[STAT_HP]; allocatedArray[NUM_STATS] += allocatedArray[STAT_HP];
for (j = 0; j < NUM_NATURE_STATS; j++) for (j = 0; j < NUM_NATURE_STATS; j++)
{ {

View file

@ -406,7 +406,7 @@ static void SetPlayerAndOpponentParties(void)
u8 monLevel; u8 monLevel;
u16 monId; u16 monId;
u8 ivs; u8 ivs;
if (gSaveBlock2Ptr->frontier.lvlMode == FRONTIER_LVL_TENT) if (gSaveBlock2Ptr->frontier.lvlMode == FRONTIER_LVL_TENT)
{ {
gFacilityTrainerMons = gSlateportBattleTentMons; gFacilityTrainerMons = gSlateportBattleTentMons;
@ -428,7 +428,7 @@ static void SetPlayerAndOpponentParties(void)
{ {
monId = gSaveBlock2Ptr->frontier.rentalMons[i].monId; monId = gSaveBlock2Ptr->frontier.rentalMons[i].monId;
ivs = gSaveBlock2Ptr->frontier.rentalMons[i].ivs; ivs = gSaveBlock2Ptr->frontier.rentalMons[i].ivs;
CreateFacilityMon(&gFacilityTrainerMons[monId], monLevel, ivs, OT_ID_PLAYER_ID, FLAG_FRONTIER_MON_FACTORY, &gPlayerParty[i]); CreateFacilityMon(&gFacilityTrainerMons[monId], monLevel, ivs, OT_ID_PLAYER_ID, FLAG_FRONTIER_MON_FACTORY, &gPlayerParty[i]);
SetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY, SetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY,
&gSaveBlock2Ptr->frontier.rentalMons[i].personality); &gSaveBlock2Ptr->frontier.rentalMons[i].personality);

View file

@ -1761,7 +1761,7 @@ static void CreateFrontierFactorySelectableMons(u8 firstMonId)
ivs = GetFactoryMonFixedIV(challengeNum + 1, FALSE); ivs = GetFactoryMonFixedIV(challengeNum + 1, FALSE);
else else
ivs = GetFactoryMonFixedIV(challengeNum, FALSE); ivs = GetFactoryMonFixedIV(challengeNum, FALSE);
CreateFacilityMon(&gFacilityTrainerMons[monId], CreateFacilityMon(&gFacilityTrainerMons[monId],
level, ivs, otId, FLAG_FRONTIER_MON_FACTORY, level, ivs, otId, FLAG_FRONTIER_MON_FACTORY,
&sFactorySelectScreen->mons[i + firstMonId].monData); &sFactorySelectScreen->mons[i + firstMonId].monData);

View file

@ -1940,7 +1940,7 @@ void IncrementRematchStepCounter(void)
#if FREE_MATCH_CALL == FALSE #if FREE_MATCH_CALL == FALSE
if (!HasAtLeastFiveBadges()) if (!HasAtLeastFiveBadges())
return; return;
if (IsVsSeekerEnabled()) if (IsVsSeekerEnabled())
return; return;

View file

@ -84,7 +84,7 @@ static void FormChangeTimeUpdate()
{ {
struct Pokemon *mon = &gPlayerParty[i]; struct Pokemon *mon = &gPlayerParty[i];
u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_TIME_OF_DAY, 0); u16 targetSpecies = GetFormChangeTargetSpecies(mon, FORM_CHANGE_TIME_OF_DAY, 0);
if (targetSpecies != SPECIES_NONE) if (targetSpecies != SPECIES_NONE)
{ {
SetMonData(mon, MON_DATA_SPECIES, &targetSpecies); SetMonData(mon, MON_DATA_SPECIES, &targetSpecies);

View file

@ -5,7 +5,7 @@
const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] = const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] =
{ {
[GIMMICK_NONE] = {0}, [GIMMICK_NONE] = {0},
[GIMMICK_MEGA] = [GIMMICK_MEGA] =
{ {
.triggerSheet = &sSpriteSheet_MegaTrigger, .triggerSheet = &sSpriteSheet_MegaTrigger,
.triggerPal = &sSpritePalette_MegaTrigger, .triggerPal = &sSpritePalette_MegaTrigger,
@ -15,7 +15,7 @@ const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] =
.CanActivate = CanMegaEvolve, .CanActivate = CanMegaEvolve,
.ActivateGimmick = ActivateMegaEvolution, .ActivateGimmick = ActivateMegaEvolution,
}, },
[GIMMICK_Z_MOVE] = [GIMMICK_Z_MOVE] =
{ {
.triggerSheet = &sSpriteSheet_ZMoveTrigger, .triggerSheet = &sSpriteSheet_ZMoveTrigger,
.triggerPal = &sSpritePalette_ZMoveTrigger, .triggerPal = &sSpritePalette_ZMoveTrigger,
@ -23,7 +23,7 @@ const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] =
.CanActivate = CanUseZMove, .CanActivate = CanUseZMove,
.ActivateGimmick = ActivateZMove, .ActivateGimmick = ActivateZMove,
}, },
[GIMMICK_ULTRA_BURST] = [GIMMICK_ULTRA_BURST] =
{ {
.triggerSheet = &sSpriteSheet_BurstTrigger, .triggerSheet = &sSpriteSheet_BurstTrigger,
.triggerPal = &sSpritePalette_BurstTrigger, .triggerPal = &sSpritePalette_BurstTrigger,
@ -31,7 +31,7 @@ const struct GimmickInfo gGimmicksInfo[GIMMICKS_COUNT] =
.CanActivate = CanUltraBurst, .CanActivate = CanUltraBurst,
.ActivateGimmick = ActivateUltraBurst, .ActivateGimmick = ActivateUltraBurst,
}, },
[GIMMICK_DYNAMAX] = [GIMMICK_DYNAMAX] =
{ {
.triggerSheet = &sSpriteSheet_DynamaxTrigger, .triggerSheet = &sSpriteSheet_DynamaxTrigger,
.triggerPal = &sSpritePalette_DynamaxTrigger, .triggerPal = &sSpritePalette_DynamaxTrigger,

View file

@ -239,7 +239,7 @@ extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_HoOh;
// Begin pokemon event objects // Begin pokemon event objects
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_PokeBall; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_PokeBall;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Follower; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Follower;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Bard; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Bard;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Hipster; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Hipster;
extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Trader; extern const struct ObjectEventGraphicsInfo gObjectEventGraphicsInfo_Trader;

View file

@ -1493,7 +1493,7 @@ static s16 ReallocSpriteTiles(struct Sprite *sprite, u32 byteSize)
{ {
i = -1; i = -1;
} }
sprite->invisible = wasVisible; sprite->invisible = wasVisible;
return i; return i;
} }
@ -1510,7 +1510,7 @@ u16 LoadSheetGraphicsInfo(const struct ObjectEventGraphicsInfo *info, u16 uuid,
bool32 oldInvisible; bool32 oldInvisible;
if (tag == TAG_NONE) if (tag == TAG_NONE)
tag = COMP_OW_TILE_TAG_BASE + uuid; tag = COMP_OW_TILE_TAG_BASE + uuid;
if (sprite) if (sprite)
{ {
oldInvisible = sprite->invisible; oldInvisible = sprite->invisible;
@ -1547,7 +1547,7 @@ u16 LoadSheetGraphicsInfo(const struct ObjectEventGraphicsInfo *info, u16 uuid,
{ {
FieldEffectFreeTilesIfUnused(oldTiles); FieldEffectFreeTilesIfUnused(oldTiles);
} }
if (sprite) if (sprite)
{ {
sprite->sheetTileStart = tileStart; sprite->sheetTileStart = tileStart;
@ -1566,7 +1566,7 @@ u16 LoadSheetGraphicsInfo(const struct ObjectEventGraphicsInfo *info, u16 uuid,
{ {
sprite->oam.tileNum = sprite->sheetTileStart; sprite->oam.tileNum = sprite->sheetTileStart;
sprite->usingSheet = FALSE; sprite->usingSheet = FALSE;
} }
else if (sprite && !sprite->sheetTileStart && sprite->oam.size != info->oam->size) else if (sprite && !sprite->sheetTileStart && sprite->oam.size != info->oam->size)
{ {
@ -1925,7 +1925,7 @@ static u8 LoadDynamicFollowerPalette(u16 species, u8 form, bool32 shiny)
spritePalette.data = gSpeciesInfo[species].overworldShinyPalette; spritePalette.data = gSpeciesInfo[species].overworldShinyPalette;
else else
spritePalette.data = gSpeciesInfo[species].overworldPalette; spritePalette.data = gSpeciesInfo[species].overworldPalette;
// Check if pal data must be decompressed // Check if pal data must be decompressed
if (IsLZ77Data(spritePalette.data, PLTT_SIZE_4BPP, PLTT_SIZE_4BPP)) if (IsLZ77Data(spritePalette.data, PLTT_SIZE_4BPP, PLTT_SIZE_4BPP))
{ {

View file

@ -977,8 +977,8 @@ static bool32 IsBuildingPCTile(u32 tileId)
static bool32 IsPlayerHousePCTile(u32 tileId) static bool32 IsPlayerHousePCTile(u32 tileId)
{ {
return gMapHeader.mapLayout->secondaryTileset == &gTileset_BrendansMaysHouse return gMapHeader.mapLayout->secondaryTileset == &gTileset_BrendansMaysHouse
&& (tileId == METATILE_BrendansMaysHouse_BrendanPC_On && (tileId == METATILE_BrendansMaysHouse_BrendanPC_On
|| tileId == METATILE_BrendansMaysHouse_BrendanPC_Off || tileId == METATILE_BrendansMaysHouse_BrendanPC_Off
|| tileId == METATILE_BrendansMaysHouse_MayPC_On || tileId == METATILE_BrendansMaysHouse_MayPC_On
|| tileId == METATILE_BrendansMaysHouse_MayPC_Off); || tileId == METATILE_BrendansMaysHouse_MayPC_Off);

View file

@ -211,7 +211,7 @@ void SaveObjectEvents(void)
gSaveBlock1Ptr->objectEvents[i].graphicsId = (graphicsId >> 8) | (graphicsId << 8); gSaveBlock1Ptr->objectEvents[i].graphicsId = (graphicsId >> 8) | (graphicsId << 8);
gSaveBlock1Ptr->objectEvents[i].spriteId = 127; // magic number gSaveBlock1Ptr->objectEvents[i].spriteId = 127; // magic number
// To avoid crash on vanilla, save follower as inactive // To avoid crash on vanilla, save follower as inactive
if (gObjectEvents[i].localId == OBJ_EVENT_ID_FOLLOWER) if (gObjectEvents[i].localId == OBJ_EVENT_ID_FOLLOWER)
gSaveBlock1Ptr->objectEvents[i].active = FALSE; gSaveBlock1Ptr->objectEvents[i].active = FALSE;
} }
} }

View file

@ -550,7 +550,7 @@ static void ShowMapNamePopUpWindow(void)
if (OW_POPUP_GENERATION == GEN_5) if (OW_POPUP_GENERATION == GEN_5)
{ {
AddTextPrinterParameterized(mapNamePopUpWindowId, FONT_SHORT, mapDisplayHeader, 8, 2, TEXT_SKIP_DRAW, NULL); AddTextPrinterParameterized(mapNamePopUpWindowId, FONT_SHORT, mapDisplayHeader, 8, 2, TEXT_SKIP_DRAW, NULL);
if (OW_POPUP_BW_TIME_MODE != OW_POPUP_BW_TIME_NONE) if (OW_POPUP_BW_TIME_MODE != OW_POPUP_BW_TIME_NONE)
{ {
RtcCalcLocalTime(); RtcCalcLocalTime();
@ -622,7 +622,7 @@ static void LoadMapNamePopUpWindowBg(void)
if (OW_POPUP_GENERATION == GEN_5) if (OW_POPUP_GENERATION == GEN_5)
{ {
popUpThemeId = sRegionMapSectionId_To_PopUpThemeIdMapping_BW[regionMapSectionId]; popUpThemeId = sRegionMapSectionId_To_PopUpThemeIdMapping_BW[regionMapSectionId];
switch (popUpThemeId) switch (popUpThemeId)
{ {
// add additional gen 5-style pop-up themes as cases here // add additional gen 5-style pop-up themes as cases here
case MAPPOPUP_THEME_BW_DEFAULT: case MAPPOPUP_THEME_BW_DEFAULT:

View file

@ -487,7 +487,7 @@ static void Task_HandleScrollingMultichoiceInput(u8 taskId)
{ {
bool32 done = FALSE; bool32 done = FALSE;
s32 input = ListMenu_ProcessInput(gTasks[taskId].data[0]); s32 input = ListMenu_ProcessInput(gTasks[taskId].data[0]);
switch (input) switch (input)
{ {
case LIST_HEADER: case LIST_HEADER:

View file

@ -466,7 +466,7 @@ u32 ScriptGiveMon(u16 species, u8 level, u16 item)
#define PARSE_FLAG(n, default_) (flags & (1 << (n))) ? VarGet(ScriptReadHalfword(ctx)) : (default_) #define PARSE_FLAG(n, default_) (flags & (1 << (n))) ? VarGet(ScriptReadHalfword(ctx)) : (default_)
/* Give or create a mon to either player or opponent /* Give or create a mon to either player or opponent
*/ */
void ScrCmd_createmon(struct ScriptContext *ctx) void ScrCmd_createmon(struct ScriptContext *ctx)
{ {

View file

@ -581,7 +581,7 @@ bool32 IsVsSeekerEnabled(void)
{ {
if (I_VS_SEEKER_CHARGING == 0) if (I_VS_SEEKER_CHARGING == 0)
return FALSE; return FALSE;
return (CheckBagHasItem(ITEM_VS_SEEKER, 1)); return (CheckBagHasItem(ITEM_VS_SEEKER, 1));
} }

View file

@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Anger Point does not trigger when already at maximum Attack
MESSAGE("Primeape cut its own HP and maximized ATTACK!"); MESSAGE("Primeape cut its own HP and maximized ATTACK!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FROST_BREATH, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_FROST_BREATH, opponent);
MESSAGE("A critical hit!"); MESSAGE("A critical hit!");
NONE_OF { NONE_OF {
ABILITY_POPUP(player, ABILITY_ANGER_POINT); ABILITY_POPUP(player, ABILITY_ANGER_POINT);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Primeape's Anger Point maxed its Attack!"); MESSAGE("Primeape's Anger Point maxed its Attack!");
@ -64,7 +64,7 @@ SINGLE_BATTLE_TEST("Anger Point does not trigger when a substitute takes the hit
MESSAGE("Primeape made a SUBSTITUTE!"); MESSAGE("Primeape made a SUBSTITUTE!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FROST_BREATH, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_FROST_BREATH, opponent);
MESSAGE("A critical hit!"); MESSAGE("A critical hit!");
NONE_OF { NONE_OF {
ABILITY_POPUP(player, ABILITY_ANGER_POINT); ABILITY_POPUP(player, ABILITY_ANGER_POINT);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
MESSAGE("Primeape's Anger Point maxed its Attack!"); MESSAGE("Primeape's Anger Point maxed its Attack!");

View file

@ -127,7 +127,7 @@ SINGLE_BATTLE_TEST("Clear Body, Full Metal Body, and White Smoke don't prevent s
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPERPOWER, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPERPOWER, opponent);
NONE_OF { NONE_OF {
ABILITY_POPUP(opponent, ability); ABILITY_POPUP(opponent, ability);
MESSAGE("Foe Solgaleo's Full Metal Body prevents stat loss!"); MESSAGE("Foe Solgaleo's Full Metal Body prevents stat loss!");
MESSAGE("Foe Torkoal's White Smoke prevents stat loss!"); MESSAGE("Foe Torkoal's White Smoke prevents stat loss!");
MESSAGE("Foe Metang's Clear Body prevents stat loss!"); MESSAGE("Foe Metang's Clear Body prevents stat loss!");
@ -186,7 +186,7 @@ SINGLE_BATTLE_TEST("Mold Breaker, Teravolt, and Turboblaze ignore Clear Body and
else{ else{
ANIMATION(ANIM_TYPE_MOVE, move, player); ANIMATION(ANIM_TYPE_MOVE, move, player);
NONE_OF { NONE_OF {
ABILITY_POPUP(opponent, ability); ABILITY_POPUP(opponent, ability);
MESSAGE("Foe Solgaleo's Full Metal Body prevents stat loss!"); MESSAGE("Foe Solgaleo's Full Metal Body prevents stat loss!");
MESSAGE("Foe Torkoal's White Smoke prevents stat loss!"); MESSAGE("Foe Torkoal's White Smoke prevents stat loss!");
MESSAGE("Foe Metang's Clear Body prevents stat loss!"); MESSAGE("Foe Metang's Clear Body prevents stat loss!");

View file

@ -116,7 +116,7 @@ SINGLE_BATTLE_TEST("(Gulp Missile) Cramorant in Gorging paralyzes the target if
} }
SINGLE_BATTLE_TEST("(Gulp Missile) triggers even if the user is fainted by opposing mon") SINGLE_BATTLE_TEST("(Gulp Missile) triggers even if the user is fainted by opposing mon")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_CRAMORANT) { HP(1); MaxHP(250); Ability(ABILITY_GULP_MISSILE); } PLAYER(SPECIES_CRAMORANT) { HP(1); MaxHP(250); Ability(ABILITY_GULP_MISSILE); }
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);

View file

@ -13,5 +13,5 @@ SINGLE_BATTLE_TEST("Magic Guard prevents recoil damage to the user")
ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_EDGE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_DOUBLE_EDGE, player);
HP_BAR(opponent); HP_BAR(opponent);
NOT HP_BAR(player); NOT HP_BAR(player);
} }
} }

View file

@ -13,7 +13,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Mirror Coat against specia
ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseSpAttack == 85); ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseSpAttack == 85);
ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseAttack == 65); ASSUME(gSpeciesInfo[SPECIES_GROVYLE].baseAttack == 65);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
PLAYER(SPECIES_GROVYLE) { Level(20); Moves(MOVE_ENERGY_BALL); } PLAYER(SPECIES_GROVYLE) { Level(20); Moves(MOVE_ENERGY_BALL); }
OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_TACKLE, MOVE_MIRROR_COAT); } OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_TACKLE, MOVE_MIRROR_COAT); }
} WHEN { } WHEN {
TURN { MOVE(player, MOVE_ENERGY_BALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_MIRROR_COAT : MOVE_TACKLE); } TURN { MOVE(player, MOVE_ENERGY_BALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_MIRROR_COAT : MOVE_TACKLE); }
@ -32,7 +32,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will blindly Counter against physical a
ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseAttack == 85); ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseAttack == 85);
ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseSpAttack == 60); ASSUME(gSpeciesInfo[SPECIES_MARSHTOMP].baseSpAttack == 60);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
PLAYER(SPECIES_MARSHTOMP) { Level(20); Moves(MOVE_WATERFALL); } PLAYER(SPECIES_MARSHTOMP) { Level(20); Moves(MOVE_WATERFALL); }
OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_TACKLE, MOVE_COUNTER); } OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_TACKLE, MOVE_COUNTER); }
} WHEN { } WHEN {
TURN { MOVE(player, MOVE_WATERFALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_COUNTER : MOVE_TACKLE); } TURN { MOVE(player, MOVE_WATERFALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_COUNTER : MOVE_TACKLE); }
@ -49,7 +49,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI will prioritize Revenge if slower")
GIVEN { GIVEN {
ASSUME(gMovesInfo[MOVE_REVENGE].effect == EFFECT_REVENGE); ASSUME(gMovesInfo[MOVE_REVENGE].effect == EFFECT_REVENGE);
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
PLAYER(SPECIES_GROVYLE) { Level(20); Speed(4); Moves(MOVE_ENERGY_BALL); } PLAYER(SPECIES_GROVYLE) { Level(20); Speed(4); Moves(MOVE_ENERGY_BALL); }
OPPONENT(SPECIES_CASTFORM) { Level(19); Speed(3); Moves(MOVE_TACKLE, MOVE_REVENGE); } OPPONENT(SPECIES_CASTFORM) { Level(19); Speed(3); Moves(MOVE_TACKLE, MOVE_REVENGE); }
} WHEN { } WHEN {
TURN { MOVE(player, MOVE_ENERGY_BALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_REVENGE : MOVE_TACKLE); } TURN { MOVE(player, MOVE_ENERGY_BALL) ; EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_REVENGE : MOVE_TACKLE); }
@ -83,7 +83,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_RISKY: AI prefers high damage moves at the expens
GIVEN { GIVEN {
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag); AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | aiRiskyFlag);
PLAYER(SPECIES_PSYDUCK) { Level(5); Moves(MOVE_TACKLE); } PLAYER(SPECIES_PSYDUCK) { Level(5); Moves(MOVE_TACKLE); }
OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_THUNDER, MOVE_THUNDERBOLT); } OPPONENT(SPECIES_CASTFORM) { Level(20); Moves(MOVE_THUNDER, MOVE_THUNDERBOLT); }
} WHEN { } WHEN {
TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_THUNDER : MOVE_THUNDERBOLT); } TURN { MOVE(player, MOVE_TACKLE); EXPECT_MOVE(opponent, aiRiskyFlag ? MOVE_THUNDER : MOVE_THUNDERBOLT); }

View file

@ -646,7 +646,7 @@ SINGLE_BATTLE_TEST("(TERA) Protean cannot change the type of a Terastallized Pok
PLAYER(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); TeraType(TYPE_GRASS); } PLAYER(SPECIES_GRENINJA) { Ability(ABILITY_PROTEAN); TeraType(TYPE_GRASS); }
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
} WHEN { } WHEN {
TURN { MOVE(player, MOVE_BUBBLE, gimmick: GIMMICK_TERA); TURN { MOVE(player, MOVE_BUBBLE, gimmick: GIMMICK_TERA);
MOVE(opponent, MOVE_EMBER); } MOVE(opponent, MOVE_EMBER); }
} SCENE { } SCENE {
MESSAGE("Greninja used Bubble!"); MESSAGE("Greninja used Bubble!");

View file

@ -10,7 +10,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Z-Moves do not retain priority")
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); } PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMALIUM_Z); }
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
} WHEN { } WHEN {
TURN { MOVE(opponent, MOVE_TACKLE); TURN { MOVE(opponent, MOVE_TACKLE);
MOVE(player, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); } MOVE(player, MOVE_QUICK_ATTACK, gimmick: GIMMICK_Z_MOVE); }
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, opponent);
@ -597,7 +597,7 @@ SINGLE_BATTLE_TEST("(Z-MOVE) Searing Sunraze Smash ignores the target's abilitie
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEARING_SUNRAZE_SMASH, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_SEARING_SUNRAZE_SMASH, player);
HP_BAR(opponent); HP_BAR(opponent);
MESSAGE("A critical hit!"); MESSAGE("A critical hit!");
} }
} }
SINGLE_BATTLE_TEST("(Z-MOVE) Z-Revelation Dance always transforms into Breakneck Blitz") SINGLE_BATTLE_TEST("(Z-MOVE) Z-Revelation Dance always transforms into Breakneck Blitz")

View file

@ -69,7 +69,7 @@ SINGLE_BATTLE_TEST("Ability Shield protects against Mycelium Might")
} WHEN { } WHEN {
TURN { MOVE(opponent, MOVE_SPORE); MOVE(player, MOVE_SPORE); } TURN { MOVE(opponent, MOVE_SPORE); MOVE(player, MOVE_SPORE); }
} SCENE { } SCENE {
if (item == ITEM_ABILITY_SHIELD) { if (item == ITEM_ABILITY_SHIELD) {
NONE_OF { NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent); ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, opponent);

View file

@ -10,7 +10,7 @@ ASSUMPTIONS
DOUBLE_BATTLE_TEST("Heal Bell cures the entire party") DOUBLE_BATTLE_TEST("Heal Bell cures the entire party")
{ {
u32 move; u32 move;
PARAMETRIZE { move = MOVE_HEAL_BELL; } PARAMETRIZE { move = MOVE_HEAL_BELL; }
PARAMETRIZE { move = MOVE_AROMATHERAPY; } PARAMETRIZE { move = MOVE_AROMATHERAPY; }
@ -39,10 +39,10 @@ DOUBLE_BATTLE_TEST("Heal Bell cures the entire party")
DOUBLE_BATTLE_TEST("Heal Bell does not cure soundproof partners") DOUBLE_BATTLE_TEST("Heal Bell does not cure soundproof partners")
{ {
u32 ability; u32 ability;
PARAMETRIZE { ability = ABILITY_SCRAPPY; } PARAMETRIZE { ability = ABILITY_SCRAPPY; }
PARAMETRIZE { ability = ABILITY_SOUNDPROOF; } PARAMETRIZE { ability = ABILITY_SOUNDPROOF; }
ASSUME(B_HEAL_BELL_SOUNDPROOF != GEN_5); ASSUME(B_HEAL_BELL_SOUNDPROOF != GEN_5);
GIVEN { GIVEN {
@ -65,10 +65,10 @@ DOUBLE_BATTLE_TEST("Heal Bell does not cure soundproof partners")
SINGLE_BATTLE_TEST("Heal Bell cures inactive soundproof Pokemon") SINGLE_BATTLE_TEST("Heal Bell cures inactive soundproof Pokemon")
{ {
u32 ability; u32 ability;
PARAMETRIZE { ability = ABILITY_SCRAPPY; } PARAMETRIZE { ability = ABILITY_SCRAPPY; }
PARAMETRIZE { ability = ABILITY_SOUNDPROOF; } PARAMETRIZE { ability = ABILITY_SOUNDPROOF; }
ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_5); ASSUME(B_HEAL_BELL_SOUNDPROOF >= GEN_5);
GIVEN { GIVEN {
@ -87,7 +87,7 @@ SINGLE_BATTLE_TEST("Heal Bell cures inactive soundproof Pokemon")
SINGLE_BATTLE_TEST("Heal Bell cures a soundproof user") SINGLE_BATTLE_TEST("Heal Bell cures a soundproof user")
{ {
ASSUME(B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_8); ASSUME(B_HEAL_BELL_SOUNDPROOF == GEN_5 || B_HEAL_BELL_SOUNDPROOF >= GEN_8);
GIVEN { GIVEN {

View file

@ -90,7 +90,7 @@ SINGLE_BATTLE_TEST("Knock Off does not remove items through Substitute")
PLAYER(SPECIES_WOBBUFFET); PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LEFTOVERS); }; OPPONENT(SPECIES_WOBBUFFET) { Item(ITEM_LEFTOVERS); };
} WHEN { } WHEN {
TURN { MOVE(opponent, MOVE_SUBSTITUTE); TURN { MOVE(opponent, MOVE_SUBSTITUTE);
MOVE(player, MOVE_KNOCK_OFF); } MOVE(player, MOVE_KNOCK_OFF); }
} SCENE { } SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
@ -112,7 +112,7 @@ SINGLE_BATTLE_TEST("Recycle cannot recover an item removed by Knock Off")
ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_KNOCK_OFF, player);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF); ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_ITEM_KNOCKOFF);
MESSAGE("Wobbuffet knocked off Foe Wobbuffet's Leftovers!"); MESSAGE("Wobbuffet knocked off Foe Wobbuffet's Leftovers!");
MESSAGE("Foe Wobbuffet used Recycle!"); MESSAGE("Foe Wobbuffet used Recycle!");
MESSAGE("But it failed!"); MESSAGE("But it failed!");
} THEN { } THEN {

View file

@ -37,7 +37,7 @@ SINGLE_BATTLE_TEST("Revelation Dance changes its type depending on the user's 1s
ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, player);
HP_BAR(opponent); HP_BAR(opponent);
MESSAGE("It's not very effective…"); MESSAGE("It's not very effective…");
} }
} }
} }
} }
@ -142,7 +142,7 @@ SINGLE_BATTLE_TEST("Revelation Dance becomes Normal type if used by a Typeless P
NONE_OF { NONE_OF {
ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, player); ANIMATION(ANIM_TYPE_MOVE, MOVE_REVELATION_DANCE, player);
HP_BAR(opponent); HP_BAR(opponent);
MESSAGE("It's not very effective…"); MESSAGE("It's not very effective…");
} }
} }
} }

View file

@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Sleep Talk fails if not asleep")
u32 status; u32 status;
PARAMETRIZE { status = STATUS1_SLEEP; } PARAMETRIZE { status = STATUS1_SLEEP; }
PARAMETRIZE { status = STATUS1_NONE; } PARAMETRIZE { status = STATUS1_NONE; }
GIVEN { GIVEN {
PLAYER(SPECIES_WOBBUFFET) { Status1(status); Moves(MOVE_SLEEP_TALK, MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH); } PLAYER(SPECIES_WOBBUFFET) { Status1(status); Moves(MOVE_SLEEP_TALK, MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH); }
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);
@ -35,7 +35,7 @@ SINGLE_BATTLE_TEST("Sleep Talk fails if not asleep")
SINGLE_BATTLE_TEST("Sleep Talk works if user has Comatose") SINGLE_BATTLE_TEST("Sleep Talk works if user has Comatose")
{ {
GIVEN { GIVEN {
PLAYER(SPECIES_KOMALA) { Moves(MOVE_SLEEP_TALK, MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH); } PLAYER(SPECIES_KOMALA) { Moves(MOVE_SLEEP_TALK, MOVE_TACKLE, MOVE_POUND, MOVE_SCRATCH); }
OPPONENT(SPECIES_WOBBUFFET); OPPONENT(SPECIES_WOBBUFFET);

View file

@ -71,4 +71,4 @@ SINGLE_BATTLE_TEST("Telekinesis makes the target immune to Ground-type attacks")
TO_DO_BATTLE_TEST("Baton Pass passes Telekinesis' effect"); TO_DO_BATTLE_TEST("Baton Pass passes Telekinesis' effect");
//Bulbapedia doesn't confirm what happens with Diglett, Dugtrio, Sandygast and Palossand, so it needs to be tested in-game. //Bulbapedia doesn't confirm what happens with Diglett, Dugtrio, Sandygast and Palossand, so it needs to be tested in-game.
TO_DO_BATTLE_TEST("Baton Pass removes Telekinesis' effect disappears if the switching-in mon is Mega Gengar"); TO_DO_BATTLE_TEST("Baton Pass removes Telekinesis' effect disappears if the switching-in mon is Mega Gengar");

View file

@ -13,7 +13,7 @@ with open("./include/config/pokemon.h", "r") as file:
def parse_mon_name(name): def parse_mon_name(name):
return re.sub(r'(?!^)([A-Z]+)', r'_\1', name).upper() return re.sub(r'(?!^)([A-Z]+)', r'_\1', name).upper()
tm_moves = [] tm_moves = []
tutor_moves = [] tutor_moves = []
@ -196,7 +196,7 @@ for move in tm_moves:
header += "// " + longest_move_name * "*" + " //\n" header += "// " + longest_move_name * "*" + " //\n"
header_print(tutor_title) header_print(tutor_title)
tutor_moves.sort() # alphabetically sort tutor moves for easier referencing tutor_moves.sort() # alphabetically sort tutor moves for easier referencing
for move in tutor_moves: for move in tutor_moves:
header_print("- " + move) header_print("- " + move)
header += "// " + longest_move_name * "*" + " //\n" header += "// " + longest_move_name * "*" + " //\n"
header_print(universal_title) header_print(universal_title)

View file

@ -673,14 +673,14 @@ int AsmFile::FindLastLineNumber(std::string& filename)
if (pos < 0) if (pos < 0)
RaiseError("line indicator for header file not found before `enum`"); RaiseError("line indicator for header file not found before `enum`");
pos++; pos++;
while (m_buffer[pos] == ' ' || m_buffer[pos] == '\t') while (m_buffer[pos] == ' ' || m_buffer[pos] == '\t')
pos++; pos++;
if (!IsAsciiDigit(m_buffer[pos])) if (!IsAsciiDigit(m_buffer[pos]))
RaiseError("malformatted line indicator found before `enum`, expected line number"); RaiseError("malformatted line indicator found before `enum`, expected line number");
unsigned n = 0; unsigned n = 0;
int digit = 0; int digit = 0;
while ((digit = ConvertDigit(m_buffer[pos++], 10)) != -1) while ((digit = ConvertDigit(m_buffer[pos++], 10)) != -1)
@ -715,7 +715,7 @@ int AsmFile::FindLastLineNumber(std::string& filename)
filename += c; filename += c;
} }
return n + linebreaks - 1; return n + linebreaks - 1;
} }