06/10/25 Master to upcoming merge
This commit is contained in:
commit
870b93aad9
@ -43,9 +43,10 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using?
|
||||
options:
|
||||
- 1.13.1 (Latest release)
|
||||
- 1.13.2 (Latest release)
|
||||
- master (default, unreleased bugfixes)
|
||||
- upcoming (Edge)
|
||||
- 1.13.1
|
||||
- 1.13.0
|
||||
- 1.12.3
|
||||
- 1.12.2
|
||||
|
||||
@ -43,9 +43,10 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using?
|
||||
options:
|
||||
- 1.13.1 (Latest release)
|
||||
- 1.13.2 (Latest release)
|
||||
- master (default, unreleased bugfixes)
|
||||
- upcoming (Edge)
|
||||
- 1.13.1
|
||||
- 1.13.0
|
||||
- 1.12.3
|
||||
- 1.12.2
|
||||
|
||||
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
@ -43,9 +43,10 @@ body:
|
||||
label: Version
|
||||
description: What version of pokeemerald-expansion are you using?
|
||||
options:
|
||||
- 1.13.1 (Latest release)
|
||||
- 1.13.2 (Latest release)
|
||||
- master (default, unreleased bugfixes)
|
||||
- upcoming (Edge)
|
||||
- 1.13.1
|
||||
- 1.13.0
|
||||
- 1.12.3
|
||||
- 1.12.2
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
If you use **`pokeemerald-expansion`**, please credit **RHH (Rom Hacking Hideout)**. Optionally, include the version number for clarity.
|
||||
|
||||
```
|
||||
Based off RHH's pokeemerald-expansion 1.13.1 https://github.com/rh-hideout/pokeemerald-expansion/
|
||||
Based off RHH's pokeemerald-expansion 1.13.2 https://github.com/rh-hideout/pokeemerald-expansion/
|
||||
```
|
||||
|
||||
Please consider [crediting all contributors](CREDITS.md) involved in the project!
|
||||
|
||||
@ -199,7 +199,7 @@ BattleScript_EffectDoodle_AfterCopy:
|
||||
printstring STRINGID_PKMNCOPIEDFOE
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
switchinabilities BS_ATTACKER
|
||||
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_MoveEnd
|
||||
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_EffectDoodleMoveEnd
|
||||
addbyte gBattleCommunication, 1
|
||||
jumpifnoally BS_ATTACKER, BattleScript_EffectDoodleMoveEnd
|
||||
setallytonextattacker BattleScript_EffectDoodle_CopyAbility
|
||||
@ -751,13 +751,13 @@ BattleScript_FlingLightBall:
|
||||
goto BattleScript_FlingEnd
|
||||
BattleScript_FlingMentalHerb:
|
||||
curecertainstatuses
|
||||
savetarget
|
||||
saveattacker
|
||||
copybyte gBattlerAttacker, gBattlerTarget
|
||||
playanimation BS_ATTACKER, B_ANIM_HELD_ITEM_EFFECT, NULL
|
||||
printfromtable gMentalHerbCureStringIds
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
updatestatusicon BS_ATTACKER
|
||||
restoretarget
|
||||
restoreattacker
|
||||
goto BattleScript_FlingEnd
|
||||
BattleScript_FlingPoisonBarb:
|
||||
seteffectsecondary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_POISON
|
||||
@ -7632,6 +7632,13 @@ BattleScript_AbilityCuredStatus::
|
||||
updatestatusicon BS_SCRIPTING
|
||||
return
|
||||
|
||||
BattleScript_AbilityCuredStatusEnd3::
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_PKMNSXCUREDITSYPROBLEM
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
updatestatusicon BS_SCRIPTING
|
||||
end3
|
||||
|
||||
BattleScript_BattlerShookOffTaunt::
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_PKMNSHOOKOFFTHETAUNT
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
- [Day/Night System FAQ](tutorials/dns.md)
|
||||
- [Changelog](./CHANGELOG.md)
|
||||
- [1.13.x]()
|
||||
- [Version 1.13.2](changelogs/1.13.x/1.13.2.md)
|
||||
- [Version 1.13.1](changelogs/1.13.x/1.13.1.md)
|
||||
- [Version 1.13.0](changelogs/1.13.x/1.13.0.md)
|
||||
- [1.12.x]()
|
||||
|
||||
123
docs/changelogs/1.13.x/1.13.2.md
Normal file
123
docs/changelogs/1.13.x/1.13.2.md
Normal file
@ -0,0 +1,123 @@
|
||||
```md
|
||||
## How to update
|
||||
- If you haven't set up a remote, run the command `git remote add RHH https://github.com/rh-hideout/pokeemerald-expansion`.
|
||||
- Once you have your remote set up, run the command `git pull RHH expansion/1.13.2
|
||||
`.
|
||||
```
|
||||
|
||||
|
||||
## 🧬 General 🧬
|
||||
### Changed
|
||||
* Removed superflous palette compression check by @hedara90 in [#7718](https://github.com/rh-hideout/pokeemerald-expansion/pull/7718)
|
||||
* update of sv.json to consider newest DLC changes by @wiz1989 in [#7672](https://github.com/rh-hideout/pokeemerald-expansion/pull/7672)
|
||||
* Adjusted line break substring breaking by @hedara90 in [#7789](https://github.com/rh-hideout/pokeemerald-expansion/pull/7789)
|
||||
* Fixup add-new-trainer-front-pic tutorial. by @GraionDilach in [#7802](https://github.com/rh-hideout/pokeemerald-expansion/pull/7802)
|
||||
* Adds conversion script for trainers.h by @AlexOn1ine in [#7663](https://github.com/rh-hideout/pokeemerald-expansion/pull/7663)
|
||||
|
||||
### Fixed
|
||||
* Fix bug with IF_GENDER evolution condition by @FosterProgramming in [#7749](https://github.com/rh-hideout/pokeemerald-expansion/pull/7749)
|
||||
* Pokemon storage moving items bugfix by @FosterProgramming in [#7763](https://github.com/rh-hideout/pokeemerald-expansion/pull/7763)
|
||||
* Fix catch bug introduced in #7774 by @FosterProgramming in [#7782](https://github.com/rh-hideout/pokeemerald-expansion/pull/7782)
|
||||
* Fix Party Menu move select name width by @AsparagusEduardo in [#7820](https://github.com/rh-hideout/pokeemerald-expansion/pull/7820)
|
||||
* Fix Debug Give Pokémon (Complex) with duplicate moves by @AsparagusEduardo in [#7821](https://github.com/rh-hideout/pokeemerald-expansion/pull/7821)
|
||||
|
||||
## 🗺️ Overworld 🗺️
|
||||
### Changed
|
||||
* Added missing `LOCALID_NONE` by @estellarc in [#7783](https://github.com/rh-hideout/pokeemerald-expansion/pull/7783)
|
||||
|
||||
### Fixed
|
||||
* Fix TRAINER_TYPE_SEE_ALL_DIRECTIONS by @DizzyEggg in [#7779](https://github.com/rh-hideout/pokeemerald-expansion/pull/7779)
|
||||
|
||||
## 🐉 Pokémon 🐉
|
||||
### Fixed
|
||||
* fix: seen flags for first mon in enemy party by @khbsd in [#7791](https://github.com/rh-hideout/pokeemerald-expansion/pull/7791)
|
||||
|
||||
## ⚔️ Battle General ⚔️
|
||||
### Fixed
|
||||
* Fix most failed tests with `GEN_LATEST` = `GEN_7` by @AsparagusEduardo in [#7688](https://github.com/rh-hideout/pokeemerald-expansion/pull/7688)
|
||||
* Fixes Sweet Veil not protecting sleep from Yawn status by @AlexOn1ine in [#7704](https://github.com/rh-hideout/pokeemerald-expansion/pull/7704)
|
||||
* Fix incorrect wrap turn amount by @AlexOn1ine in [#7667](https://github.com/rh-hideout/pokeemerald-expansion/pull/7667)
|
||||
* Fixes Rage Fist for gen7 Disguise by @AlexOn1ine in [#7692](https://github.com/rh-hideout/pokeemerald-expansion/pull/7692)
|
||||
* Fixes Intrepid Sword/Dauntless Shield boosting after entering while at max stats by @PhallenTree in [#7716](https://github.com/rh-hideout/pokeemerald-expansion/pull/7716)
|
||||
* Fixes incorrect ending for some scripts by @AlexOn1ine in [#7691](https://github.com/rh-hideout/pokeemerald-expansion/pull/7691)
|
||||
* Fixes Uproar not waking up mons by @AlexOn1ine in [#7714](https://github.com/rh-hideout/pokeemerald-expansion/pull/7714)
|
||||
* Fixes Endure and Eject Pack issues by @AlexOn1ine in [#7687](https://github.com/rh-hideout/pokeemerald-expansion/pull/7687)
|
||||
* Fix Beak Blast burning fire types by @hedara90 in [#7740](https://github.com/rh-hideout/pokeemerald-expansion/pull/7740)
|
||||
* Fixes Recharge not actually being removed when recharge turn occurs by @PhallenTree in [#7744](https://github.com/rh-hideout/pokeemerald-expansion/pull/7744)
|
||||
* Bugfixes Batch by @AlexOn1ine in [#7739](https://github.com/rh-hideout/pokeemerald-expansion/pull/7739)
|
||||
* Fixes Beat Up incorrect slots usage by @AlexOn1ine in [#7741](https://github.com/rh-hideout/pokeemerald-expansion/pull/7741)
|
||||
* Fixes Mycelium Might and Lagging Tail adjusting prio incorrectly by @AlexOn1ine in [#7742](https://github.com/rh-hideout/pokeemerald-expansion/pull/7742)
|
||||
* Wrong argument passed down by @AlexOn1ine in [#7751](https://github.com/rh-hideout/pokeemerald-expansion/pull/7751)
|
||||
* Fixed Ball Fetch Ability by @bassforte123 in [#7764](https://github.com/rh-hideout/pokeemerald-expansion/pull/7764)
|
||||
* Fixes Flower Shield affecting semi-invulnerable mons by @AlexOn1ine in [#7766](https://github.com/rh-hideout/pokeemerald-expansion/pull/7766)
|
||||
* Fixes Helping Hand boosts not stacking with each other by @PhallenTree in [#7775](https://github.com/rh-hideout/pokeemerald-expansion/pull/7775)
|
||||
* Fixes OHKO moves calculating accuracy twice by @AlexOn1ine in [#7785](https://github.com/rh-hideout/pokeemerald-expansion/pull/7785)
|
||||
* Fixes Instructed moves looking at the wrong turn order number by @PhallenTree in [#7788](https://github.com/rh-hideout/pokeemerald-expansion/pull/7788)
|
||||
* Fix Flame Burst timeout if primary target is fainted by @hedara90 in [#7793](https://github.com/rh-hideout/pokeemerald-expansion/pull/7793)
|
||||
* Fixes Leppa Berry timings by @AlexOn1ine in [#7787](https://github.com/rh-hideout/pokeemerald-expansion/pull/7787)
|
||||
* Fixes Effects activating when move wasn't successful by @AlexOn1ine in [#7803](https://github.com/rh-hideout/pokeemerald-expansion/pull/7803)
|
||||
* Fixes Throat Spray being blocked by Sheer Force by @AlexOn1ine in [#7808](https://github.com/rh-hideout/pokeemerald-expansion/pull/7808)
|
||||
* Fixes inaccurate save / restore in Fling script by @AlexOn1ine in [#7811](https://github.com/rh-hideout/pokeemerald-expansion/pull/7811)
|
||||
* Fix test exit prints for stored battlers by @AlexOn1ine in [#7807](https://github.com/rh-hideout/pokeemerald-expansion/pull/7807)
|
||||
* Fixes EndTurn Eject Pack by @AlexOn1ine in [#7813](https://github.com/rh-hideout/pokeemerald-expansion/pull/7813)
|
||||
* Fix Battle Frontier using Strange Balls by @AsparagusEduardo in [#7823](https://github.com/rh-hideout/pokeemerald-expansion/pull/7823)
|
||||
* Fix Throat Spray activating multiply times by @AlexOn1ine in [#7818](https://github.com/rh-hideout/pokeemerald-expansion/pull/7818)
|
||||
* fix (choice lock): Gorilla Tactics interactions with choice item removal by @ghostyboyy97 in [#7824](https://github.com/rh-hideout/pokeemerald-expansion/pull/7824)
|
||||
- Fixed interactions with choice items and Gorilla Tactics both present when choice item is removed by a thief effect or item swap effect.
|
||||
* Fixes encore random target for gen5+ by @AlexOn1ine in [#7800](https://github.com/rh-hideout/pokeemerald-expansion/pull/7800)
|
||||
|
||||
## 🤹 Moves 🤹
|
||||
### Changed
|
||||
* Initial Lash Out tests by @grintoul1 in [#7769](https://github.com/rh-hideout/pokeemerald-expansion/pull/7769)
|
||||
|
||||
### Fixed
|
||||
* Fix Salt Cure in double battles by @Bassoonian in [#7797](https://github.com/rh-hideout/pokeemerald-expansion/pull/7797)
|
||||
|
||||
## 🎭 Abilities 🎭
|
||||
### Fixed
|
||||
* Fix for Levitate and Mold Breaker being seen correctly by switch AI, with Levitate tests by @grintoul1 in [#7748](https://github.com/rh-hideout/pokeemerald-expansion/pull/7748)
|
||||
* Fix Forecast and Flower Gift corruption by @Bassoonian in [#7796](https://github.com/rh-hideout/pokeemerald-expansion/pull/7796)
|
||||
* Immunity abilities trigger on turn 0 (leads) by @spindrift64 in [#7814](https://github.com/rh-hideout/pokeemerald-expansion/pull/7814)
|
||||
|
||||
## 🤖 Battle AI 🤖
|
||||
### Changed
|
||||
* Tidy up CanTargetFaintAiWithMod and CanTargetMoveFaintAi by @grintoul1 in [#7693](https://github.com/rh-hideout/pokeemerald-expansion/pull/7693)
|
||||
* Doubles AI: Trick Room timer fix and test for DOUBLE_TRICK_ROOM_ON_LAST_TURN_CHANCE by @grintoul1 in [#7622](https://github.com/rh-hideout/pokeemerald-expansion/pull/7622)
|
||||
|
||||
### Fixed
|
||||
* Toxic thread uses light screen's scoring.... by @surskitty in [#7674](https://github.com/rh-hideout/pokeemerald-expansion/pull/7674)
|
||||
* Fix most failed and assume fail tests with `GEN_LATEST` = `GEN_6` by @AsparagusEduardo in [#7696](https://github.com/rh-hideout/pokeemerald-expansion/pull/7696)
|
||||
* Fix for Levitate and Mold Breaker being seen correctly by switch AI, with Levitate tests by @grintoul1 in [#7748](https://github.com/rh-hideout/pokeemerald-expansion/pull/7748)
|
||||
|
||||
## 🧹 Other Cleanup 🧹
|
||||
* Tidy up CanTargetFaintAiWithMod and CanTargetMoveFaintAi by @grintoul1 in [#7693](https://github.com/rh-hideout/pokeemerald-expansion/pull/7693)
|
||||
* Removed superflous palette compression check by @hedara90 in [#7718](https://github.com/rh-hideout/pokeemerald-expansion/pull/7718)
|
||||
* Fix failing test for B_PREFERRED_ICE_WEATHER = B_ICE_WEATHER_SNOW by @phexmiau in [#7755](https://github.com/rh-hideout/pokeemerald-expansion/pull/7755)
|
||||
* Adjusted line break substring breaking by @hedara90 in [#7789](https://github.com/rh-hideout/pokeemerald-expansion/pull/7789)
|
||||
* Added missing `LOCALID_NONE` by @estellarc in [#7783](https://github.com/rh-hideout/pokeemerald-expansion/pull/7783)
|
||||
|
||||
## 🧪 Test Runner 🧪
|
||||
### Changed
|
||||
* Add tests for Filter, Solid Rock and Prism Armor by @hedara90 in [#7734](https://github.com/rh-hideout/pokeemerald-expansion/pull/7734)
|
||||
* Fix failing test for B_PREFERRED_ICE_WEATHER = B_ICE_WEATHER_SNOW by @phexmiau in [#7755](https://github.com/rh-hideout/pokeemerald-expansion/pull/7755)
|
||||
* Initial Lash Out tests by @grintoul1 in [#7769](https://github.com/rh-hideout/pokeemerald-expansion/pull/7769)
|
||||
* Improve how test involving ball throw work by @FosterProgramming in [#7774](https://github.com/rh-hideout/pokeemerald-expansion/pull/7774)
|
||||
|
||||
### Fixed
|
||||
* Fix EWRAM_INIT in tests and add a default state to test runner main loop by @hedara90 in [#7699](https://github.com/rh-hideout/pokeemerald-expansion/pull/7699)
|
||||
* Fix most failed and assume fail tests with `GEN_LATEST` = `GEN_6` by @AsparagusEduardo in [#7696](https://github.com/rh-hideout/pokeemerald-expansion/pull/7696)
|
||||
* Fix for Levitate and Mold Breaker being seen correctly by switch AI, with Levitate tests by @grintoul1 in [#7748](https://github.com/rh-hideout/pokeemerald-expansion/pull/7748)
|
||||
* Fix Big Root tests by @hedara90 in [#7817](https://github.com/rh-hideout/pokeemerald-expansion/pull/7817)
|
||||
|
||||
## 📚 Documentation 📚
|
||||
* Fixup add-new-trainer-front-pic tutorial. by @GraionDilach in [#7802](https://github.com/rh-hideout/pokeemerald-expansion/pull/7802)
|
||||
|
||||
## New Contributors
|
||||
* @phexmiau made their first contribution in [#7755](https://github.com/rh-hideout/pokeemerald-expansion/pull/7755)
|
||||
* @ghostyboyy97 made their first contribution in [#7824](https://github.com/rh-hideout/pokeemerald-expansion/pull/7824)
|
||||
|
||||
**Full Changelog**: https://github.com/rh-hideout/pokeemerald-expansion/compare/expansion/1.13.1...expansion/1.13.2
|
||||
|
||||
|
||||
<!--Last PR: 7814-->
|
||||
<!--Used to keep track of the last PR merged in case new ones come in before the changelog is done.-->
|
||||
@ -598,7 +598,8 @@ struct PartyState
|
||||
u32 supersweetSyrup:1;
|
||||
u32 timesGotHit:5;
|
||||
u32 changedSpecies:11; // For forms when multiple mons can change into the same pokemon.
|
||||
u32 padding:10;
|
||||
u32 sentOut:1;
|
||||
u32 padding:9;
|
||||
};
|
||||
|
||||
// Cleared at the beginning of the battle. Fields need to be cleared when needed manually otherwise.
|
||||
|
||||
@ -198,6 +198,7 @@ extern const u8 BattleScript_AbilityStatusEffect[];
|
||||
extern const u8 BattleScript_SynchronizeActivates[];
|
||||
extern const u8 BattleScript_NoItemSteal[];
|
||||
extern const u8 BattleScript_AbilityCuredStatus[];
|
||||
extern const u8 BattleScript_AbilityCuredStatusEnd3[];
|
||||
extern const u8 BattleScript_IgnoresWhileAsleep[];
|
||||
extern const u8 BattleScript_IgnoresAndUsesRandomMove[];
|
||||
extern const u8 BattleScript_MoveUsedLoafingAround[];
|
||||
|
||||
@ -58,6 +58,7 @@ enum {
|
||||
ABILITYEFFECT_OPPORTUNIST,
|
||||
ABILITYEFFECT_OPPORTUNIST_FIRST_TURN,
|
||||
ABILITYEFFECT_SWITCH_IN_STATUSES,
|
||||
ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES,
|
||||
};
|
||||
|
||||
// For the first argument of ItemBattleEffects, to deteremine which block of item effects to try
|
||||
@ -329,6 +330,7 @@ struct Pokemon *GetIllusionMonPtr(u32 battler);
|
||||
void ClearIllusionMon(u32 battler);
|
||||
u32 GetIllusionMonPartyId(struct Pokemon *party, struct Pokemon *mon, struct Pokemon *partnerMon, u32 battler);
|
||||
bool32 SetIllusionMon(struct Pokemon *mon, u32 battler);
|
||||
u32 TryImmunityAbilityHealStatus(u32 battler, u32 caseID);
|
||||
bool32 ShouldGetStatBadgeBoost(u16 flagId, u32 battler);
|
||||
enum DamageCategory GetBattleMoveCategory(u32 move);
|
||||
void SetDynamicMoveCategory(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||
@ -409,6 +411,7 @@ bool32 IsPursuitTargetSet(void);
|
||||
void ClearPursuitValuesIfSet(u32 battler);
|
||||
void ClearPursuitValues(void);
|
||||
bool32 HasWeatherEffect(void);
|
||||
bool32 IsAnyTargetAffected(u32 battlerAtk);
|
||||
bool32 IsFutureSightAttackerInParty(u32 battlerAtk, u32 battlerDef, u32 move);
|
||||
bool32 HadMoreThanHalfHpNowDoesnt(u32 battler);
|
||||
void UpdateStallMons(void);
|
||||
|
||||
@ -317,6 +317,7 @@
|
||||
#define B_TOXIC_REVERSAL GEN_LATEST // In Gen5+, bad poison will change to regular poison at the end of battles.
|
||||
#define B_TRY_CATCH_TRAINER_BALL GEN_LATEST // In Gen4+, trying to catch a Trainer's Pokémon does not consume the Poké Ball.
|
||||
#define B_SLEEP_CLAUSE FALSE // Enables Sleep Clause all the time in every case, overriding B_FLAG_SLEEP_CLAUSE. Use that for modularity.
|
||||
#define B_PARTNER_MONS_MARKED_SEEN FALSE // If TRUE, if your double battle partner sends out a Pokémon you haven't encountered yet, it will be marked as SEEN in your Pokédex.
|
||||
|
||||
#define NUM_BEEPS_GEN_LATEST 4 // Loops 4 times
|
||||
#define NUM_BEEPS_GEN_3 -1 // Loops infinitely
|
||||
|
||||
@ -153,6 +153,7 @@ enum MoveEndEffects
|
||||
MOVEEND_MULTIHIT_MOVE,
|
||||
MOVEEND_MOVE_BLOCK,
|
||||
MOVEEND_ITEM_EFFECTS_ATTACKER,
|
||||
MOVEEND_ITEM_THROAT_SPRAY,
|
||||
MOVEEND_ABILITY_BLOCK,
|
||||
MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist
|
||||
MOVEEND_COLOR_CHANGE, // Color Change / Berserk / Anger Shell
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#ifndef GUARD_CONSTANTS_EXPANSION_H
|
||||
#define GUARD_CONSTANTS_EXPANSION_H
|
||||
|
||||
// Last version: 1.13.1
|
||||
// Last version: 1.13.2
|
||||
#define EXPANSION_VERSION_MAJOR 1
|
||||
#define EXPANSION_VERSION_MINOR 14
|
||||
#define EXPANSION_VERSION_PATCH 0
|
||||
|
||||
@ -41,6 +41,10 @@ enum GenConfigTag
|
||||
GEN_CONFIG_PRANKSTER_DARK_TYPES,
|
||||
GEN_CONFIG_DESTINY_BOND_FAIL,
|
||||
GEN_CONFIG_POWDER_RAIN,
|
||||
GEN_CONFIG_POWDER_GRASS,
|
||||
GEN_CONFIG_OBLIVIOUS_TAUNT,
|
||||
GEN_CONFIG_TOXIC_NEVER_MISS,
|
||||
GEN_CONFIG_PARALYZE_ELECTRIC,
|
||||
GEN_CONFIG_COUNT
|
||||
};
|
||||
|
||||
|
||||
@ -44,6 +44,10 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
|
||||
[GEN_CONFIG_PRANKSTER_DARK_TYPES] = B_PRANKSTER_DARK_TYPES,
|
||||
[GEN_CONFIG_DESTINY_BOND_FAIL] = B_DESTINY_BOND_FAIL,
|
||||
[GEN_CONFIG_POWDER_RAIN] = B_POWDER_RAIN,
|
||||
[GEN_CONFIG_POWDER_GRASS] = B_POWDER_GRASS,
|
||||
[GEN_CONFIG_OBLIVIOUS_TAUNT] = B_OBLIVIOUS_TAUNT,
|
||||
[GEN_CONFIG_TOXIC_NEVER_MISS] = B_TOXIC_NEVER_MISS,
|
||||
[GEN_CONFIG_PARALYZE_ELECTRIC] = B_PARALYZE_ELECTRIC,
|
||||
};
|
||||
|
||||
#if TESTING
|
||||
|
||||
@ -853,6 +853,7 @@ u8 GetOpposingLinkMultiBattlerId(bool8 rightSide, u8 multiplayerId);
|
||||
u16 FacilityClassToPicIndex(u16 facilityClass);
|
||||
u16 PlayerGenderToFrontTrainerPicId(u8 playerGender);
|
||||
void HandleSetPokedexFlag(enum NationalDexOrder nationalNum, u8 caseId, u32 personality);
|
||||
void HandleSetPokedexFlagFromMon(struct Pokemon *mon, u32 caseId);
|
||||
bool8 HasTwoFramesAnimation(u16 species);
|
||||
struct MonSpritesGfxManager *CreateMonSpritesGfxManager(u8 managerId, u8 mode);
|
||||
void DestroyMonSpritesGfxManager(u8 managerId);
|
||||
|
||||
401
migration_scripts/1.13/convert_trainers.py
Normal file
401
migration_scripts/1.13/convert_trainers.py
Normal file
@ -0,0 +1,401 @@
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
is_blank = re.compile(r'^[ \t]*(//.*)?$')
|
||||
|
||||
begin_party_definition = re.compile(r'struct TrainerMon (\w+)\[\] =')
|
||||
end_party_definition = re.compile(r'^ },')
|
||||
begin_pokemon_definition = re.compile(r'^ { *$')
|
||||
end_pokemon_definition = re.compile(r'^ },? *$')
|
||||
level_definition = re.compile(r'\.lvl = (\d+)')
|
||||
species_definition = re.compile(r'\.species = SPECIES_(\w+)')
|
||||
gender_definition = re.compile(r'\.gender = TRAINER_MON_(\w+)')
|
||||
nickname_definition = re.compile(r'\.nickname = COMPOUND_STRING\("([^"]+)"\)')
|
||||
item_definition = re.compile(r'\.heldItem = ITEM_(\w+)')
|
||||
ball_definition = re.compile(r'\.ball = ITEM_(\w+)')
|
||||
ability_definition = re.compile(r'\.ability = ABILITY_(\w+)')
|
||||
friendship_definition = re.compile(r'\.friendship = (\d+)')
|
||||
shiny_definition = re.compile(r'\.isShiny = (\w+)')
|
||||
ivs_definition = re.compile(r'\.iv = TRAINER_PARTY_IVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
|
||||
evs_definition = re.compile(r'\.ev = TRAINER_PARTY_EVS\(([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+),([0-9 ]+)\)')
|
||||
moves_definition = re.compile(r'\.moves = \{([^}]+)\}')
|
||||
move_definition = re.compile(r'MOVE_(\w+)')
|
||||
nature_definition = re.compile(r'NATURE_(\w+)')
|
||||
|
||||
is_trainer_skip = re.compile(r'(const struct Trainer gTrainers\[\] = \{)|(^ \{$)|(\.partySize =)|(\.party = NULL)|(\.mugshotEnabled = TRUE)|(\};)')
|
||||
|
||||
trainer_normal_definition = re.compile(r' \[DIFFICULTY_NORMAL\]\[(TRAINER_\w+)\] =')
|
||||
trainer_easy_definition = re.compile(r' \[DIFFICULTY_EASY\]\[(TRAINER_\w+)\] =')
|
||||
trainer_hard_definition = re.compile(r' \[DIFFICULTY_HARD\]\[(TRAINER_\w+)\] =')
|
||||
end_pokemon_definition = re.compile(r' },')
|
||||
trainer_class_definition = re.compile(r'\.trainerClass = TRAINER_CLASS_(\w+)')
|
||||
encounter_music_gender_definition = re.compile(r'\.encounterMusic_gender = (F_TRAINER_FEMALE \| )?TRAINER_ENCOUNTER_MUSIC_(\w+)')
|
||||
encounter_music_definition = re.compile(r'TRAINER_ENCOUNTER_MUSIC_(\w+)')
|
||||
trainer_pic_definition = re.compile(r'\.trainerPic = TRAINER_PIC_(\w+)')
|
||||
trainer_name_definition = re.compile(r'\.trainerName = _\("([^"]*)"\)')
|
||||
trainer_items_definition = re.compile(r'\.items = \{([^}]*)\}')
|
||||
trainer_item_definition = re.compile(r'ITEM_(\w+)')
|
||||
trainer_double_battle_definition = re.compile(r'\.battleType = (\w+)')
|
||||
trainer_ai_flags_definition = re.compile(r'\.aiFlags = (.*)')
|
||||
trainer_ai_flag_definition = re.compile(r'AI_FLAG_(\w+)')
|
||||
trainer_party_definition = re.compile(r'\.party = ')
|
||||
trainer_mugshot_definition = re.compile(r'\.mugshotColor = MUGSHOT_COLOR_(\w+)')
|
||||
trainer_starting_status_definition = re.compile(r'\.startingStatus = STARTING_STATUS_(\w+)')
|
||||
|
||||
# NOTE: These are just for aesthetics, the Pokemon would still compile
|
||||
# without them.
|
||||
species_replacements = {
|
||||
"CHIEN_PAO": "Chien-Pao",
|
||||
"CHI_YU": "Chi-Yu",
|
||||
"HAKAMO_O": "Hakamo-o",
|
||||
"HO_OH": "Ho-Oh",
|
||||
"JANGMO_O": "Jangmo-o",
|
||||
"KOMMO_O": "Kommo-o",
|
||||
"PORYGON_Z": "Porygon-Z",
|
||||
"ROTOM_": "Rotom-",
|
||||
"TING_LU": "Ting-Lu",
|
||||
"TYPE_NULL": "Type: Null",
|
||||
"WO_CHIEN": "Wo-Chien",
|
||||
|
||||
"_ALOLAN": "-Alola",
|
||||
"_AQUA_BREED": "-Aqua",
|
||||
"_BATTLE_BOND": "-Bond",
|
||||
"_BLAZE_BREED": "-Blaze",
|
||||
"_CAP": "",
|
||||
"_CLOAK": "",
|
||||
"_COMBAT_BREED": "-Combat",
|
||||
"_CROWED_SHIELD": "-Crowned",
|
||||
"_CROWED_SWORD": "-Crowned",
|
||||
"_DRIVE": "",
|
||||
"_EAST_SEA": "-East",
|
||||
"_FAMILY_OF_FOUR": "-Four",
|
||||
"_FEMALE": "-F",
|
||||
"_FLOWER": "",
|
||||
"_GALARIAN": "-Galar",
|
||||
"_GIGANTAMAX": "-Gmax",
|
||||
"_HISUIAN": "-Hisui",
|
||||
"_ICE_RIDER": "-Ice",
|
||||
"_NOICE_FACE": "-Noice",
|
||||
"_ORIGIN": "-Origin",
|
||||
"_ORIGINAL_COLOR": "-Original",
|
||||
"_PALDEAN": "-Paldea",
|
||||
"_PLUMAGE": "",
|
||||
"_POKE_BALL": "-Pokeball",
|
||||
"_SHADOW_RIDER": "-Shadow",
|
||||
"_STRIKE_STYLE": "-Style",
|
||||
"_TOTEM": "-Totem",
|
||||
"_ZEN_MODE": "-Zen",
|
||||
}
|
||||
|
||||
class_fixups = {
|
||||
"Rs": "RS",
|
||||
}
|
||||
|
||||
pic_fixups = {
|
||||
"Rs": "RS",
|
||||
}
|
||||
|
||||
pokemon_attribute_order = ['Level', 'Ability', 'IVs', 'EVs', 'Happiness', 'Shiny', 'Ball']
|
||||
|
||||
class Pokemon:
|
||||
def __init__(self):
|
||||
self.nickname = None
|
||||
self.species = None
|
||||
self.gender = None
|
||||
self.item = None
|
||||
self.nature = None
|
||||
self.attributes = {}
|
||||
self.attributes['IVs'] = "0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe"
|
||||
self.moves = []
|
||||
|
||||
|
||||
class Trainer:
|
||||
def __init__(self, id_):
|
||||
self.id = id_
|
||||
self.class_ = None
|
||||
self.encounter_music = None
|
||||
self.gender = None
|
||||
self.pic = None
|
||||
self.name = None
|
||||
self.items = []
|
||||
self.double_battle = None
|
||||
self.ai_flags = None
|
||||
self.mugshot = None
|
||||
self.starting_status = None
|
||||
self.party = None
|
||||
self.difficulty = None
|
||||
|
||||
|
||||
def write_tutorial(output):
|
||||
output.write('/*\n')
|
||||
output.write('Trainers and their parties defined with Competetive Syntax.\n')
|
||||
output.write('Compatible with Pokemon Showdown exports.\n')
|
||||
output.write('https://github.com/smogon/pokemon-showdown/blob/master/sim/TEAMS.md\n')
|
||||
output.write('\n')
|
||||
output.write('A trainer specification starts with "=== TRAINER_XXXX ==="\n')
|
||||
output.write('and includes everything until the next line that starts with "==="\n')
|
||||
output.write('or the file ends.\n')
|
||||
output.write('\n')
|
||||
output.write('A blank line is required between the trainer and their Pokemon\n')
|
||||
output.write('and between their Pokemon.\n')
|
||||
output.write('TRAINER_XXXX is how the trainer is referred to within code.\n')
|
||||
output.write('Fields with description and/or example of usage\n')
|
||||
output.write('Required fields for trainers:\n')
|
||||
output.write(' - Name\n')
|
||||
output.write(' - Pic\n')
|
||||
output.write('Optional (but still recommended) fields for trainers:\n')
|
||||
output.write(' - Class (if not specified, PkMn Trainer will be used)\n')
|
||||
output.write(' - Gender (Male/Female, affects random gender weights of party if not specified)\n')
|
||||
output.write(' - Music\n')
|
||||
output.write(' - Items (Some Item / Another Item / Third Item)\n')
|
||||
output.write(' (Can also be specified with ITEM_SOME_ITEM)\n')
|
||||
output.write(' - Battle Type (Singles / Doubles, defaults to Singles)\n')
|
||||
output.write(' - AI (Ai Flag / Another Flag / Third Flag / ...\n')
|
||||
output.write(' see "constants/battle_ai.h" for all flags)\n')
|
||||
output.write(' - Mugshot (enable Mugshots during battle transition\n')
|
||||
output.write(' set to one of Purple, Green, Pink, Blue or Yellow)\n')
|
||||
output.write(' - Starting Status (see include/constants/battle.h for values)\n')
|
||||
output.write('\n')
|
||||
output.write('Pokemon are then specified using the Showdown Export format.\n')
|
||||
output.write("If a field is not specified, it will use it's default value.\n")
|
||||
output.write("\n")
|
||||
output.write('Required fields for Pokemon:\n')
|
||||
output.write(' - Species (Either as SPECIES_ABRA or Abra)\n')
|
||||
output.write(' This line also specifies Gender, Nickname and Held item.\n')
|
||||
output.write(' Alfred (Abra) (M) @ Eviolite\n')
|
||||
output.write(' Roberta (SPECIES_ABRA) (F) @ ITEM_CHOICE_SPECS\n')
|
||||
output.write(' Both lines are valid. Gender (M) or (F) must use a capital letter.\n')
|
||||
output.write(' Nickname length is limited to 10 characters using standard letters.\n')
|
||||
output.write(" With narrow font it's increased to 12. Longer strings will be silently shortened.\n")
|
||||
output.write('\n')
|
||||
output.write('Optional fields for Pokemon:\n')
|
||||
output.write(' - Level (Number between 1 and 100, defaults to 100)\n')
|
||||
output.write(' - Ability (Ability Name or ABILITY_ABILITY_NAME)\n')
|
||||
output.write(' - IVs (0 HP / 1 Atk / 2 Def / 3 SpA / 4 SpD / 5 Spe, defaults to all 31)\n')
|
||||
output.write(' (Order does not matter)\n')
|
||||
output.write(' - EVs (252 HP / 128 Spe / 48 Def, defaults to all 0, is not capped at 512 total)\n')
|
||||
output.write(' (Order does not matter)\n')
|
||||
output.write(' - Ball (Poke Ball or ITEM_POKE_BALL, defaults to Poke Ball)\n')
|
||||
output.write(' - Happiness (Number between 1 and 255)\n')
|
||||
output.write(' - Nature (Rash or NATURE_RASH, defaults to Hardy)\n')
|
||||
output.write(' - Shiny (Yes/No, defaults to No)\n')
|
||||
output.write(' - Dynamax Level (Number between 0 and 10, default 10, also sets "shouldDynamax" to True)\n')
|
||||
output.write(' - Gigantamax (Yes/No, sets to Gigantamax factor)\n')
|
||||
output.write(' (doesn\'t do anything to Pokemon without a Gigantamax form, also sets "shouldDynamax" to True)\n')
|
||||
output.write(' - Tera Type (Set to a Type, either Fire or TYPE_FIRE, also sets "shouldTerastal" to True)\n')
|
||||
output.write('Moves are defined with a - (dash) followed by a single space, then the move name.\n')
|
||||
output.write('Either "- Tackle" or "- MOVE_TACKLE" works. One move per line.\n')
|
||||
output.write('Moves have to be the last lines of a Pokemon.\n')
|
||||
output.write('If no moves are specified, the Pokemon will use the last 4 moves it learns\n')
|
||||
output.write('through levelup at its level.\n')
|
||||
output.write("\n")
|
||||
output.write('Default IVs and Level can be changed in the "main" function of tools/trainerproc/main.c\n')
|
||||
output.write("\n")
|
||||
output.write('This file is processed with a custom preprocessor.\n')
|
||||
output.write('*/\n')
|
||||
output.write("\n")
|
||||
output.write('/*\n')
|
||||
output.write('Comments can be added as C comment blocks\n')
|
||||
output.write('// cannot be used as comments\n')
|
||||
output.write('*/\n')
|
||||
output.write("\n")
|
||||
output.write('/*Comments can also be on a single line*/\n')
|
||||
output.write("\n")
|
||||
output.write("\n")
|
||||
|
||||
|
||||
|
||||
def write_to_file(trainer, output):
|
||||
output.write(f'=== {trainer.id} ===\n')
|
||||
output.write(f'Name: {trainer.name}\n')
|
||||
output.write(f'Class: {trainer.class_}\n')
|
||||
output.write(f'Pic: {trainer.pic}\n')
|
||||
output.write(f'Gender: {trainer.gender}\n')
|
||||
output.write(f'Music: {trainer.encounter_music}\n')
|
||||
if len(trainer.items) > 0:
|
||||
output.write(f'Items: {trainer.items}\n')
|
||||
output.write(f'Battle Type: {trainer.double_battle}\n')
|
||||
if trainer.ai_flags is not None:
|
||||
output.write(f'AI: {trainer.ai_flags}\n')
|
||||
if trainer.mugshot:
|
||||
output.write(f'Mugshot: {trainer.mugshot}\n')
|
||||
if trainer.difficulty is not None:
|
||||
output.write(f'Difficulty: {trainer.difficulty}\n')
|
||||
|
||||
output.write(f'\n')
|
||||
|
||||
for pokemon in trainer.party:
|
||||
if pokemon.species is None:
|
||||
continue
|
||||
if pokemon.item is not None:
|
||||
output.write(f'{pokemon.species} @ {pokemon.item}\n')
|
||||
else:
|
||||
output.write(f'{pokemon.species}\n')
|
||||
# for key in pokemon.attributes:
|
||||
for key in pokemon_attribute_order:
|
||||
if key in pokemon.attributes:
|
||||
output.write(f'{key}: {pokemon.attributes[key]}\n')
|
||||
if pokemon.nature:
|
||||
output.write(f'Nature: {pokemon.nature}\n')
|
||||
for move in pokemon.moves:
|
||||
output.write(f'- {move}\n')
|
||||
output.write(f'\n')
|
||||
|
||||
|
||||
def parse_trainers(content, output):
|
||||
newlines = 0
|
||||
trainer = None
|
||||
pokemon = None
|
||||
party = []
|
||||
moves = []
|
||||
|
||||
write_tutorial(output)
|
||||
|
||||
for line_no, line in enumerate(content, 1):
|
||||
try:
|
||||
line = line[:-1]
|
||||
|
||||
# Trainer defition
|
||||
if m := trainer_normal_definition.search(line):
|
||||
if trainer is not None:
|
||||
trainer.party = party
|
||||
write_to_file(trainer, output)
|
||||
trainer = None
|
||||
party = []
|
||||
[id_] = m.groups()
|
||||
trainer = Trainer(id_)
|
||||
trainer.difficulty = None
|
||||
trainer.gender = 'Male'
|
||||
elif m := trainer_easy_definition.search(line):
|
||||
if trainer is not None:
|
||||
trainer.party = party
|
||||
write_to_file(trainer, output)
|
||||
trainer = None
|
||||
party = []
|
||||
[id_] = m.groups()
|
||||
trainer = Trainer(id_)
|
||||
trainer.difficulty = "Easy"
|
||||
trainer.gender = 'Male'
|
||||
elif m := trainer_hard_definition.search(line):
|
||||
if trainer is not None:
|
||||
trainer.party = party
|
||||
write_to_file(trainer, output)
|
||||
trainer = None
|
||||
party = []
|
||||
[id_] = m.groups()
|
||||
trainer = Trainer(id_)
|
||||
trainer.difficulty = "Hard"
|
||||
trainer.gender = 'Male'
|
||||
elif m := trainer_class_definition.search(line):
|
||||
[class_] = m.groups()
|
||||
class_ = class_.replace("_", " ").title()
|
||||
for match, replacement in class_fixups.items():
|
||||
class_ = class_.replace(match, replacement)
|
||||
trainer.class_ = class_
|
||||
elif m := encounter_music_gender_definition.search(line):
|
||||
[is_female, music] = m.groups()
|
||||
trainer.gender = 'Female' if is_female else 'Male'
|
||||
trainer.encounter_music = music.replace("_", " ").title()
|
||||
elif m := encounter_music_definition.search(line):
|
||||
[music] = m.groups()
|
||||
trainer.encounter_music = music.replace("_", " ").title()
|
||||
elif "F_TRAINER_FEMALE" in line:
|
||||
trainer.gender = 'Female'
|
||||
elif m := trainer_pic_definition.search(line):
|
||||
[pic] = m.groups()
|
||||
pic = pic.replace("_", " ").title()
|
||||
for match, replacement in pic_fixups.items():
|
||||
pic = pic.replace(match, replacement)
|
||||
trainer.pic = pic
|
||||
elif m := trainer_name_definition.search(line):
|
||||
[name] = m.groups()
|
||||
trainer.name = name
|
||||
elif m := trainer_items_definition.search(line):
|
||||
[items] = m.groups()
|
||||
trainer.items = " / ".join(item.replace("_", " ").title() for item in trainer_item_definition.findall(items) if item != "NONE")
|
||||
elif m := trainer_double_battle_definition.search(line):
|
||||
[double_battle] = m.groups()
|
||||
if double_battle == 'TRAINER_BATTLE_TYPE_DOUBLES':
|
||||
trainer.double_battle = "Doubles"
|
||||
elif double_battle == 'TRAINER_BATTLE_TYPE_SINGLES':
|
||||
trainer.double_battle = "Singles"
|
||||
elif m := trainer_ai_flags_definition.search(line):
|
||||
[ai_flags] = m.groups()
|
||||
trainer.ai_flags = " / ".join(ai_flag.replace("_", " ").title() for ai_flag in trainer_ai_flag_definition.findall(ai_flags))
|
||||
elif m := trainer_mugshot_definition.search(line):
|
||||
[color] = m.groups()
|
||||
trainer.mugshot = color.title()
|
||||
elif m := trainer_starting_status_definition.search(line):
|
||||
[starting_status] = m.groups()
|
||||
trainer.starting_status = starting_status.replace("_", " ").title()
|
||||
elif m := trainer_party_definition.search(line):
|
||||
pokemon = Pokemon()
|
||||
|
||||
# Party mons
|
||||
elif end_pokemon_definition.search(line):
|
||||
party.append(pokemon)
|
||||
pokemon = Pokemon()
|
||||
elif m := level_definition.search(line):
|
||||
[level] = m.groups()
|
||||
pokemon.attributes['Level'] = level
|
||||
elif m := species_definition.search(line):
|
||||
[species_] = m.groups()
|
||||
for match, replacement in species_replacements.items():
|
||||
species_ = species_.replace(match, replacement)
|
||||
pokemon.species = species_.replace("_", " ").title()
|
||||
elif m := gender_definition.search(line):
|
||||
[gender_] = m.groups()
|
||||
if gender_ == 'MALE':
|
||||
pokemon.gender = 'M'
|
||||
elif gender_ == 'FEMALE':
|
||||
pokemon.gender = 'F'
|
||||
elif m := nickname_definition.search(line):
|
||||
[nickname] = m.groups()
|
||||
pokemon.nickname = nickname
|
||||
elif m := item_definition.search(line):
|
||||
[item_] = m.groups()
|
||||
pokemon.item = item_.replace("_", " ").title()
|
||||
elif m := ball_definition.search(line):
|
||||
[ball] = m.groups()
|
||||
pokemon.attributes['Ball'] = ball.replace("_", " ").title()
|
||||
elif m := ability_definition.search(line):
|
||||
[ability] = m.groups()
|
||||
pokemon.attributes['Ability'] = ability.replace("_", " ").title()
|
||||
elif m := friendship_definition.search(line):
|
||||
[friendship] = m.groups()
|
||||
pokemon.attributes['Happiness'] = friendship
|
||||
elif m := shiny_definition.search(line):
|
||||
[shiny] = m.groups()
|
||||
if shiny == 'TRUE':
|
||||
pokemon.attributes['Shiny'] = 'Yes'
|
||||
elif shiny == 'FALSE':
|
||||
pokemon.attributes['Shiny'] = 'No'
|
||||
elif m := ivs_definition.search(line):
|
||||
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
|
||||
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
|
||||
pokemon.attributes['IVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items())
|
||||
elif m := evs_definition.search(line):
|
||||
[hp, attack, defense, speed, special_attack, special_defense] = [stat.strip() for stat in m.groups()]
|
||||
stats = {"HP": hp, "Atk": attack, "Def": defense, "SpA": special_attack, "SpD": special_defense, "Spe": speed}
|
||||
pokemon.attributes['EVs'] = ' / '.join(f"{value} {key}" for key, value in stats.items() if value != '0')
|
||||
elif m := move_definition.search(line):
|
||||
[move] = m.groups()
|
||||
pokemon.moves.append(move.replace("_", " ").title())
|
||||
elif m := nature_definition.search(line):
|
||||
[nature] = m.groups()
|
||||
pokemon.nature = nature.replace("_", " ").title()
|
||||
|
||||
except Exception as e:
|
||||
print(f"{line_no}: {e}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
[argv0, trainers_in_path, out_path] = sys.argv
|
||||
except:
|
||||
print(f"usage: python3 {sys.argv[0]} <trainers.h> <out>")
|
||||
print("trainers.h path: src/data/trainers.h")
|
||||
print("trainers.party output path: src/data/trainers.party")
|
||||
else:
|
||||
with open(trainers_in_path, "r") as source, open(out_path, 'w') as output:
|
||||
parse_trainers(source, output)
|
||||
@ -1518,7 +1518,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
|
||||
return bestMonId;
|
||||
}
|
||||
|
||||
static u32 GetFirstNonIvalidMon(u32 firstId, u32 lastId, u32 invalidMons, u32 battlerIn1, u32 battlerIn2)
|
||||
static u32 GetFirstNonInvalidMon(u32 firstId, u32 lastId, u32 invalidMons, u32 battlerIn1, u32 battlerIn2)
|
||||
{
|
||||
if (!IsDoubleBattle())
|
||||
return PARTY_SIZE;
|
||||
@ -2301,7 +2301,7 @@ static u32 GetBestMonIntegrated(struct Pokemon *party, int firstId, int lastId,
|
||||
return aceMonId;
|
||||
|
||||
// Fallback
|
||||
u32 bestMonId = GetFirstNonIvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2);
|
||||
u32 bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2);
|
||||
if (bestMonId != PARTY_SIZE)
|
||||
return bestMonId;
|
||||
|
||||
@ -2423,7 +2423,7 @@ u32 GetMostSuitableMonToSwitchInto(u32 battler, enum SwitchType switchType)
|
||||
return aceMonId;
|
||||
|
||||
// Fallback
|
||||
bestMonId = GetFirstNonIvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2);
|
||||
bestMonId = GetFirstNonInvalidMon(firstId, lastId, invalidMons, battlerIn1, battlerIn2);
|
||||
if (bestMonId != PARTY_SIZE)
|
||||
return bestMonId;
|
||||
|
||||
|
||||
@ -545,7 +545,7 @@ bool32 IsTruantMonVulnerable(u32 battlerAI, u32 opposingBattler)
|
||||
bool32 IsAffectedByPowder(u32 battler, enum Ability ability, enum ItemHoldEffect holdEffect)
|
||||
{
|
||||
if (ability == ABILITY_OVERCOAT
|
||||
|| (B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS))
|
||||
|| (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6 && IS_BATTLER_OF_TYPE(battler, TYPE_GRASS))
|
||||
|| holdEffect == HOLD_EFFECT_SAFETY_GOGGLES)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
@ -1700,7 +1700,10 @@ enum Ability AI_DecideKnownAbilityForTurn(u32 battlerId)
|
||||
|
||||
enum ItemHoldEffect AI_DecideHoldEffectForTurn(u32 battlerId)
|
||||
{
|
||||
enum ItemHoldEffect holdEffect;
|
||||
enum ItemHoldEffect holdEffect = HOLD_EFFECT_NONE;
|
||||
|
||||
if (gBattleMons[battlerId].item == ITEM_NONE) // Failsafe for when user recorded an item but it was consumed
|
||||
return holdEffect;
|
||||
|
||||
if (!IsAiBattlerAware(battlerId))
|
||||
holdEffect = gAiPartyData->mons[GetBattlerSide(battlerId)][gBattlerPartyIndexes[battlerId]].heldEffect;
|
||||
|
||||
@ -567,12 +567,14 @@ static void OpponentHandleChoosePokemon(u32 battler)
|
||||
}
|
||||
}
|
||||
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
|
||||
GetBattlerPartyState(battler)->sentOut = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
chosenMonId = gBattleStruct->AI_monToSwitchIntoId[battler];
|
||||
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
|
||||
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
|
||||
GetBattlerPartyState(battler)->sentOut = TRUE;
|
||||
}
|
||||
#if TESTING
|
||||
TestRunner_Battle_CheckSwitch(battler, chosenMonId);
|
||||
|
||||
@ -285,7 +285,6 @@ static void PlayerPartnerHandleChoosePokemon(u32 battler)
|
||||
else if (gBattleStruct->monToSwitchIntoId[battler] >= PARTY_SIZE || !IsValidForBattle(&gPlayerParty[gBattleStruct->monToSwitchIntoId[battler]]))
|
||||
{
|
||||
chosenMonId = GetMostSuitableMonToSwitchInto(battler, SWITCH_AFTER_KO);
|
||||
|
||||
if (chosenMonId == PARTY_SIZE || !IsValidForBattle(&gPlayerParty[chosenMonId])) // just switch to the next mon
|
||||
{
|
||||
s32 firstId = (IsAiVsAiBattle()) ? 0 : (PARTY_SIZE / 2);
|
||||
@ -303,12 +302,14 @@ static void PlayerPartnerHandleChoosePokemon(u32 battler)
|
||||
}
|
||||
}
|
||||
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
|
||||
GetBattlerPartyState(battler)->sentOut = TRUE;
|
||||
}
|
||||
else // Mon to switch out has been already chosen.
|
||||
{
|
||||
chosenMonId = gBattleStruct->monToSwitchIntoId[battler];
|
||||
gBattleStruct->AI_monToSwitchIntoId[battler] = PARTY_SIZE;
|
||||
gBattleStruct->monToSwitchIntoId[battler] = chosenMonId;
|
||||
GetBattlerPartyState(battler)->sentOut = TRUE;
|
||||
}
|
||||
BtlController_EmitChosenMonReturnValue(battler, B_COMM_TO_ENGINE, chosenMonId, NULL);
|
||||
BtlController_Complete(battler);
|
||||
|
||||
@ -61,8 +61,8 @@ enum EndTurnResolutionOrder
|
||||
ENDTURN_TERRAIN,
|
||||
ENDTURN_THIRD_EVENT_BLOCK,
|
||||
ENDTURN_EMERGENCY_EXIT_4,
|
||||
ENDTURN_ABILITIES,
|
||||
ENDTURN_FOURTH_EVENT_BLOCK,
|
||||
ENDTURN_FORM_CHANGE_ABILITIES,
|
||||
ENDTURN_EJECT_PACK,
|
||||
ENDTURN_DYNAMAX,
|
||||
ENDTURN_COUNT,
|
||||
};
|
||||
@ -101,13 +101,6 @@ enum ThirdEventBlock
|
||||
THIRD_EVENT_BLOCK_ITEMS,
|
||||
};
|
||||
|
||||
// Form changing abilities and Eject Pack
|
||||
enum FourthEventBlock
|
||||
{
|
||||
FOURTH_EVENT_BLOCK_HUNGER_SWITCH,
|
||||
FOURTH_EVENT_BLOCK_EJECT_PACK,
|
||||
};
|
||||
|
||||
static u32 GetBattlerSideForMessage(u32 side)
|
||||
{
|
||||
u32 battler = 0;
|
||||
@ -1456,7 +1449,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
|
||||
return effect;
|
||||
}
|
||||
|
||||
static bool32 HandleEndTurnAbilities(u32 battler)
|
||||
static bool32 HandleEndTurnFormChangeAbilities(u32 battler)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
|
||||
@ -1470,6 +1463,7 @@ static bool32 HandleEndTurnAbilities(u32 battler)
|
||||
case ABILITY_SCHOOLING:
|
||||
case ABILITY_SHIELDS_DOWN:
|
||||
case ABILITY_ZEN_MODE:
|
||||
case ABILITY_HUNGER_SWITCH:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE))
|
||||
effect = TRUE;
|
||||
default:
|
||||
@ -1479,38 +1473,10 @@ static bool32 HandleEndTurnAbilities(u32 battler)
|
||||
return effect;
|
||||
}
|
||||
|
||||
static bool32 HandleEndTurnFourthEventBlock(u32 battler)
|
||||
static bool32 HandleEndTurnEjectPack(u32 battler)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
|
||||
switch (gBattleStruct->eventBlockCounter)
|
||||
{
|
||||
case FOURTH_EVENT_BLOCK_HUNGER_SWITCH:
|
||||
{
|
||||
enum Ability ability = GetBattlerAbility(battler);
|
||||
if (ability == ABILITY_HUNGER_SWITCH)
|
||||
{
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, battler, ability, 0, MOVE_NONE))
|
||||
effect = TRUE;
|
||||
}
|
||||
gBattleStruct->eventBlockCounter++;
|
||||
break;
|
||||
}
|
||||
case FOURTH_EVENT_BLOCK_EJECT_PACK:
|
||||
{
|
||||
enum ItemHoldEffect holdEffect = GetBattlerHoldEffect(battler);
|
||||
if (holdEffect == HOLD_EFFECT_EJECT_PACK)
|
||||
{
|
||||
if (ItemBattleEffects(ITEMEFFECT_NORMAL, battler))
|
||||
effect = TRUE;
|
||||
}
|
||||
gBattleStruct->eventBlockCounter = 0;
|
||||
gBattleStruct->turnEffectsBattlerId++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return effect;
|
||||
gBattleStruct->turnEffectsBattlerId++;
|
||||
return TrySwitchInEjectPack(ITEMEFFECT_NORMAL);
|
||||
}
|
||||
|
||||
static bool32 HandleEndTurnDynamax(u32 battler)
|
||||
@ -1590,8 +1556,8 @@ static bool32 (*const sEndTurnEffectHandlers[])(u32 battler) =
|
||||
[ENDTURN_TERRAIN] = HandleEndTurnTerrain,
|
||||
[ENDTURN_THIRD_EVENT_BLOCK] = HandleEndTurnThirdEventBlock,
|
||||
[ENDTURN_EMERGENCY_EXIT_4] = HandleEndTurnEmergencyExit,
|
||||
[ENDTURN_ABILITIES] = HandleEndTurnAbilities,
|
||||
[ENDTURN_FOURTH_EVENT_BLOCK] = HandleEndTurnFourthEventBlock,
|
||||
[ENDTURN_FORM_CHANGE_ABILITIES] = HandleEndTurnFormChangeAbilities,
|
||||
[ENDTURN_EJECT_PACK] = HandleEndTurnEjectPack,
|
||||
[ENDTURN_DYNAMAX] = HandleEndTurnDynamax,
|
||||
};
|
||||
|
||||
|
||||
@ -3735,6 +3735,10 @@ static void DoBattleIntro(void)
|
||||
gBattleStruct->overworldWeatherDone = FALSE;
|
||||
Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield.
|
||||
|
||||
// mark all battlers as sent out
|
||||
for (battler = 0; battler < gBattlersCount; battler++)
|
||||
GetBattlerPartyState(battler)->sentOut = TRUE;
|
||||
|
||||
// Try to set a status to start the battle with
|
||||
gBattleStruct->startingStatus = 0;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetTrainerStartingStatusFromId(TRAINER_BATTLE_PARAM.opponentB))
|
||||
@ -3856,6 +3860,8 @@ static void TryDoEventsBeforeFirstTurn(void)
|
||||
i = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS_FIRST_TURN, i, gBattleMons[i].ability, 0, 0) != 0)
|
||||
return;
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES, i, 0, 0, 0) != 0)
|
||||
return;
|
||||
}
|
||||
gBattleStruct->switchInBattlerCounter = 0;
|
||||
gBattleStruct->eventsBeforeFirstTurnState++;
|
||||
@ -5163,6 +5169,7 @@ static void TurnValuesCleanUp(bool8 var0)
|
||||
gSpecialStatuses[i].parentalBondState = PARENTAL_BOND_OFF;
|
||||
gBattleStruct->battlerState[i].usedEjectItem = FALSE;
|
||||
gProtectStructs[i].lashOutAffected = FALSE;
|
||||
gDisableStructs[i].endured = FALSE;
|
||||
}
|
||||
|
||||
gSideTimers[B_SIDE_PLAYER].followmeTimer = 0;
|
||||
@ -5587,14 +5594,31 @@ static void HandleEndTurn_FinishBattle(void)
|
||||
GetMonData(GetBattlerMon(battler), MON_DATA_NICKNAME, gBattleResults.playerMon2Name);
|
||||
}
|
||||
}
|
||||
else if (!IsOnPlayerSide(battler))
|
||||
{
|
||||
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality);
|
||||
}
|
||||
}
|
||||
TryPutPokemonTodayOnAir();
|
||||
}
|
||||
|
||||
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| BATTLE_TYPE_TRAINER_HILL
|
||||
| BATTLE_TYPE_FRONTIER)))
|
||||
{
|
||||
for (u32 side = 0; side < NUM_BATTLE_SIDES; side++)
|
||||
{
|
||||
struct Pokemon *party = GetSideParty(side);
|
||||
|
||||
if (side == B_SIDE_PLAYER && !B_PARTNER_MONS_MARKED_SEEN)
|
||||
continue;
|
||||
|
||||
for (u32 partySlot = 0; partySlot < PARTY_SIZE; partySlot++)
|
||||
{
|
||||
if (gBattleStruct->partyState[side][partySlot].sentOut)
|
||||
HandleSetPokedexFlagFromMon(&party[partySlot], FLAG_SET_SEEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| BATTLE_TYPE_TRAINER
|
||||
@ -5720,20 +5744,24 @@ static void TryEvolvePokemon(void)
|
||||
if (!(sTriedEvolving & (1u << i)))
|
||||
{
|
||||
bool32 canStopEvo = TRUE;
|
||||
u32 species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_SPECIAL, i, NULL, &canStopEvo, CHECK_EVO);
|
||||
enum EvolutionMode mode = EVO_MODE_BATTLE_SPECIAL;
|
||||
u32 evolutionItemArg = i;
|
||||
u32 species = GetEvolutionTargetSpecies(&gPlayerParty[i], mode, evolutionItemArg, NULL, &canStopEvo, CHECK_EVO);
|
||||
sTriedEvolving |= 1u << i;
|
||||
|
||||
if (species == SPECIES_NONE && (gLeveledUpInBattle & (1u << i)))
|
||||
{
|
||||
gLeveledUpInBattle &= ~(1u << i);
|
||||
species = GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_ONLY, gLeveledUpInBattle, NULL, &canStopEvo, CHECK_EVO);
|
||||
mode = EVO_MODE_BATTLE_ONLY;
|
||||
evolutionItemArg = gLeveledUpInBattle;
|
||||
species = GetEvolutionTargetSpecies(&gPlayerParty[i], mode, evolutionItemArg, NULL, &canStopEvo, CHECK_EVO);
|
||||
}
|
||||
|
||||
if (species != SPECIES_NONE)
|
||||
{
|
||||
FreeAllWindowBuffers();
|
||||
gBattleMainFunc = WaitForEvoSceneToFinish;
|
||||
GetEvolutionTargetSpecies(&gPlayerParty[i], EVO_MODE_BATTLE_ONLY, gLeveledUpInBattle, NULL, &canStopEvo, DO_EVO);
|
||||
GetEvolutionTargetSpecies(&gPlayerParty[i], mode, evolutionItemArg, NULL, &canStopEvo, DO_EVO);
|
||||
EvolutionScene(&gPlayerParty[i], species, canStopEvo, i);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -862,7 +862,7 @@ static bool8 DoesTypePreventStatus(u16 species, u32 status)
|
||||
break;
|
||||
case STATUS1_PARALYSIS:
|
||||
if (GetSpeciesType(species, 0) == TYPE_GROUND || GetSpeciesType(species, 1) == TYPE_GROUND
|
||||
|| (B_PARALYZE_ELECTRIC >= GEN_6 && (GetSpeciesType(species, 0) == TYPE_ELECTRIC || GetSpeciesType(species, 1) == TYPE_ELECTRIC)))
|
||||
|| (GetGenConfig(GEN_CONFIG_PARALYZE_ELECTRIC) >= GEN_6 && (GetSpeciesType(species, 0) == TYPE_ELECTRIC || GetSpeciesType(species, 1) == TYPE_ELECTRIC)))
|
||||
ret = TRUE;
|
||||
break;
|
||||
case STATUS1_BURN:
|
||||
|
||||
@ -966,19 +966,17 @@ static void ValidateSavedBattlerCounts(void)
|
||||
{
|
||||
if (gBattleStruct->savedAttackerCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
// #endif
|
||||
if (TESTING)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!", __FILE__, __LINE__);
|
||||
else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedAttackerCount is greater than 0! More calls to SaveBattlerAttacker than RestoreBattlerAttacker!");
|
||||
}
|
||||
if (gBattleStruct->savedTargetCount > 0)
|
||||
{
|
||||
// #if TESTING
|
||||
// Test_ExitWithResult(TEST_RESULT_ERROR, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
// #endif
|
||||
if (TESTING)
|
||||
Test_ExitWithResult(TEST_RESULT_ERROR, 0, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!", __FILE__, __LINE__);
|
||||
else
|
||||
DebugPrintfLevel(MGBA_LOG_WARN, "savedTargetCount is greater than 0! More calls to SaveBattlerTarget than RestoreBattlerTarget!");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1066,7 +1064,7 @@ bool32 IsMovePowderBlocked(struct BattleContext *ctx)
|
||||
|
||||
if (IsPowderMove(ctx->currentMove) && (ctx->battlerAtk != ctx->battlerDef))
|
||||
{
|
||||
if (B_POWDER_GRASS >= GEN_6
|
||||
if (GetGenConfig(GEN_CONFIG_POWDER_GRASS) >= GEN_6
|
||||
&& (IS_BATTLER_OF_TYPE(ctx->battlerDef, TYPE_GRASS) || ctx->ability[ctx->battlerDef] == ABILITY_OVERCOAT))
|
||||
{
|
||||
gBattlerAbility = ctx->battlerDef;
|
||||
@ -2809,7 +2807,8 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem)
|
||||
BtlController_EmitSetMonData(battlerItem, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item
|
||||
MarkBattlerForControllerExec(battlerItem);
|
||||
|
||||
gBattleStruct->choicedMove[battlerItem] = 0;
|
||||
if (GetBattlerAbility(gBattlerTarget) != ABILITY_GORILLA_TACTICS)
|
||||
gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE;
|
||||
|
||||
TrySaveExchangedItem(battlerItem, gLastUsedItem);
|
||||
}
|
||||
@ -5668,7 +5667,7 @@ static bool32 HandleMoveEndMoveBlock(u32 moveEffect)
|
||||
gLastUsedItem = gBattleMons[gBattlerTarget].item;
|
||||
gBattleMons[gBattlerTarget].item = 0;
|
||||
if (gBattleMons[gBattlerTarget].ability != ABILITY_GORILLA_TACTICS)
|
||||
gBattleStruct->choicedMove[gBattlerTarget] = 0;
|
||||
gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE;
|
||||
CheckSetUnburden(gBattlerTarget);
|
||||
|
||||
// In Gen 5+, Knock Off removes the target's item rather than rendering it unusable.
|
||||
@ -6084,9 +6083,12 @@ static void Cmd_moveend(void)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_STATUS_IMMUNITY_ABILITIES: // status immunities
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0))
|
||||
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
|
||||
else
|
||||
for (u16 battler = 0; battler < gBattlersCount; battler++)
|
||||
{
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, battler, 0, 0, 0))
|
||||
effect = TRUE;
|
||||
}
|
||||
if(!effect)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_SYNCHRONIZE_ATTACKER: // attacker synchronize
|
||||
@ -6455,10 +6457,30 @@ static void Cmd_moveend(void)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ITEM_EFFECTS_ATTACKER:
|
||||
// ITEMEFFECT_MOVE_END loops over all battlers, not just attacker.
|
||||
// It will executre only the first mon with an applicable item.
|
||||
// So presumably it is a bug
|
||||
if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker))
|
||||
effect = TRUE;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ITEM_THROAT_SPRAY:
|
||||
if (IsSoundMove(gCurrentMove)
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker) == HOLD_EFFECT_THROAT_SPRAY
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsAnyTargetAffected(gBattlerAttacker)
|
||||
&& CompareStat(gBattlerAttacker, STAT_SPATK, MAX_STAT_STAGE, CMP_LESS_THAN)
|
||||
&& !NoAliveMonsForEitherParty()) // Don't activate if battle will end
|
||||
{
|
||||
gLastUsedItem = gBattleMons[gBattlerAttacker].item;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
|
||||
effect = TRUE;
|
||||
BattleScriptCall(BattleScript_AttackerItemStatRaise);
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ABILITY_BLOCK:
|
||||
effect = HandleMoveEndAbilityBlock(gBattlerAttacker, gBattlerTarget, gCurrentMove);
|
||||
gBattleScripting.moveendState++;
|
||||
@ -7148,13 +7170,7 @@ static void Cmd_switchinanim(void)
|
||||
|
||||
battler = GetBattlerForBattleScript(cmd->battler);
|
||||
|
||||
if (!IsOnPlayerSide(battler)
|
||||
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| BATTLE_TYPE_TRAINER_HILL
|
||||
| BATTLE_TYPE_FRONTIER)))
|
||||
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[battler].species), FLAG_SET_SEEN, gBattleMons[battler].personality);
|
||||
GetBattlerPartyState(battler)->sentOut = TRUE;
|
||||
|
||||
gAbsentBattlerFlags &= ~(1u << battler);
|
||||
|
||||
@ -12516,7 +12532,7 @@ static void Cmd_settaunt(void)
|
||||
{
|
||||
CMD_ARGS(const u8 *failInstr);
|
||||
|
||||
if (B_OBLIVIOUS_TAUNT >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS)
|
||||
if (GetGenConfig(GEN_CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && GetBattlerAbility(gBattlerTarget) == ABILITY_OBLIVIOUS)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_NotAffectedAbilityPopUp;
|
||||
gLastUsedAbility = ABILITY_OBLIVIOUS;
|
||||
@ -12640,8 +12656,10 @@ static void Cmd_tryswapitems(void)
|
||||
BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[gBattlerTarget].item);
|
||||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
|
||||
gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE;
|
||||
gBattleStruct->choicedMove[gBattlerAttacker] = MOVE_NONE;
|
||||
if (GetBattlerAbility(gBattlerTarget) != ABILITY_GORILLA_TACTICS)
|
||||
gBattleStruct->choicedMove[gBattlerTarget] = MOVE_NONE;
|
||||
if (GetBattlerAbility(gBattlerTarget) != ABILITY_GORILLA_TACTICS)
|
||||
gBattleStruct->choicedMove[gBattlerAttacker] = MOVE_NONE;
|
||||
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
|
||||
@ -16905,6 +16923,7 @@ void BS_SwitchinAbilities(void)
|
||||
AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, battler, 0, 0, 0);
|
||||
AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, battler, 0, 0, 0);
|
||||
AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, battler, 0, 0, 0);
|
||||
AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, battler, 0, 0, 0);
|
||||
|
||||
if (gBattleWeather & B_WEATHER_ANY && HasWeatherEffect())
|
||||
AbilityBattleEffects(ABILITYEFFECT_ON_WEATHER, battler, 0, 0, 0);
|
||||
|
||||
@ -1649,8 +1649,8 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
|
||||
SetMonData(dst, MON_DATA_TERA_TYPE, &data);
|
||||
}
|
||||
|
||||
|
||||
SetMonData(dst, MON_DATA_POKEBALL, &ball);
|
||||
if (ball != BALL_STRANGE)
|
||||
SetMonData(dst, MON_DATA_POKEBALL, &ball);
|
||||
CalculateMonStats(dst);
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +66,6 @@ static u32 GetFlingPowerFromItemId(u32 itemId);
|
||||
static void SetRandomMultiHitCounter();
|
||||
static u32 GetBattlerItemHoldEffectParam(u32 battler, u32 item);
|
||||
static bool32 CanBeInfinitelyConfused(u32 battler);
|
||||
static bool32 IsAnyTargetAffected(u32 battlerAtk);
|
||||
static bool32 IsNonVolatileStatusBlocked(u32 battlerDef, enum Ability abilityDef, enum Ability abilityAffected, const u8 *battleScript, enum FunctionCallOption option);
|
||||
static bool32 CanSleepDueToSleepClause(u32 battlerAtk, u32 battlerDef, enum FunctionCallOption option);
|
||||
|
||||
@ -420,7 +419,8 @@ void HandleAction_UseMove(void)
|
||||
{
|
||||
gCurrentMove = gChosenMove = gDisableStructs[gBattlerAttacker].encoredMove;
|
||||
gCurrMovePos = gChosenMovePos = gDisableStructs[gBattlerAttacker].encoredMovePos;
|
||||
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
if (GetGenConfig(GEN_CONFIG_ENCORE_TARGET) < GEN_5)
|
||||
gBattleStruct->moveTarget[gBattlerAttacker] = GetBattleMoveTarget(gCurrentMove, NO_TARGET_OVERRIDE);
|
||||
}
|
||||
// check if the encored move wasn't overwritten
|
||||
else if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].encoredMove != MOVE_NONE
|
||||
@ -4998,7 +4998,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec
|
||||
case ABILITY_EFFECT_SPORE:
|
||||
{
|
||||
enum Ability abilityAtk = GetBattlerAbility(gBattlerAttacker);
|
||||
if ((!IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS) || B_POWDER_GRASS < GEN_6)
|
||||
if ((GetGenConfig(GEN_CONFIG_POWDER_GRASS) < GEN_6 || !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_GRASS))
|
||||
&& abilityAtk != ABILITY_OVERCOAT
|
||||
&& GetBattlerHoldEffect(gBattlerAttacker) != HOLD_EFFECT_SAFETY_GOGGLES)
|
||||
{
|
||||
@ -5386,96 +5386,12 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, enum Ability ability, u32 spec
|
||||
}
|
||||
break;
|
||||
case ABILITYEFFECT_IMMUNITY:
|
||||
for (battler = 0; battler < gBattlersCount; battler++)
|
||||
{
|
||||
switch (GetBattlerAbilityIgnoreMoldBreaker(battler))
|
||||
{
|
||||
case ABILITY_IMMUNITY:
|
||||
case ABILITY_PASTEL_VEIL:
|
||||
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER))
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_OWN_TEMPO:
|
||||
if (gBattleMons[battler].volatiles.confusionTurns > 0)
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
|
||||
effect = 2;
|
||||
}
|
||||
break;
|
||||
case ABILITY_LIMBER:
|
||||
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_INSOMNIA:
|
||||
case ABILITY_VITAL_SPIRIT:
|
||||
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
|
||||
{
|
||||
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
|
||||
gBattleMons[battler].volatiles.nightmare = FALSE;
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_WATER_VEIL:
|
||||
case ABILITY_WATER_BUBBLE:
|
||||
case ABILITY_THERMAL_EXCHANGE:
|
||||
if (gBattleMons[battler].status1 & STATUS1_BURN)
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_MAGMA_ARMOR:
|
||||
if (gBattleMons[battler].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE))
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_OBLIVIOUS:
|
||||
if (gBattleMons[battler].volatiles.infatuation)
|
||||
effect = 3;
|
||||
else if (gDisableStructs[battler].tauntTimer != 0)
|
||||
effect = 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (effect != 0)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
case 1: // status cleared
|
||||
gBattleMons[battler].status1 = 0;
|
||||
BattleScriptCall(BattleScript_AbilityCuredStatus);
|
||||
break;
|
||||
case 2: // get rid of confusion
|
||||
RemoveConfusionStatus(battler);
|
||||
BattleScriptCall(BattleScript_AbilityCuredStatus);
|
||||
break;
|
||||
case 3: // get rid of infatuation
|
||||
gBattleMons[battler].volatiles.infatuation = 0;
|
||||
BattleScriptCall(BattleScript_BattlerGotOverItsInfatuation);
|
||||
break;
|
||||
case 4: // get rid of taunt
|
||||
gDisableStructs[battler].tauntTimer = 0;
|
||||
BattleScriptCall(BattleScript_BattlerShookOffTaunt);
|
||||
break;
|
||||
}
|
||||
|
||||
gBattleScripting.battler = gBattlerAbility = battler;
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
return effect;
|
||||
}
|
||||
}
|
||||
effect = TryImmunityAbilityHealStatus(battler, caseID);
|
||||
if (effect)
|
||||
return effect;
|
||||
break;
|
||||
case ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES:
|
||||
effect = TryImmunityAbilityHealStatus(battler, caseID);
|
||||
break;
|
||||
case ABILITYEFFECT_SYNCHRONIZE:
|
||||
if (gLastUsedAbility == ABILITY_SYNCHRONIZE && gBattleStruct->synchronizeMoveEffect != MOVE_EFFECT_NONE)
|
||||
@ -5994,7 +5910,7 @@ bool32 CanSetNonVolatileStatus(u32 battlerAtk, u32 battlerDef, enum Ability abil
|
||||
{
|
||||
battleScript = BattleScript_AlreadyParalyzed;
|
||||
}
|
||||
else if (B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC))
|
||||
else if (GetGenConfig(GEN_CONFIG_PARALYZE_ELECTRIC) >= GEN_6 && IS_BATTLER_OF_TYPE(battlerDef, TYPE_ELECTRIC))
|
||||
{
|
||||
battleScript = BattleScript_NotAffected;
|
||||
}
|
||||
@ -6801,6 +6717,9 @@ static u8 ItemEffectMoveEnd(u32 battler, enum ItemHoldEffect holdEffect)
|
||||
BattleScriptCall(BattleScript_AttackerItemStatRaise);
|
||||
}
|
||||
break;
|
||||
case HOLD_EFFECT_MIRROR_HERB:
|
||||
effect = TryConsumeMirrorHerb(battler, ITEMEFFECT_NONE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -10771,6 +10690,110 @@ bool32 SetIllusionMon(struct Pokemon *mon, u32 battler)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
u32 TryImmunityAbilityHealStatus(u32 battler, u32 caseID)
|
||||
{
|
||||
u32 effect = 0;
|
||||
switch (GetBattlerAbilityIgnoreMoldBreaker(battler))
|
||||
{
|
||||
case ABILITY_IMMUNITY:
|
||||
case ABILITY_PASTEL_VEIL:
|
||||
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER))
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_OWN_TEMPO:
|
||||
if (gBattleMons[battler].volatiles.confusionTurns > 0)
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
|
||||
effect = 2;
|
||||
}
|
||||
break;
|
||||
case ABILITY_LIMBER:
|
||||
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_INSOMNIA:
|
||||
case ABILITY_VITAL_SPIRIT:
|
||||
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
|
||||
{
|
||||
TryDeactivateSleepClause(GetBattlerSide(battler), gBattlerPartyIndexes[battler]);
|
||||
gBattleMons[battler].volatiles.nightmare = FALSE;
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_WATER_VEIL:
|
||||
case ABILITY_WATER_BUBBLE:
|
||||
case ABILITY_THERMAL_EXCHANGE:
|
||||
if (gBattleMons[battler].status1 & STATUS1_BURN)
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_MAGMA_ARMOR:
|
||||
if (gBattleMons[battler].status1 & (STATUS1_FREEZE | STATUS1_FROSTBITE))
|
||||
{
|
||||
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case ABILITY_OBLIVIOUS:
|
||||
if (gBattleMons[battler].volatiles.infatuation)
|
||||
effect = 3;
|
||||
else if (GetGenConfig(GEN_CONFIG_OBLIVIOUS_TAUNT) >= GEN_6 && gDisableStructs[battler].tauntTimer != 0)
|
||||
effect = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
if (effect != 0)
|
||||
{
|
||||
switch (effect)
|
||||
{
|
||||
case 1: // status cleared
|
||||
gBattleMons[battler].status1 = 0;
|
||||
if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES)
|
||||
BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3);
|
||||
else
|
||||
BattleScriptCall(BattleScript_AbilityCuredStatus);
|
||||
break;
|
||||
case 2: // get rid of confusion
|
||||
RemoveConfusionStatus(battler);
|
||||
if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES)
|
||||
BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3);
|
||||
else
|
||||
BattleScriptCall(BattleScript_AbilityCuredStatus);
|
||||
break;
|
||||
case 3: // get rid of infatuation
|
||||
gBattleMons[battler].volatiles.infatuation = 0;
|
||||
if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES)
|
||||
BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3);
|
||||
else
|
||||
BattleScriptCall(BattleScript_AbilityCuredStatus);
|
||||
break;
|
||||
case 4: // get rid of taunt
|
||||
gDisableStructs[battler].tauntTimer = 0;
|
||||
if(caseID == ABILITYEFFECT_ON_SWITCHIN_IMMUNITIES)
|
||||
BattleScriptExecute(BattleScript_AbilityCuredStatusEnd3);
|
||||
else
|
||||
BattleScriptCall(BattleScript_AbilityCuredStatus);
|
||||
break;
|
||||
}
|
||||
|
||||
gBattleScripting.battler = gBattlerAbility = battler;
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
return effect;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool32 ShouldGetStatBadgeBoost(u16 badgeFlag, u32 battler)
|
||||
{
|
||||
if (B_BADGE_BOOST == GEN_3 && badgeFlag != 0)
|
||||
@ -11738,7 +11761,7 @@ bool32 HasWeatherEffect(void)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool32 IsAnyTargetAffected(u32 battlerAtk)
|
||||
bool32 IsAnyTargetAffected(u32 battlerAtk)
|
||||
{
|
||||
for (u32 battlerDef = 0; battlerDef < gBattlersCount; battlerDef++)
|
||||
{
|
||||
@ -11825,14 +11848,11 @@ bool32 TrySwitchInEjectPack(enum ItemCaseId caseID)
|
||||
gBattleScripting.battler = battler;
|
||||
gLastUsedItem = gBattleMons[battler].item;
|
||||
if (caseID == ITEMEFFECT_ON_SWITCH_IN_FIRST_TURN)
|
||||
{
|
||||
BattleScriptPushCursorAndCallback(BattleScript_EjectPackActivate_End3);
|
||||
}
|
||||
else if (caseID == ITEMEFFECT_NORMAL)
|
||||
BattleScriptExecute(BattleScript_EjectPackActivate_End2);
|
||||
else
|
||||
{
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EjectPackActivate_Ret;
|
||||
}
|
||||
BattleScriptCall(BattleScript_EjectPackActivate_Ret);
|
||||
gAiLogicData->ejectPackSwitch = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
@ -11985,7 +12005,7 @@ bool32 CanMoveSkipAccuracyCalc(u32 battlerAtk, u32 battlerDef, enum Ability abil
|
||||
u32 nonVolatileStatus = GetMoveNonVolatileStatus(move);
|
||||
|
||||
if ((gBattleMons[battlerDef].volatiles.lockOn && gDisableStructs[battlerDef].battlerWithSureHit == battlerAtk)
|
||||
|| (B_TOXIC_NEVER_MISS >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|
||||
|| (GetGenConfig(GEN_CONFIG_TOXIC_NEVER_MISS) >= GEN_6 && nonVolatileStatus == MOVE_EFFECT_TOXIC && IS_BATTLER_OF_TYPE(battlerAtk, TYPE_POISON))
|
||||
|| gBattleMons[battlerDef].volatiles.glaiveRush)
|
||||
{
|
||||
effect = TRUE;
|
||||
|
||||
14
src/clock.c
14
src/clock.c
@ -1,16 +1,16 @@
|
||||
#include "global.h"
|
||||
#include "berry.h"
|
||||
#include "clock.h"
|
||||
#include "dewford_trend.h"
|
||||
#include "event_data.h"
|
||||
#include "field_specials.h"
|
||||
#include "field_weather.h"
|
||||
#include "main.h"
|
||||
#include "lottery_corner.h"
|
||||
#include "overworld.h"
|
||||
#include "rtc.h"
|
||||
#include "time_events.h"
|
||||
#include "field_specials.h"
|
||||
#include "lottery_corner.h"
|
||||
#include "dewford_trend.h"
|
||||
#include "tv.h"
|
||||
#include "field_weather.h"
|
||||
#include "berry.h"
|
||||
#include "main.h"
|
||||
#include "overworld.h"
|
||||
#include "wallclock.h"
|
||||
#include "constants/form_change_types.h"
|
||||
|
||||
|
||||
@ -2889,6 +2889,10 @@ static void DebugAction_Give_Pokemon_ComplexCreateMon(u8 taskId) //https://githu
|
||||
//Moves
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
// Non-default moveset chosen. Reset moves before setting the chosen moves.
|
||||
if (moves[0] != MOVE_NONE)
|
||||
SetMonMoveSlot(&mon, MOVE_NONE, i);
|
||||
|
||||
if (moves[i] == MOVE_NONE || moves[i] >= MOVES_COUNT)
|
||||
continue;
|
||||
|
||||
|
||||
@ -5851,16 +5851,23 @@ static u8 IsEasyChatWordUnlocked(u16 easyChatWord)
|
||||
void InitializeEasyChatWordArray(u16 *words, u16 length)
|
||||
{
|
||||
u16 i;
|
||||
for (i = length - 1; i != EC_EMPTY_WORD; i--)
|
||||
*(words++) = EC_EMPTY_WORD;
|
||||
if (words != NULL)
|
||||
{
|
||||
for (i = length - 1; i != EC_EMPTY_WORD; i--)
|
||||
*(words++) = EC_EMPTY_WORD;
|
||||
}
|
||||
}
|
||||
|
||||
void InitQuestionnaireWords(void)
|
||||
{
|
||||
int i;
|
||||
u16 *words = GetQuestionnaireWordsPtr();
|
||||
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
|
||||
words[i] = EC_EMPTY_WORD;
|
||||
|
||||
if (words != NULL)
|
||||
{
|
||||
for (i = 0; i < NUM_QUESTIONNAIRE_WORDS; i++)
|
||||
words[i] = EC_EMPTY_WORD;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 IsEasyChatAnswerUnlocked(int easyChatWord)
|
||||
|
||||
@ -5230,13 +5230,13 @@ static void ShowMoveSelectWindow(u8 slot)
|
||||
{
|
||||
u8 i;
|
||||
u8 moveCount = 0;
|
||||
u8 fontId = FONT_NORMAL;
|
||||
u8 windowId = DisplaySelectionWindow(SELECTWINDOW_MOVES);
|
||||
u16 move;
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
move = GetMonData(&gPlayerParty[slot], MON_DATA_MOVE1 + i);
|
||||
u8 fontId = GetFontIdToFit(GetMoveName(move), FONT_NORMAL, 0, 72);
|
||||
AddTextPrinterParameterized(windowId, fontId, GetMoveName(move), 8, (i * 16) + 1, TEXT_SKIP_DRAW, NULL);
|
||||
if (move != MOVE_NONE)
|
||||
moveCount++;
|
||||
@ -8025,4 +8025,3 @@ static void FieldCallback_RockClimb(void)
|
||||
gFieldEffectArguments[0] = GetCursorSelectionMonId();
|
||||
FieldEffectStart(FLDEFF_USE_ROCK_CLIMB);
|
||||
}
|
||||
|
||||
|
||||
@ -4844,7 +4844,7 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16
|
||||
case EVO_MODE_ITEM_CHECK:
|
||||
for (i = 0; evolutions[i].method != EVOLUTIONS_END; i++)
|
||||
{
|
||||
bool32 conditionMet = FALSE;
|
||||
bool32 conditionsMet = FALSE;
|
||||
if (SanitizeSpeciesId(evolutions[i].targetSpecies) == SPECIES_NONE)
|
||||
continue;
|
||||
|
||||
@ -4852,11 +4852,11 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16
|
||||
{
|
||||
case EVO_ITEM:
|
||||
if (evolutions[i].param == evolutionItem)
|
||||
conditionMet = TRUE;
|
||||
conditionsMet = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conditionMet && DoesMonMeetAdditionalConditions(mon, evolutions[i].params, NULL, PARTY_SIZE, canStopEvo, evoState))
|
||||
if (conditionsMet && DoesMonMeetAdditionalConditions(mon, evolutions[i].params, NULL, PARTY_SIZE, canStopEvo, evoState))
|
||||
{
|
||||
// All checks passed, so stop checking the rest of the evolutions.
|
||||
// This is different from vanilla where the loop continues.
|
||||
@ -4878,9 +4878,9 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16
|
||||
|
||||
switch (evolutions[i].method)
|
||||
{
|
||||
case EVO_BATTLE_END:
|
||||
conditionsMet = TRUE;
|
||||
break;
|
||||
case EVO_BATTLE_END:
|
||||
conditionsMet = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (conditionsMet && DoesMonMeetAdditionalConditions(mon, evolutions[i].params, NULL, evolutionItem, canStopEvo, evoState))
|
||||
@ -4906,7 +4906,6 @@ u32 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16
|
||||
case EVO_SPIN:
|
||||
if (gSpecialVar_0x8000 == evolutions[i].param)
|
||||
conditionsMet = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6357,6 +6356,14 @@ void HandleSetPokedexFlag(enum NationalDexOrder nationalNum, u8 caseId, u32 pers
|
||||
}
|
||||
}
|
||||
|
||||
void HandleSetPokedexFlagFromMon(struct Pokemon *mon, u32 caseId)
|
||||
{
|
||||
u32 personality = GetMonData(mon, MON_DATA_PERSONALITY);
|
||||
enum NationalDexOrder nationalNum = SpeciesToNationalPokedexNum(GetMonData(mon, MON_DATA_SPECIES));
|
||||
|
||||
HandleSetPokedexFlag(nationalNum, caseId, personality);
|
||||
}
|
||||
|
||||
bool8 HasTwoFramesAnimation(u16 species)
|
||||
{
|
||||
return P_TWO_FRAME_FRONT_SPRITES
|
||||
|
||||
@ -63,3 +63,19 @@ SINGLE_BATTLE_TEST("Immunity doesn't prevent Pokémon from being poisoned by Tox
|
||||
NOT HP_BAR(player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Immunity cures existing poison on turn 0")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_ZANGOOSE) {
|
||||
Ability(ABILITY_IMMUNITY);
|
||||
Status1(STATUS1_POISON);
|
||||
}
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_IMMUNITY);
|
||||
TURN { MOVE(player, MOVE_SPLASH); }
|
||||
} THEN {
|
||||
EXPECT_EQ(player->status1, STATUS1_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,22 +31,35 @@ SINGLE_BATTLE_TEST("Oblivious prevents Captivate")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Oblivious prevents Taunt")
|
||||
SINGLE_BATTLE_TEST("Oblivious prevents Taunt (Gen6+)")
|
||||
{
|
||||
u32 gen = 0;
|
||||
PARAMETRIZE { gen = GEN_5; }
|
||||
PARAMETRIZE { gen = GEN_6; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_OBLIVIOUS_TAUNT, gen);
|
||||
ASSUME(GetMoveEffect(MOVE_TAUNT) == EFFECT_TAUNT);
|
||||
ASSUME(B_OBLIVIOUS_TAUNT >= GEN_6);
|
||||
PLAYER(SPECIES_SLOWPOKE) { Ability(ABILITY_OBLIVIOUS); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_TAUNT); }
|
||||
TURN { MOVE(player, MOVE_SPORE); }
|
||||
TURN { MOVE(player, MOVE_SPORE, allowed: gen == GEN_6); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_OBLIVIOUS);
|
||||
NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent); }
|
||||
MESSAGE("It doesn't affect Slowpoke…");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent);
|
||||
if (gen == GEN_6) {
|
||||
NONE_OF { ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent); }
|
||||
ABILITY_POPUP(player, ABILITY_OBLIVIOUS);
|
||||
MESSAGE("It doesn't affect Slowpoke…");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent);
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TAUNT, opponent);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(player, ABILITY_OBLIVIOUS);
|
||||
MESSAGE("It doesn't affect Slowpoke…");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_SLP, opponent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,25 +1,37 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves")
|
||||
SINGLE_BATTLE_TEST("Overcoat blocks powder and spore moves (Gen6+)")
|
||||
{
|
||||
u32 gen = 0;
|
||||
PARAMETRIZE { gen = GEN_5; }
|
||||
PARAMETRIZE { gen = GEN_6; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, gen);
|
||||
ASSUME(IsPowderMove(MOVE_STUN_SPORE));
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_PINECO) { Ability(ABILITY_OVERCOAT); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STUN_SPORE); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_OVERCOAT);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player);
|
||||
MESSAGE("It doesn't affect the opposing Pineco…");
|
||||
if (gen == GEN_6) {
|
||||
ABILITY_POPUP(opponent, ABILITY_OVERCOAT);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player);
|
||||
MESSAGE("It doesn't affect the opposing Pineco…");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player);
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_OVERCOAT);
|
||||
MESSAGE("It doesn't affect the opposing Pineco…");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Overcoat blocks damage from sandstorm")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); }
|
||||
PLAYER(SPECIES_HELIOLISK) { Speed(40); Ability(ABILITY_SAND_VEIL); }
|
||||
OPPONENT(SPECIES_PINECO) { Speed(30); Ability(ABILITY_OVERCOAT); }
|
||||
OPPONENT(SPECIES_STARLY) { Speed(20); }
|
||||
@ -41,7 +53,7 @@ DOUBLE_BATTLE_TEST("Overcoat blocks damage from hail")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_HAIL) == EFFECT_HAIL);
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); Ability(ABILITY_SNOW_CLOAK); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(50); Ability(ABILITY_SNOW_CLOAK); }
|
||||
PLAYER(SPECIES_SOLOSIS) { Speed(40); Ability(ABILITY_RUN_AWAY); }
|
||||
OPPONENT(SPECIES_PINECO) { Speed(30); Ability(ABILITY_OVERCOAT); }
|
||||
OPPONENT(SPECIES_SNORUNT) { Speed(20); }
|
||||
@ -73,4 +85,3 @@ SINGLE_BATTLE_TEST("Overcoat blocks Effect Spore's effect")
|
||||
EXPECT_EQ(player->status1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -292,10 +292,10 @@ SINGLE_BATTLE_TEST("Parental Bond Snore strikes twice while asleep")
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
MESSAGE("The Pokémon was hit 2 time(s)!");
|
||||
} THEN {
|
||||
if (B_PARENTAL_BOND_DMG == GEN_6)
|
||||
EXPECT_MUL_EQ(damage[0], Q_4_12(0.5), damage[1]);
|
||||
else
|
||||
if (B_PARENTAL_BOND_DMG >= GEN_7)
|
||||
EXPECT_MUL_EQ(damage[0], Q_4_12(0.25), damage[1]);
|
||||
else
|
||||
EXPECT_MUL_EQ(damage[0], Q_4_12(0.5), damage[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -59,6 +59,7 @@ SINGLE_BATTLE_TEST("Protosynthesis ability pop up activates only once during the
|
||||
u16 turns;
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_ABILITY_WEATHER, GEN_6);
|
||||
PLAYER(SPECIES_WALKING_WAKE) { Ability(ABILITY_PROTOSYNTHESIS); }
|
||||
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); };
|
||||
} WHEN {
|
||||
|
||||
@ -56,11 +56,21 @@ SINGLE_BATTLE_TEST("Supersweet Syrup can not further lower opponents evasion if
|
||||
TURN { MOVE(opponent, MOVE_SWEET_SCENT); }
|
||||
TURN { MOVE(opponent, MOVE_SWEET_SCENT); }
|
||||
TURN { MOVE(opponent, MOVE_SWEET_SCENT); }
|
||||
if (GetMoveEffect(MOVE_SWEET_SCENT) == EFFECT_EVASION_DOWN) {
|
||||
TURN { MOVE(opponent, MOVE_SWEET_SCENT); }
|
||||
TURN { MOVE(opponent, MOVE_SWEET_SCENT); }
|
||||
TURN { MOVE(opponent, MOVE_SWEET_SCENT); }
|
||||
}
|
||||
TURN { SWITCH(opponent, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent);
|
||||
if (GetMoveEffect(MOVE_SWEET_SCENT) == EFFECT_EVASION_DOWN) {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SWEET_SCENT, opponent);
|
||||
}
|
||||
ABILITY_POPUP(opponent, ABILITY_SUPERSWEET_SYRUP);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
|
||||
@ -59,7 +59,7 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_PREDICT_SWITCH: Considers ShouldSwitch and GetMos
|
||||
// Switching in trapper is an advanced feature of ShouldSwitch that requires GetMostSuitableMonToSwitchInto to also return a specific mon; this passing means the AI can use both in prediction
|
||||
PASSES_RANDOMLY(5, 10, RNG_AI_PREDICT_SWITCH);
|
||||
GIVEN {
|
||||
ASSUME(B_POWDER_GRASS >= GEN_6);
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_TRY_TO_FAINT | AI_FLAG_CHECK_VIABILITY | AI_FLAG_OMNISCIENT | AI_FLAG_SMART_SWITCHING | AI_FLAG_SMART_MON_CHOICES | AI_FLAG_PREDICT_SWITCH | AI_FLAG_PREDICT_INCOMING_MON);
|
||||
PLAYER(SPECIES_SKARMORY) { Moves(MOVE_SCRATCH); }
|
||||
PLAYER(SPECIES_DUGTRIO) { Ability(ABILITY_ARENA_TRAP); Moves(MOVE_ACROBATICS); }
|
||||
|
||||
@ -101,6 +101,7 @@ SINGLE_BATTLE_TEST("Damage calculation matches Gen5+ (Marshadow vs Mawile)")
|
||||
PARAMETRIZE { expectedDamage = 123; }
|
||||
GIVEN {
|
||||
ASSUME(GetMoveCategory(MOVE_SPECTRAL_THIEF) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
ASSUME(B_UPDATED_TYPE_MATCHUPS >= GEN_6); // Steel resists Ghost in Gen2-5
|
||||
PLAYER(SPECIES_MARSHADOW) { Level(100); Attack(286); }
|
||||
OPPONENT(SPECIES_MAWILE) { Level(100); Defense(226); HP(241); }
|
||||
} WHEN {
|
||||
@ -196,6 +197,7 @@ SINGLE_BATTLE_TEST("Gem boosted Damage calculation")
|
||||
{
|
||||
s16 dmg;
|
||||
s16 expectedDamage;
|
||||
#if I_GEM_BOOST_POWER >= GEN_6
|
||||
PARAMETRIZE { expectedDamage = 240; }
|
||||
PARAMETRIZE { expectedDamage = 237; }
|
||||
PARAMETRIZE { expectedDamage = 234; }
|
||||
@ -212,6 +214,25 @@ SINGLE_BATTLE_TEST("Gem boosted Damage calculation")
|
||||
PARAMETRIZE { expectedDamage = 208; }
|
||||
PARAMETRIZE { expectedDamage = 205; }
|
||||
PARAMETRIZE { expectedDamage = 204; }
|
||||
#else
|
||||
KNOWN_FAILING;
|
||||
PARAMETRIZE { expectedDamage = 273; }
|
||||
PARAMETRIZE { expectedDamage = 270; }
|
||||
PARAMETRIZE { expectedDamage = 267; }
|
||||
PARAMETRIZE { expectedDamage = 264; }
|
||||
PARAMETRIZE { expectedDamage = 261; }
|
||||
PARAMETRIZE { expectedDamage = 258; }
|
||||
PARAMETRIZE { expectedDamage = 256; }
|
||||
PARAMETRIZE { expectedDamage = 253; }
|
||||
PARAMETRIZE { expectedDamage = 250; }
|
||||
PARAMETRIZE { expectedDamage = 247; }
|
||||
PARAMETRIZE { expectedDamage = 244; }
|
||||
PARAMETRIZE { expectedDamage = 241; }
|
||||
PARAMETRIZE { expectedDamage = 240; }
|
||||
PARAMETRIZE { expectedDamage = 237; }
|
||||
PARAMETRIZE { expectedDamage = 234; }
|
||||
PARAMETRIZE { expectedDamage = 231; }
|
||||
#endif
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_MAKUHITA) { Item(ITEM_FIGHTING_GEM); }
|
||||
OPPONENT(SPECIES_MAKUHITA);
|
||||
|
||||
@ -1464,7 +1464,7 @@ DOUBLE_BATTLE_TEST("Dynamax: G-Max Chi Strike boosts allies' crit chance by 1 st
|
||||
{
|
||||
u32 j;
|
||||
GIVEN {
|
||||
ASSUME(B_CRIT_CHANCE >= GEN_6);
|
||||
WITH_CONFIG(GEN_CONFIG_CRIT_CHANCE, GEN_6);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_G_MAX_CHI_STRIKE, MOVE_EFFECT_CRIT_PLUS_SIDE));
|
||||
PLAYER(SPECIES_MACHAMP) { GigantamaxFactor(TRUE); }
|
||||
PLAYER(SPECIES_MACHOP);
|
||||
|
||||
@ -606,14 +606,14 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves
|
||||
s16 damage[4];
|
||||
GIVEN {
|
||||
ASSUME(GetMovePower(MOVE_MEGA_DRAIN) == 40);
|
||||
ASSUME(GetMovePower(MOVE_BUBBLE) == 40);
|
||||
ASSUME(GetMovePower(MOVE_WATER_GUN) == 40);
|
||||
PLAYER(SPECIES_WOBBUFFET) { TeraType(TYPE_STELLAR); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_MEGA_DRAIN); }
|
||||
TURN { MOVE(player, MOVE_MEGA_DRAIN, gimmick: GIMMICK_TERA); }
|
||||
TURN { MOVE(player, MOVE_MEGA_DRAIN); }
|
||||
TURN { MOVE(player, MOVE_BUBBLE); }
|
||||
TURN { MOVE(player, MOVE_WATER_GUN); }
|
||||
} SCENE {
|
||||
// turn 1
|
||||
MESSAGE("Wobbuffet used Mega Drain!");
|
||||
@ -628,8 +628,8 @@ SINGLE_BATTLE_TEST("(TERA) Terastallizing into the Stellar type boosts all moves
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_MEGA_DRAIN, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[2]);
|
||||
// turn 4
|
||||
MESSAGE("Wobbuffet used Bubble!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BUBBLE, player);
|
||||
MESSAGE("Wobbuffet used Water Gun!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[3]);
|
||||
} THEN {
|
||||
// The jump from 40 BP to 72 BP (60 * 1.2x) is a 1.8x boost.
|
||||
|
||||
@ -14,7 +14,7 @@ SINGLE_BATTLE_TEST("Big Root increases healing from absorbing moves", s16 damage
|
||||
PARAMETRIZE { item = ITEM_BIG_ROOT; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); }
|
||||
PLAYER(SPECIES_XURKITREE) { HP(200); Item(item); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ABSORB); }
|
||||
@ -24,7 +24,7 @@ SINGLE_BATTLE_TEST("Big Root increases healing from absorbing moves", s16 damage
|
||||
HP_BAR(player, captureDamage: &results[i].heal);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage); // Damage is unaffected
|
||||
EXPECT_MUL_EQ(results[1].heal, Q_4_12(5234 / 4096), results[0].heal);
|
||||
EXPECT_MUL_EQ(results[0].heal, Q_4_12(1.3), results[1].heal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ SINGLE_BATTLE_TEST("Big Root increases damage from absorbing Liquid Ooze", s16 d
|
||||
PARAMETRIZE { item = ITEM_BIG_ROOT; }
|
||||
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { HP(200); Item(item); }
|
||||
PLAYER(SPECIES_XURKITREE) { HP(200); Item(item); }
|
||||
OPPONENT(SPECIES_TENTACOOL) { Ability(ABILITY_LIQUID_OOZE); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_ABSORB); }
|
||||
@ -73,6 +73,6 @@ SINGLE_BATTLE_TEST("Big Root increases damage from absorbing Liquid Ooze", s16 d
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ABSORB, player);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_MUL_EQ(results[1].damage, Q_4_12(5234 / 4096), results[0].damage);
|
||||
EXPECT_MUL_EQ(results[0].damage, Q_4_12(1.3), results[1].damage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ SINGLE_BATTLE_TEST("Booster Energy will activate Quark Drive after Electric Terr
|
||||
SINGLE_BATTLE_TEST("Booster Energy will activate Protosynthesis after harsh sunlight ends")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_ABILITY_WEATHER, GEN_6);
|
||||
PLAYER(SPECIES_RAGING_BOLT) { Attack(100); Defense(100); Speed(100); SpAttack(110); SpDefense(100); Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); }
|
||||
OPPONENT(SPECIES_TORKOAL) { Speed(100); Ability(ABILITY_DROUGHT); };
|
||||
} WHEN {
|
||||
|
||||
@ -338,3 +338,26 @@ SINGLE_BATTLE_TEST("Eject Pack does not activate if mon is switched in due to Ej
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, opponent);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Eject Pack will trigger on the fastest mon at the end of the turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_SYRUP_BOMB, MOVE_EFFECT_SYRUP_BOMB) == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(1); Item(ITEM_EJECT_PACK); }
|
||||
PLAYER(SPECIES_WYNAUT) { Speed(10); Item(ITEM_EJECT_PACK); }
|
||||
PLAYER(SPECIES_WOBBUFFET) { Speed(2); }
|
||||
OPPONENT(SPECIES_WYNAUT) { Speed(4); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Speed(3); }
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponentLeft, MOVE_SYRUP_BOMB, target: playerLeft);
|
||||
MOVE(opponentRight, MOVE_SYRUP_BOMB, target: playerRight);
|
||||
SEND_OUT(playerRight, 2);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SYRUP_BOMB_SPEED_DROP, playerRight);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_SYRUP_BOMB_SPEED_DROP, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerRight);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,7 +32,6 @@ SINGLE_BATTLE_TEST("Gem boost is only applied once")
|
||||
s16 normalHit;
|
||||
|
||||
GIVEN {
|
||||
ASSUME(I_GEM_BOOST_POWER >= GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_NORMAL_GEM); };
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
@ -46,7 +45,10 @@ SINGLE_BATTLE_TEST("Gem boost is only applied once")
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SCRATCH, player);
|
||||
HP_BAR(opponent, captureDamage: &normalHit);
|
||||
} THEN {
|
||||
EXPECT_MUL_EQ(normalHit, Q_4_12(1.3), boostedHit);
|
||||
if (I_GEM_BOOST_POWER >= GEN_6)
|
||||
EXPECT_MUL_EQ(normalHit, Q_4_12(1.3), boostedHit);
|
||||
else
|
||||
EXPECT_MUL_EQ(normalHit, Q_4_12(1.5), boostedHit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ SINGLE_BATTLE_TEST("Acrobatics still doubles in power when Flying Gem is consume
|
||||
PARAMETRIZE { heldItem = ITEM_NONE; }
|
||||
PARAMETRIZE { heldItem = ITEM_FLYING_GEM; }
|
||||
GIVEN {
|
||||
ASSUME(I_GEM_BOOST_POWER >= GEN_6);
|
||||
ASSUME(gItemsInfo[ITEM_FLYING_GEM].holdEffect == HOLD_EFFECT_GEMS);
|
||||
ASSUME(gItemsInfo[ITEM_FLYING_GEM].secondaryId == TYPE_FLYING);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_DRAGON_DARTS) == EFFECT_DRAGON_DARTS);
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dragon Darts strikes twice")
|
||||
@ -72,13 +71,13 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes an opponent twice if the other one is F
|
||||
struct BattlePokemon *chosenTarget = NULL;
|
||||
struct BattlePokemon *finalTarget = NULL;
|
||||
u32 speciesLeft, speciesRight;
|
||||
PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_CLEFAIRY; speciesRight = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; }
|
||||
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_CLEFAIRY; }
|
||||
PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentRight; speciesLeft = SPECIES_FIDOUGH; speciesRight = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentRight; speciesLeft = SPECIES_FIDOUGH; speciesRight = SPECIES_WOBBUFFET; }
|
||||
PARAMETRIZE { chosenTarget = opponentLeft; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_FIDOUGH; }
|
||||
PARAMETRIZE { chosenTarget = opponentRight; finalTarget = opponentLeft; speciesLeft = SPECIES_WOBBUFFET; speciesRight = SPECIES_FIDOUGH; }
|
||||
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY);
|
||||
ASSUME(GetSpeciesType(SPECIES_FIDOUGH, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_FIDOUGH, 1) == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(speciesLeft);
|
||||
@ -257,7 +256,6 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes right ally twice if one strike misses")
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
@ -273,14 +271,14 @@ DOUBLE_BATTLE_TEST("Dragon Darts strikes will be both redirected to Follow Me us
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy type follow me user")
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a Fairy-type follow me user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY);
|
||||
ASSUME(GetSpeciesType(SPECIES_FIDOUGH, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_FIDOUGH, 1) == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CLEFAIRY);
|
||||
OPPONENT(SPECIES_FIDOUGH);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponentRight, MOVE_FOLLOW_ME); MOVE(playerLeft, MOVE_DRAGON_DARTS, target: opponentLeft); }
|
||||
} SCENE {
|
||||
@ -295,7 +293,6 @@ DOUBLE_BATTLE_TEST("Dragon Darts fails to strike any target if under a fairy typ
|
||||
DOUBLE_BATTLE_TEST("Dragon Darts fails to strike the second target if first target fainted and follow me was active")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_ENDURE) == EFFECT_ENDURE);
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Endure allows the user to survive any attack with 1 HP left");
|
||||
|
||||
SINGLE_BATTLE_TEST("Endure does not prevent multiple hits and stat changes occur at the end of the turn")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT);
|
||||
ASSUME(GetMoveEffect(MOVE_ENDURE) == EFFECT_ENDURE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
|
||||
} WHEN {
|
||||
@ -54,6 +58,23 @@ DOUBLE_BATTLE_TEST("Endure is not transferred to a mon that is switched in due t
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Endure only lasts for one turn")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_ENDURE); MOVE(player, MOVE_POUND); }
|
||||
TURN { MOVE(player, MOVE_POUND); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_ENDURE, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player);
|
||||
MESSAGE("The opposing Wobbuffet endured the hit!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POUND, player);
|
||||
NOT MESSAGE("The opposing Wobbuffet endured the hit!");
|
||||
}
|
||||
}
|
||||
|
||||
TO_DO_BATTLE_TEST("Endure's success rate decreases for every consecutively used turn");
|
||||
TO_DO_BATTLE_TEST("Endure uses the same counter as Protect");
|
||||
TO_DO_BATTLE_TEST("Endure doesn't trigger effects that require damage to be done to the Pokémon (Gen 2-4)"); // Eg. Rough Skin
|
||||
|
||||
@ -12,15 +12,14 @@ SINGLE_BATTLE_TEST("Fickle Beam deals double damage 30% of the time")
|
||||
|
||||
PASSES_RANDOMLY(30, 100, RNG_FICKLE_BEAM);
|
||||
GIVEN {
|
||||
ASSUME(GetMovePower(MOVE_POWER_GEM) == 80);
|
||||
ASSUME(GetMovePower(MOVE_FICKLE_BEAM) == 80);
|
||||
ASSUME(GetMovePower(MOVE_DAZZLING_GLEAM) == GetMovePower(MOVE_FICKLE_BEAM));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_POWER_GEM); }
|
||||
TURN { MOVE(player, MOVE_DAZZLING_GLEAM); }
|
||||
TURN { MOVE(player, MOVE_FICKLE_BEAM); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_POWER_GEM, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DAZZLING_GLEAM, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[0]);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FICKLE_BEAM, player);
|
||||
HP_BAR(opponent, captureDamage: &damage[1]);
|
||||
|
||||
@ -1,10 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
#if B_UPDATED_MOVE_DATA >= GEN_6
|
||||
#define FUTURE_SIGHT_EQUIVALENT MOVE_SEED_FLARE /* 120 power */
|
||||
#elif B_UPDATED_MOVE_DATA >= GEN_5
|
||||
#define FUTURE_SIGHT_EQUIVALENT MOVE_DYNAMAX_CANNON /* 100 power */
|
||||
#else
|
||||
#define FUTURE_SIGHT_EQUIVALENT MOVE_EXTRASENSORY /* 80 power */
|
||||
#endif
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMovePower(MOVE_SEED_FLARE) == GetMovePower(MOVE_FUTURE_SIGHT));
|
||||
ASSUME(GetMoveCategory(MOVE_SEED_FLARE) == GetMoveCategory(MOVE_FUTURE_SIGHT));
|
||||
ASSUME(GetMovePower(FUTURE_SIGHT_EQUIVALENT) == GetMovePower(MOVE_FUTURE_SIGHT));
|
||||
ASSUME(GetMoveCategory(FUTURE_SIGHT_EQUIVALENT) == GetMoveCategory(MOVE_FUTURE_SIGHT));
|
||||
ASSUME(GetMoveEffect(MOVE_FUTURE_SIGHT) == EFFECT_FUTURE_SIGHT);
|
||||
ASSUME(GetMovePower(MOVE_FUTURE_SIGHT) > 0);
|
||||
}
|
||||
@ -23,13 +31,13 @@ SINGLE_BATTLE_TEST("Future Sight uses Sp. Atk stat of the original user without
|
||||
PLAYER(SPECIES_RAICHU) { Item(item); }
|
||||
OPPONENT(SPECIES_REGICE);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN { }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player);
|
||||
HP_BAR(opponent, captureDamage: &seedFlareDmg);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
|
||||
MESSAGE("The opposing Regice took the Future Sight attack!");
|
||||
@ -49,13 +57,13 @@ SINGLE_BATTLE_TEST("Future Sight is not boosted by Life Orb is original user if
|
||||
PLAYER(SPECIES_RAICHU) { Item(ITEM_LIFE_ORB); }
|
||||
OPPONENT(SPECIES_REGICE);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN { }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player);
|
||||
HP_BAR(opponent, captureDamage: &seedFlareDmg);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
|
||||
MESSAGE("The opposing Regice took the Future Sight attack!");
|
||||
@ -77,13 +85,13 @@ SINGLE_BATTLE_TEST("Future Sight receives STAB from party mon (Gen 5+)")
|
||||
PLAYER(SPECIES_RAICHU);
|
||||
OPPONENT(SPECIES_REGICE);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN { }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player);
|
||||
HP_BAR(opponent, captureDamage: &seedFlareDmg);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
|
||||
HP_BAR(opponent, captureDamage: &futureSightDmg);
|
||||
@ -100,13 +108,13 @@ SINGLE_BATTLE_TEST("Future Sight is affected by type effectiveness (Gen 5+)")
|
||||
PLAYER(SPECIES_RAICHU);
|
||||
OPPONENT(SPECIES_HOUNDOOM);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SEED_FLARE, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, FUTURE_SIGHT_EQUIVALENT, WITH_RNG(RNG_SECONDARY_EFFECT, FALSE)); }
|
||||
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
|
||||
TURN { SWITCH(player, 1); }
|
||||
TURN { }
|
||||
TURN { }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SEED_FLARE, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, FUTURE_SIGHT_EQUIVALENT, player);
|
||||
HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
|
||||
MESSAGE("The opposing Houndoom took the Future Sight attack!");
|
||||
|
||||
@ -280,6 +280,7 @@ DOUBLE_BATTLE_TEST("Instructed move will be redirected by Rage Powder after inst
|
||||
PARAMETRIZE { moveTarget = opponentLeft; }
|
||||
PARAMETRIZE { moveTarget = opponentRight; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6);
|
||||
ASSUME(GetMoveEffect(MOVE_RAGE_POWDER) == EFFECT_FOLLOW_ME);
|
||||
ASSUME(IsPowderMove(MOVE_RAGE_POWDER) == TRUE);
|
||||
ASSUME(GetMoveEffect(MOVE_SOAK) == EFFECT_SOAK);
|
||||
|
||||
@ -177,14 +177,14 @@ SINGLE_BATTLE_TEST("Scale Shot is immune to Fairy types and will end the move co
|
||||
GIVEN {
|
||||
ASSUME(GetMoveEffect(MOVE_SCALE_SHOT) == EFFECT_MULTI_HIT);
|
||||
ASSUME(GetMoveType(MOVE_SCALE_SHOT) == TYPE_DRAGON);
|
||||
ASSUME(GetSpeciesType(SPECIES_CLEFAIRY, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_CLEFAIRY, 1) == TYPE_FAIRY);
|
||||
ASSUME(GetSpeciesType(SPECIES_FIDOUGH, 0) == TYPE_FAIRY || GetSpeciesType(SPECIES_FIDOUGH, 1) == TYPE_FAIRY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CLEFAIRY) { HP(1); }
|
||||
OPPONENT(SPECIES_FIDOUGH) { HP(1); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SCALE_SHOT); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SCALE_SHOT, player);
|
||||
MESSAGE("It doesn't affect the opposing Clefairy…");
|
||||
MESSAGE("It doesn't affect the opposing Fidough…");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -149,9 +149,10 @@ DOUBLE_BATTLE_TEST("Powder fails if target is already affected by Powder")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Powder fails if the target is Grass type")
|
||||
SINGLE_BATTLE_TEST("Powder fails if the target is Grass type (Gen6+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6);
|
||||
ASSUME(GetSpeciesType(SPECIES_VENUSAUR, 0) == TYPE_GRASS || GetSpeciesType(SPECIES_VENUSAUR, 1) == TYPE_GRASS);
|
||||
PLAYER(SPECIES_VENUSAUR);
|
||||
OPPONENT(SPECIES_VIVILLON);
|
||||
@ -164,9 +165,10 @@ SINGLE_BATTLE_TEST("Powder fails if the target is Grass type")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Powder fails if the target has Overcoat")
|
||||
SINGLE_BATTLE_TEST("Powder fails if the target has Overcoat (Gen6+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6);
|
||||
PLAYER(SPECIES_FORRETRESS) { Ability(ABILITY_OVERCOAT); }
|
||||
OPPONENT(SPECIES_VIVILLON);
|
||||
} WHEN {
|
||||
|
||||
@ -43,14 +43,16 @@ SINGLE_BATTLE_TEST("Toxic can't bad poison a poison or steel type")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type")
|
||||
SINGLE_BATTLE_TEST("Toxic cannot miss if used by a Poison-type (Gen6+)")
|
||||
{
|
||||
u32 species;
|
||||
u32 species, gen;
|
||||
bool32 hit;
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; hit = FALSE; }
|
||||
PARAMETRIZE { species = SPECIES_NIDORAN_M; hit = TRUE; }
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; hit = FALSE; gen = GEN_5; }
|
||||
PARAMETRIZE { species = SPECIES_NIDORAN_M; hit = FALSE; gen = GEN_5; }
|
||||
PARAMETRIZE { species = SPECIES_WOBBUFFET; hit = FALSE; gen = GEN_6; }
|
||||
PARAMETRIZE { species = SPECIES_NIDORAN_M; hit = TRUE; gen = GEN_6; }
|
||||
GIVEN {
|
||||
ASSUME(B_TOXIC_NEVER_MISS >= GEN_6);
|
||||
WITH_CONFIG(GEN_CONFIG_TOXIC_NEVER_MISS, gen);
|
||||
ASSUME(GetSpeciesType(SPECIES_NIDORAN_M, 0) == TYPE_POISON);
|
||||
PLAYER(species);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
|
||||
@ -38,11 +38,10 @@ SINGLE_BATTLE_TEST("Dire Claw cannot poison/paralyze poison/electric types respe
|
||||
u8 statusAnim;
|
||||
u16 species;
|
||||
u32 rng;
|
||||
#if B_PARALYZE_ELECTRIC >= GEN_6
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; }
|
||||
#endif // B_PARALYZE_ELECTRIC
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PSN; rng = MOVE_EFFECT_POISON; species = SPECIES_ARBOK; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species);
|
||||
} WHEN {
|
||||
|
||||
@ -21,19 +21,27 @@ SINGLE_BATTLE_TEST("Thunder Shock inflicts paralysis")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Thunder Shock cannot paralyze an Electric-type")
|
||||
SINGLE_BATTLE_TEST("Thunder Shock cannot paralyze an Electric-type (Gen6+)")
|
||||
{
|
||||
u32 gen = 0;
|
||||
PARAMETRIZE { gen = GEN_5; }
|
||||
PARAMETRIZE { gen = GEN_6; }
|
||||
GIVEN {
|
||||
ASSUME(B_PARALYZE_ELECTRIC >= GEN_6);
|
||||
WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, gen);
|
||||
ASSUME(GetSpeciesType(SPECIES_PIKACHU, 0) == TYPE_ELECTRIC);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIKACHU);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THUNDER_SHOCK); }
|
||||
TURN { MOVE(player, MOVE_THUNDER_SHOCK, secondaryEffect: TRUE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THUNDER_SHOCK, player);
|
||||
HP_BAR(opponent);
|
||||
NONE_OF {
|
||||
if (gen == GEN_6) {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent);
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent);
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
|
||||
@ -46,12 +46,11 @@ SINGLE_BATTLE_TEST("Tri Attack cannot paralyze/burn/freeze electric/fire/ice typ
|
||||
u8 statusAnim;
|
||||
u16 species;
|
||||
u32 rng;
|
||||
#if B_PARALYZE_ELECTRIC >= GEN_6
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_PRZ; rng = MOVE_EFFECT_PARALYSIS; species = SPECIES_RAICHU; }
|
||||
#endif // B_PARALYZE_ELECTRIC
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_BRN; rng = MOVE_EFFECT_BURN; species = SPECIES_ARCANINE; }
|
||||
PARAMETRIZE { statusAnim = B_ANIM_STATUS_FRZ; rng = MOVE_EFFECT_FREEZE_OR_FROSTBITE; species = SPECIES_GLALIE; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(species);
|
||||
} WHEN {
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon")
|
||||
SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon (Gen6+)")
|
||||
{
|
||||
u32 gen = 0;
|
||||
PARAMETRIZE { gen = GEN_5; }
|
||||
PARAMETRIZE { gen = GEN_6; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, gen);
|
||||
ASSUME(IsPowderMove(MOVE_STUN_SPORE));
|
||||
ASSUME(GetSpeciesType(SPECIES_ODDISH, 0) == TYPE_GRASS);
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
@ -11,7 +15,12 @@ SINGLE_BATTLE_TEST("Powder moves are blocked by Grass-type Pokémon")
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_STUN_SPORE); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player);
|
||||
MESSAGE("It doesn't affect the opposing Oddish…");
|
||||
if (gen == GEN_6) {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player);
|
||||
MESSAGE("It doesn't affect the opposing Oddish…");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_STUN_SPORE, player);
|
||||
NOT MESSAGE("It doesn't affect the opposing Oddish…");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1075,6 +1075,7 @@ SINGLE_BATTLE_TEST("Sleep Clause: Sleep clause is deactivated when a sleeping mo
|
||||
enum Ability ability;
|
||||
PARAMETRIZE { ability = ABILITY_VITAL_SPIRIT; }
|
||||
PARAMETRIZE { ability = ABILITY_INSOMNIA; }
|
||||
|
||||
GIVEN {
|
||||
FLAG_SET(B_FLAG_SLEEP_CLAUSE);
|
||||
ASSUME(GetMoveEffect(MOVE_SPORE) == EFFECT_NON_VOLATILE_STATUS);
|
||||
|
||||
@ -56,6 +56,7 @@ AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target")
|
||||
PARAMETRIZE { species = SPECIES_PIKACHU; ability = ABILITY_STATIC; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, GEN_6);
|
||||
AI_FLAGS(AI_FLAG_CHECK_BAD_MOVE | AI_FLAG_CHECK_VIABILITY | AI_FLAG_TRY_TO_FAINT | AI_FLAG_OMNISCIENT);
|
||||
PLAYER(species) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { Moves(MOVE_CELEBRATE, MOVE_THUNDER_WAVE); }
|
||||
@ -64,18 +65,30 @@ AI_SINGLE_BATTLE_TEST("AI avoids Thunder Wave when it can not paralyse target")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Thunder Wave doesn't affect Electric types in Gen6+")
|
||||
SINGLE_BATTLE_TEST("Thunder Wave doesn't affect Electric types (Gen6+)")
|
||||
{
|
||||
u32 gen = 0;
|
||||
PARAMETRIZE { gen = GEN_5; }
|
||||
PARAMETRIZE { gen = GEN_6; }
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_PARALYZE_ELECTRIC, gen);
|
||||
ASSUME(GetSpeciesType(SPECIES_PIKACHU, 0) == TYPE_ELECTRIC);
|
||||
ASSUME(B_PARALYZE_ELECTRIC >= GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIKACHU);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THUNDER_WAVE); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet used Thunder Wave!");
|
||||
MESSAGE("It doesn't affect the opposing Pikachu…");
|
||||
if (gen == GEN_6) {
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent);
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
MESSAGE("It doesn't affect the opposing Pikachu…");
|
||||
} else {
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_PRZ, opponent);
|
||||
STATUS_ICON(opponent, paralysis: TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -22,11 +22,25 @@ SINGLE_BATTLE_TEST("Sleep prevents the battler from using a move")
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sleep: Spore doesn't affect grass types (Gen 6+)")
|
||||
SINGLE_BATTLE_TEST("Sleep: Spore affects grass types (Gen1-5)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_5);
|
||||
ASSUME(IsPowderMove(MOVE_SPORE));
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CHIKORITA);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SPORE); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPORE, player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sleep: Spore doesn't affect grass types (Gen6+)")
|
||||
{
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_POWDER_GRASS, GEN_6);
|
||||
ASSUME(IsPowderMove(MOVE_SPORE));
|
||||
ASSUME(B_POWDER_GRASS >= GEN_6);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CHIKORITA);
|
||||
} WHEN {
|
||||
|
||||
@ -288,7 +288,7 @@ TEST("givemon [moves]")
|
||||
ZeroPlayerPartyMons();
|
||||
|
||||
RUN_OVERWORLD_SCRIPT(
|
||||
givemon SPECIES_WOBBUFFET, 100, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_NONE, move4=MOVE_NONE;
|
||||
givemon SPECIES_WOBBUFFET, 100, move1=MOVE_SCRATCH, move2=MOVE_SPLASH, move3=MOVE_NONE;
|
||||
);
|
||||
|
||||
EXPECT_EQ(GetMonData(&gPlayerParty[0], MON_DATA_SPECIES), SPECIES_WOBBUFFET);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user