Merge branch '_RHH/master' into _RHH/upcoming
This commit is contained in:
commit
3205f377d5
16 changed files with 207 additions and 88 deletions
5
.github/pull_request_template.md
vendored
5
.github/pull_request_template.md
vendored
|
@ -20,6 +20,11 @@
|
||||||
<!-- If your PR contains any unfinished features that are not considered merge-blocking, please list them here for clarity so no one can forget. -->
|
<!-- If your PR contains any unfinished features that are not considered merge-blocking, please list them here for clarity so no one can forget. -->
|
||||||
<!-- If it doesn't apply, feel free to remove this section. -->
|
<!-- If it doesn't apply, feel free to remove this section. -->
|
||||||
|
|
||||||
|
## Things to note in the release changelog:
|
||||||
|
<!-- We use an automated system to generate our changelogs, so if there's something of note that our end users should know in regards to this change besides the title of this PR, they should be added here. -->
|
||||||
|
<!-- *MUST* be structured as bullet points. -->
|
||||||
|
<!-- If it doesn't apply, feel free to remove this section. -->
|
||||||
|
|
||||||
## **Discord contact info**
|
## **Discord contact info**
|
||||||
<!--- Formatted as username (e.g. Lunos) or username#numbers (e.g. Lunos#4026) -->
|
<!--- Formatted as username (e.g. Lunos) or username#numbers (e.g. Lunos#4026) -->
|
||||||
<!--- Contributors must join https://discord.gg/6CzjAG6GZk -->
|
<!--- Contributors must join https://discord.gg/6CzjAG6GZk -->
|
||||||
|
|
|
@ -119,11 +119,6 @@ Based off RHH's pokeemerald-expansion 1.9.3 https://github.com/rh-hideout/pokeem
|
||||||
- ***Gen 6+ Exp. Share*** (configurable)
|
- ***Gen 6+ Exp. Share*** (configurable)
|
||||||
- Berserk Gene
|
- Berserk Gene
|
||||||
- Most battle items from Gen 4+
|
- Most battle items from Gen 4+
|
||||||
- Existing item data but missing effects:
|
|
||||||
- Gimmighoul Coin
|
|
||||||
- Booster Energy
|
|
||||||
- Tera Shards
|
|
||||||
- Tera Orb
|
|
||||||
- ***Feature branches incorporated (with permission):***
|
- ***Feature branches incorporated (with permission):***
|
||||||
- [RHH intro credits](https://github.com/Xhyzi/pokeemerald/tree/rhh-intro-credits) by @Xhyzi.
|
- [RHH intro credits](https://github.com/Xhyzi/pokeemerald/tree/rhh-intro-credits) by @Xhyzi.
|
||||||
- A small signature from all of us to show the collective effort in the project :)
|
- A small signature from all of us to show the collective effort in the project :)
|
||||||
|
|
|
@ -16170,11 +16170,11 @@ SandsearStormFireSpin:
|
||||||
|
|
||||||
@Credits to Skeli
|
@Credits to Skeli
|
||||||
gBattleAnimMove_LunarBlessing::
|
gBattleAnimMove_LunarBlessing::
|
||||||
|
loadspritegfx ANIM_TAG_BLUE_STAR
|
||||||
loadspritegfx ANIM_TAG_MOON
|
loadspritegfx ANIM_TAG_MOON
|
||||||
loadspritegfx ANIM_TAG_SPARKLE_2
|
loadspritegfx ANIM_TAG_SPARKLE_2
|
||||||
loadspritegfx ANIM_TAG_GUARD_RING
|
loadspritegfx ANIM_TAG_GUARD_RING
|
||||||
loadspritegfx ANIM_TAG_SMALL_EMBER @Yellow colour for ring
|
loadspritegfx ANIM_TAG_SMALL_EMBER @Yellow colour for ring
|
||||||
loadspritegfx ANIM_TAG_BLUE_STAR
|
|
||||||
monbg ANIM_ATK_PARTNER
|
monbg ANIM_ATK_PARTNER
|
||||||
setalpha 16, 0
|
setalpha 16, 0
|
||||||
createvisualtask AnimTask_BlendBattleAnimPal, 0xa, F_PAL_BG, 0x1, 0x0, 0x10, 0x0
|
createvisualtask AnimTask_BlendBattleAnimPal, 0xa, F_PAL_BG, 0x1, 0x0, 0x10, 0x0
|
||||||
|
@ -18074,10 +18074,12 @@ PopulationBombContinue:
|
||||||
waitforvisualfinish
|
waitforvisualfinish
|
||||||
end
|
end
|
||||||
|
|
||||||
|
gBattleAnimMove_RevivalBlessing::
|
||||||
|
goto gBattleAnimMove_LunarBlessing
|
||||||
|
|
||||||
gBattleAnimMove_TeraBlast::
|
gBattleAnimMove_TeraBlast::
|
||||||
gBattleAnimMove_OrderUp::
|
gBattleAnimMove_OrderUp::
|
||||||
gBattleAnimMove_GlaiveRush::
|
gBattleAnimMove_GlaiveRush::
|
||||||
gBattleAnimMove_RevivalBlessing::
|
|
||||||
gBattleAnimMove_SaltCure::
|
gBattleAnimMove_SaltCure::
|
||||||
gBattleAnimMove_TripleDive::
|
gBattleAnimMove_TripleDive::
|
||||||
gBattleAnimMove_Doodle::
|
gBattleAnimMove_Doodle::
|
||||||
|
|
|
@ -466,6 +466,9 @@ BattleScript_EffectRevivalBlessing::
|
||||||
goto BattleScript_MoveEnd
|
goto BattleScript_MoveEnd
|
||||||
|
|
||||||
BattleScript_EffectRevivalBlessingSendOut:
|
BattleScript_EffectRevivalBlessingSendOut:
|
||||||
|
getswitchedmondata BS_SCRIPTING
|
||||||
|
switchindataupdate BS_SCRIPTING
|
||||||
|
hpthresholds BS_SCRIPTING
|
||||||
switchinanim BS_SCRIPTING, FALSE
|
switchinanim BS_SCRIPTING, FALSE
|
||||||
waitstate
|
waitstate
|
||||||
switchineffects BS_SCRIPTING
|
switchineffects BS_SCRIPTING
|
||||||
|
@ -4959,7 +4962,7 @@ BattleScript_EffectFollowMe::
|
||||||
attackcanceler
|
attackcanceler
|
||||||
attackstring
|
attackstring
|
||||||
ppreduce
|
ppreduce
|
||||||
.if B_UPDATED_MOVE_DATA >= GEN_6
|
.if B_UPDATED_MOVE_DATA >= GEN_8
|
||||||
jumpifnotbattletype BATTLE_TYPE_DOUBLE, BattleScript_ButItFailed
|
jumpifnotbattletype BATTLE_TYPE_DOUBLE, BattleScript_ButItFailed
|
||||||
.endif
|
.endif
|
||||||
setforcedtarget
|
setforcedtarget
|
||||||
|
|
|
@ -244,9 +244,9 @@
|
||||||
#define F_SUMMARY_SCREEN_FLIP_SPRITE 0x80
|
#define F_SUMMARY_SCREEN_FLIP_SPRITE 0x80
|
||||||
|
|
||||||
#define EVOLUTIONS_END 0xFFFF // Not an actual evolution, used to mark the end of an evolution array.
|
#define EVOLUTIONS_END 0xFFFF // Not an actual evolution, used to mark the end of an evolution array.
|
||||||
#define EVO_NONE 0xFFFE // Not an actual evolution, used to generate offspring that can't evolve into the specified species, like regional forms.
|
|
||||||
|
|
||||||
enum EvolutionMethods {
|
enum EvolutionMethods {
|
||||||
|
EVO_NONE, // Not an actual evolution, used to generate offspring that can't evolve into the specified species, like regional forms.
|
||||||
EVO_FRIENDSHIP, // Pokémon levels up with friendship ≥ 220
|
EVO_FRIENDSHIP, // Pokémon levels up with friendship ≥ 220
|
||||||
EVO_FRIENDSHIP_DAY, // Pokémon levels up during the day with friendship ≥ 220
|
EVO_FRIENDSHIP_DAY, // Pokémon levels up during the day with friendship ≥ 220
|
||||||
EVO_FRIENDSHIP_NIGHT, // Pokémon levels up at night with friendship ≥ 220
|
EVO_FRIENDSHIP_NIGHT, // Pokémon levels up at night with friendship ≥ 220
|
||||||
|
|
|
@ -797,7 +797,7 @@ u8 CalculatePPWithBonus(u16 move, u8 ppBonuses, u8 moveIndex);
|
||||||
void RemoveMonPPBonus(struct Pokemon *mon, u8 moveIndex);
|
void RemoveMonPPBonus(struct Pokemon *mon, u8 moveIndex);
|
||||||
void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex);
|
void RemoveBattleMonPPBonus(struct BattlePokemon *mon, u8 moveIndex);
|
||||||
void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst);
|
void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst);
|
||||||
void CopyPlayerPartyMonToBattleData(u8 battlerId, u8 partyIndex);
|
void CopyPartyMonToBattleData(u32 battlerId, u32 partyIndex);
|
||||||
bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex);
|
bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex);
|
||||||
bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, u8 e);
|
bool8 PokemonUseItemEffects(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex, u8 e);
|
||||||
bool8 HealStatusConditions(struct Pokemon *mon, u32 healMask, u8 battlerId);
|
bool8 HealStatusConditions(struct Pokemon *mon, u32 healMask, u8 battlerId);
|
||||||
|
|
|
@ -735,6 +735,8 @@ extern struct BattleTestRunnerState *const gBattleTestRunnerState;
|
||||||
#define APPEND_COMMA_TRUE(a) , a, TRUE
|
#define APPEND_COMMA_TRUE(a) , a, TRUE
|
||||||
#define R_APPEND_TRUE(...) __VA_OPT__(FIRST(__VA_ARGS__), TRUE RECURSIVELY(R_FOR_EACH(APPEND_COMMA_TRUE, EXCEPT_1(__VA_ARGS__))))
|
#define R_APPEND_TRUE(...) __VA_OPT__(FIRST(__VA_ARGS__), TRUE RECURSIVELY(R_FOR_EACH(APPEND_COMMA_TRUE, EXCEPT_1(__VA_ARGS__))))
|
||||||
|
|
||||||
|
#define AI_TRAINER_NAME "{PKMN} TRAINER LEAF"
|
||||||
|
|
||||||
/* Test */
|
/* Test */
|
||||||
|
|
||||||
#define TO_DO_BATTLE_TEST(_name) \
|
#define TO_DO_BATTLE_TEST(_name) \
|
||||||
|
@ -952,7 +954,10 @@ struct MoveContext
|
||||||
u16 gimmick:4;
|
u16 gimmick:4;
|
||||||
u16 explicitGimmick:1;
|
u16 explicitGimmick:1;
|
||||||
u16 allowed:1;
|
u16 allowed:1;
|
||||||
|
// End of word
|
||||||
u16 explicitAllowed:1;
|
u16 explicitAllowed:1;
|
||||||
|
u16 partyIndex:3; // Used for moves where you select a party member without swiching, such as Revival Blessing
|
||||||
|
u16 explicitPartyIndex:1;
|
||||||
u16 notExpected:1; // Has effect only with EXPECT_MOVE
|
u16 notExpected:1; // Has effect only with EXPECT_MOVE
|
||||||
u16 explicitNotExpected:1;
|
u16 explicitNotExpected:1;
|
||||||
struct BattlePokemon *target;
|
struct BattlePokemon *target;
|
||||||
|
|
|
@ -532,7 +532,7 @@ struct SimulatedDamage AI_CalcDamage(u32 move, u32 battlerAtk, u32 battlerDef, u
|
||||||
gBattleStruct->swapDamageCategory = GetCategoryBasedOnStats(battlerAtk) == DAMAGE_CATEGORY_PHYSICAL;
|
gBattleStruct->swapDamageCategory = GetCategoryBasedOnStats(battlerAtk) == DAMAGE_CATEGORY_PHYSICAL;
|
||||||
break;
|
break;
|
||||||
case EFFECT_TERA_STARSTORM:
|
case EFFECT_TERA_STARSTORM:
|
||||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA && gBattleMons[gBattlerAttacker].species == SPECIES_TERAPAGOS_STELLAR)
|
if (GetActiveGimmick(battlerAtk) == GIMMICK_TERA && gBattleMons[battlerAtk].species == SPECIES_TERAPAGOS_STELLAR)
|
||||||
gBattleStruct->swapDamageCategory = GetCategoryBasedOnStats(battlerAtk) == DAMAGE_CATEGORY_PHYSICAL;
|
gBattleStruct->swapDamageCategory = GetCategoryBasedOnStats(battlerAtk) == DAMAGE_CATEGORY_PHYSICAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17441,7 +17441,10 @@ void BS_TryRevivalBlessing(void)
|
||||||
if (IsDoubleBattle() &&
|
if (IsDoubleBattle() &&
|
||||||
gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)] == gSelectedMonPartyId)
|
gBattlerPartyIndexes[BATTLE_PARTNER(gBattlerAttacker)] == gSelectedMonPartyId)
|
||||||
{
|
{
|
||||||
gBattleScripting.battler = BATTLE_PARTNER(gBattlerAttacker);
|
u32 i = BATTLE_PARTNER(gBattlerAttacker);
|
||||||
|
gAbsentBattlerFlags &= ~(1u << i);
|
||||||
|
gBattleStruct->monToSwitchIntoId[i] = gSelectedMonPartyId;
|
||||||
|
gBattleScripting.battler = i;
|
||||||
gBattleCommunication[MULTIUSE_STATE] = TRUE;
|
gBattleCommunication[MULTIUSE_STATE] = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,7 @@ extern const struct SpriteTemplate gAncientPowerRockSpriteTemplate[];
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
COPYRIGHT_INITIALIZE,
|
COPYRIGHT_INITIALIZE,
|
||||||
|
COPYRIGHT_EMULATOR_BLEND,
|
||||||
COPYRIGHT_START_FADE = 140,
|
COPYRIGHT_START_FADE = 140,
|
||||||
COPYRIGHT_START_INTRO,
|
COPYRIGHT_START_INTRO,
|
||||||
};
|
};
|
||||||
|
@ -1104,7 +1105,7 @@ static u8 SetUpCopyrightScreen(void)
|
||||||
GameCubeMultiBoot_Init(&gMultibootProgramStruct);
|
GameCubeMultiBoot_Init(&gMultibootProgramStruct);
|
||||||
// REG_DISPCNT needs to be overwritten the second time, because otherwise the intro won't show up on VBA 1.7.2 and John GBA Lite emulators.
|
// REG_DISPCNT needs to be overwritten the second time, because otherwise the intro won't show up on VBA 1.7.2 and John GBA Lite emulators.
|
||||||
// The REG_DISPCNT overwrite is NOT needed in m-GBA, No$GBA, VBA 1.8.0, My Boy and Pizza Boy GBA emulators.
|
// The REG_DISPCNT overwrite is NOT needed in m-GBA, No$GBA, VBA 1.8.0, My Boy and Pizza Boy GBA emulators.
|
||||||
case 1:
|
case COPYRIGHT_EMULATOR_BLEND:
|
||||||
REG_DISPCNT = DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON;
|
REG_DISPCNT = DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON;
|
||||||
default:
|
default:
|
||||||
UpdatePaletteFade();
|
UpdatePaletteFade();
|
||||||
|
|
|
@ -3674,10 +3674,12 @@ void PokemonToBattleMon(struct Pokemon *src, struct BattlePokemon *dst)
|
||||||
dst->status2 = 0;
|
dst->status2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyPlayerPartyMonToBattleData(u8 battlerId, u8 partyIndex)
|
void CopyPartyMonToBattleData(u32 battlerId, u32 partyIndex)
|
||||||
{
|
{
|
||||||
PokemonToBattleMon(&gPlayerParty[partyIndex], &gBattleMons[battlerId]);
|
u32 side = GetBattlerSide(battlerId);
|
||||||
gBattleStruct->hpOnSwitchout[GetBattlerSide(battlerId)] = gBattleMons[battlerId].hp;
|
struct Pokemon *party = GetSideParty(side);
|
||||||
|
PokemonToBattleMon(&party[partyIndex], &gBattleMons[battlerId]);
|
||||||
|
gBattleStruct->hpOnSwitchout[side] = gBattleMons[battlerId].hp;
|
||||||
UpdateSentPokesToOpponentValue(battlerId);
|
UpdateSentPokesToOpponentValue(battlerId);
|
||||||
ClearTemporarySpeciesSpriteData(battlerId, FALSE);
|
ClearTemporarySpeciesSpriteData(battlerId, FALSE);
|
||||||
}
|
}
|
||||||
|
|
40
test/battle/ability/curious_medicine.c
Normal file
40
test/battle/ability/curious_medicine.c
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "global.h"
|
||||||
|
#include "test/battle.h"
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Curious Medicine resets ally's stat stages upon entering battle")
|
||||||
|
{
|
||||||
|
u32 ability;
|
||||||
|
|
||||||
|
PARAMETRIZE { ability = ABILITY_CURIOUS_MEDICINE; }
|
||||||
|
PARAMETRIZE { ability = ABILITY_OWN_TEMPO; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_SCOLIPEDE);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_SLOWKING_GALAR) { Ability(ability); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_QUIVER_DANCE); MOVE(playerLeft, MOVE_CHARM, target: opponentLeft); }
|
||||||
|
TURN { SWITCH(opponentRight, 2); MOVE(playerLeft, MOVE_CELEBRATE); }
|
||||||
|
} SCENE {
|
||||||
|
// Turn 1 - buff up
|
||||||
|
MESSAGE("Foe Scolipede used Quiver Dance!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||||
|
// Turn 2 - Switch into Slowking
|
||||||
|
MESSAGE("2 sent out Slowking!");
|
||||||
|
if (ability == ABILITY_CURIOUS_MEDICINE)
|
||||||
|
{
|
||||||
|
ABILITY_POPUP(opponentRight, ABILITY_CURIOUS_MEDICINE);
|
||||||
|
MESSAGE("Foe Scolipede's stat changes were reset!");
|
||||||
|
}
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_ATK], (ability == ABILITY_CURIOUS_MEDICINE) ? DEFAULT_STAT_STAGE : DEFAULT_STAT_STAGE - 2);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_SPEED], (ability == ABILITY_CURIOUS_MEDICINE) ? DEFAULT_STAT_STAGE : DEFAULT_STAT_STAGE + 1);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_SPATK], (ability == ABILITY_CURIOUS_MEDICINE) ? DEFAULT_STAT_STAGE : DEFAULT_STAT_STAGE + 1);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_SPDEF], (ability == ABILITY_CURIOUS_MEDICINE) ? DEFAULT_STAT_STAGE : DEFAULT_STAT_STAGE + 1);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_ACC], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_EVASION], DEFAULT_STAT_STAGE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,14 +27,14 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SEQUENCE_SWITCHING: AI will always switch after a
|
||||||
}
|
}
|
||||||
} SCENE {
|
} SCENE {
|
||||||
if (aiSequenceSwitchingFlag) {
|
if (aiSequenceSwitchingFlag) {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Machoke!");
|
MESSAGE(AI_TRAINER_NAME " sent out Machoke!");
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Machamp!");
|
MESSAGE(AI_TRAINER_NAME " sent out Machamp!");
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Mankey!");
|
MESSAGE(AI_TRAINER_NAME " sent out Mankey!");
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Primeape!");
|
MESSAGE(AI_TRAINER_NAME " sent out Primeape!");
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Magnezone!");
|
MESSAGE(AI_TRAINER_NAME " sent out Magnezone!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Magnezone!");
|
MESSAGE(AI_TRAINER_NAME " sent out Magnezone!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ AI_SINGLE_BATTLE_TEST("AI switches if Perish Song is about to kill")
|
||||||
TURN { ; }
|
TURN { ; }
|
||||||
TURN { EXPECT_SWITCH(opponent, 1); }
|
TURN { EXPECT_SWITCH(opponent, 1); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Crobat!");
|
MESSAGE(AI_TRAINER_NAME " sent out Crobat!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ AI_DOUBLE_BATTLE_TEST("AI will not try to switch for the same pokemon for 2 spot
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { EXPECT_SWITCH(opponentLeft, 3); };
|
TURN { EXPECT_SWITCH(opponentLeft, 3); };
|
||||||
} SCENE {
|
} SCENE {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF withdrew Gengar!");
|
MESSAGE(AI_TRAINER_NAME " withdrew Gengar!");
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
MESSAGE(AI_TRAINER_NAME " sent out Raticate!");
|
||||||
NONE_OF {
|
NONE_OF {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF withdrew Haunter!");
|
MESSAGE(AI_TRAINER_NAME " withdrew Haunter!");
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Raticate!");
|
MESSAGE(AI_TRAINER_NAME " sent out Raticate!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,9 +183,9 @@ AI_SINGLE_BATTLE_TEST("AI_FLAG_SMART_MON_CHOICES: AI will not switch in a Pokemo
|
||||||
} SCENE {
|
} SCENE {
|
||||||
MESSAGE("Foe Kadabra fainted!");
|
MESSAGE("Foe Kadabra fainted!");
|
||||||
if (alakazamFirst) {
|
if (alakazamFirst) {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Alakazam!");
|
MESSAGE(AI_TRAINER_NAME " sent out Alakazam!");
|
||||||
} else {
|
} else {
|
||||||
MESSAGE("{PKMN} TRAINER LEAF sent out Blastoise!");
|
MESSAGE(AI_TRAINER_NAME " sent out Blastoise!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "test/battle.h"
|
#include "test/battle.h"
|
||||||
|
|
||||||
// Note: Since these tests are recorded battle, they don't test the right battle controller
|
|
||||||
// behaviors. These have been tested in-game, in double, in multi, and in link battles. AI will always
|
|
||||||
// revive their first fainted party member in order.
|
|
||||||
|
|
||||||
ASSUMPTIONS
|
ASSUMPTIONS
|
||||||
{
|
{
|
||||||
ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING);
|
ASSUME(gMovesInfo[MOVE_REVIVAL_BLESSING].effect == EFFECT_REVIVAL_BLESSING);
|
||||||
|
@ -18,7 +14,7 @@ SINGLE_BATTLE_TEST("Revival Blessing revives a chosen fainted party member for t
|
||||||
PLAYER(SPECIES_WYNAUT) { HP(0); }
|
PLAYER(SPECIES_WYNAUT) { HP(0); }
|
||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { MOVE(player, MOVE_REVIVAL_BLESSING); SEND_OUT(player, 2); }
|
TURN { MOVE(player, MOVE_REVIVAL_BLESSING, partyIndex:2); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
MESSAGE("Wobbuffet used Revival Blessing!");
|
MESSAGE("Wobbuffet used Revival Blessing!");
|
||||||
MESSAGE("Wynaut was revived and is ready to fight again!");
|
MESSAGE("Wynaut was revived and is ready to fight again!");
|
||||||
|
@ -33,7 +29,7 @@ SINGLE_BATTLE_TEST("Revival Blessing revives a fainted party member for an oppon
|
||||||
OPPONENT(SPECIES_PICHU) { HP(0); }
|
OPPONENT(SPECIES_PICHU) { HP(0); }
|
||||||
OPPONENT(SPECIES_PIKACHU) { HP(0); }
|
OPPONENT(SPECIES_PIKACHU) { HP(0); }
|
||||||
} WHEN {
|
} WHEN {
|
||||||
TURN { MOVE(opponent, MOVE_REVIVAL_BLESSING); SEND_OUT(opponent, 1); }
|
TURN { MOVE(opponent, MOVE_REVIVAL_BLESSING, partyIndex:1); }
|
||||||
} SCENE {
|
} SCENE {
|
||||||
MESSAGE("Foe Raichu used Revival Blessing!");
|
MESSAGE("Foe Raichu used Revival Blessing!");
|
||||||
MESSAGE("Pichu was revived and is ready to fight again!");
|
MESSAGE("Pichu was revived and is ready to fight again!");
|
||||||
|
@ -53,57 +49,80 @@ SINGLE_BATTLE_TEST("Revival Blessing fails if no party members are fainted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: There isn't a good way to test multi battles at the moment, but
|
DOUBLE_BATTLE_TEST("Revival Blessing cannot revive a partner's party member")
|
||||||
// this PASSES in game!
|
{
|
||||||
TO_DO_BATTLE_TEST("Revival Blessing cannot revive a partner's party member");
|
KNOWN_FAILING;
|
||||||
// DOUBLE_BATTLE_TEST("Revival Blessing cannot revive a partner's party member")
|
struct BattlePokemon *user = NULL;
|
||||||
// {
|
gBattleTypeFlags |= BATTLE_TYPE_TWO_OPPONENTS;
|
||||||
// struct BattlePokemon *user;
|
PARAMETRIZE { user = opponentLeft; }
|
||||||
// gBattleTypeFlags |= BATTLE_TYPE_TWO_OPPONENTS;
|
PARAMETRIZE { user = opponentRight; }
|
||||||
// PARAMETRIZE { user = opponentLeft; }
|
GIVEN {
|
||||||
// PARAMETRIZE { user = opponentRight; }
|
ASSUME((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) != FALSE);
|
||||||
// GIVEN {
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
// ASSUME((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) != FALSE);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
// PLAYER(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
// PLAYER(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
// OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
// OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
// OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WYNAUT) { HP(0); }
|
||||||
// OPPONENT(SPECIES_WYNAUT);
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
// OPPONENT(SPECIES_WYNAUT) { HP(0); }
|
} WHEN {
|
||||||
// OPPONENT(SPECIES_WYNAUT);
|
TURN { MOVE(user, MOVE_REVIVAL_BLESSING, partyIndex:4); }
|
||||||
// } WHEN {
|
} SCENE {
|
||||||
// TURN { MOVE(user, MOVE_REVIVAL_BLESSING); }
|
if (user == opponentLeft) {
|
||||||
// } SCENE {
|
MESSAGE("Foe Wobbuffet used Revival Blessing!");
|
||||||
// if (user == opponentLeft) {
|
MESSAGE("But it failed!");
|
||||||
// MESSAGE("Foe Wobbuffet used Revival Blessing!");
|
} else {
|
||||||
// MESSAGE("But it failed!");
|
MESSAGE("Foe Wynaut used Revival Blessing!");
|
||||||
// } else {
|
MESSAGE("Wynaut was revived and is ready to fight again!");
|
||||||
// MESSAGE("Foe Wynaut used Revival Blessing!");
|
}
|
||||||
// MESSAGE("Wynaut was revived and is ready to fight again!");
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Note: The test runner gets upset about "sending out" a battler on the field,
|
DOUBLE_BATTLE_TEST("Revival Blessing doesn't prevent revived battlers from losing their turn")
|
||||||
// but this PASSES in game!
|
{
|
||||||
TO_DO_BATTLE_TEST("Revived battlers still lose their turn");
|
GIVEN {
|
||||||
// DOUBLE_BATTLE_TEST("Revived battlers still lose their turn")
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
// {
|
PLAYER(SPECIES_WYNAUT);
|
||||||
// GIVEN {
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
// PLAYER(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WYNAUT) { HP(1); }
|
||||||
// PLAYER(SPECIES_WYNAUT);
|
} WHEN {
|
||||||
// OPPONENT(SPECIES_WOBBUFFET);
|
TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentRight);
|
||||||
// OPPONENT(SPECIES_WYNAUT) { HP(1); }
|
MOVE(opponentLeft, MOVE_REVIVAL_BLESSING, partyIndex: 1); }
|
||||||
// } WHEN {
|
} SCENE {
|
||||||
// TURN { MOVE(playerLeft, MOVE_TACKLE, target: opponentRight);
|
MESSAGE("Wobbuffet used Tackle!");
|
||||||
// MOVE(opponentLeft, MOVE_REVIVAL_BLESSING);
|
MESSAGE("Foe Wynaut fainted!");
|
||||||
// SEND_OUT(opponentLeft, 1); }
|
MESSAGE("Foe Wobbuffet used Revival Blessing!");
|
||||||
// } SCENE {
|
MESSAGE("Wynaut was revived and is ready to fight again!");
|
||||||
// MESSAGE("Wobbuffet used Tackle!");
|
NOT { MESSAGE("Wynaut used Celebrate!"); }
|
||||||
// MESSAGE("Foe Wynaut fainted!");
|
}
|
||||||
// MESSAGE("Foe Wobbuffet used Revival Blessing!");
|
}
|
||||||
// MESSAGE("Wynaut was revived and is ready to fight again!");
|
|
||||||
// NOT { MESSAGE("Wynaut used Celebrate!"); }
|
DOUBLE_BATTLE_TEST("Revival Blessing correctly updates battler absent flags")
|
||||||
// }
|
{
|
||||||
// }
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_SALAMENCE) { Level(40); }
|
||||||
|
PLAYER(SPECIES_PIDGEOT) { Level(40); }
|
||||||
|
OPPONENT(SPECIES_GEODUDE) { Level(5); Ability(ABILITY_ROCK_HEAD); }
|
||||||
|
OPPONENT(SPECIES_STARLY) { Level(5); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(playerLeft, MOVE_EARTHQUAKE);
|
||||||
|
MOVE(opponentRight, MOVE_REVIVAL_BLESSING, partyIndex: 0); }
|
||||||
|
TURN { MOVE(playerLeft, MOVE_EARTHQUAKE); }
|
||||||
|
} SCENE {
|
||||||
|
// Turn 1
|
||||||
|
MESSAGE("Salamence used Earthquake!");
|
||||||
|
HP_BAR(opponentLeft);
|
||||||
|
MESSAGE("Foe Geodude fainted!");
|
||||||
|
MESSAGE("It doesn't affect Pidgeot…");
|
||||||
|
MESSAGE("It doesn't affect Foe Starly…");
|
||||||
|
MESSAGE("Foe Starly used Revival Blessing!");
|
||||||
|
MESSAGE("Geodude was revived and is ready to fight again!"); // Should have prefix but it doesn't currently.
|
||||||
|
// Turn 2
|
||||||
|
MESSAGE("Salamence used Earthquake!");
|
||||||
|
HP_BAR(opponentLeft);
|
||||||
|
MESSAGE("Foe Geodude fainted!");
|
||||||
|
MESSAGE("It doesn't affect Pidgeot…");
|
||||||
|
MESSAGE("It doesn't affect Foe Starly…");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2104,11 +2104,44 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 MoveGetFirstFainted(s32 battlerId)
|
||||||
|
{
|
||||||
|
u32 i, partySize;
|
||||||
|
struct Pokemon *party;
|
||||||
|
|
||||||
|
if ((battlerId & BIT_SIDE) == B_SIDE_PLAYER)
|
||||||
|
{
|
||||||
|
partySize = DATA.playerPartySize;
|
||||||
|
party = DATA.recordedBattle.playerParty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
partySize = DATA.opponentPartySize;
|
||||||
|
party = DATA.recordedBattle.opponentParty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through to find fainted battler.
|
||||||
|
for (i = 0; i < partySize; ++i)
|
||||||
|
{
|
||||||
|
u32 species = GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG);
|
||||||
|
if (species != SPECIES_NONE
|
||||||
|
&& species != SPECIES_EGG
|
||||||
|
&& GetMonData(&party[i], MON_DATA_HP) == 0)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns PARTY_SIZE if none found.
|
||||||
|
return PARTY_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx)
|
void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx)
|
||||||
{
|
{
|
||||||
s32 battlerId = battler - gBattleMons;
|
s32 battlerId = battler - gBattleMons;
|
||||||
u32 moveId, moveSlot;
|
u32 moveId, moveSlot;
|
||||||
s32 target;
|
s32 target;
|
||||||
|
bool32 requirePartyIndex = FALSE;
|
||||||
|
|
||||||
INVALID_IF(DATA.turnState == TURN_CLOSED, "MOVE outside TURN");
|
INVALID_IF(DATA.turnState == TURN_CLOSED, "MOVE outside TURN");
|
||||||
INVALID_IF(IsAITest() && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT, "MOVE is not allowed for opponent in AI tests. Use EXPECT_MOVE instead");
|
INVALID_IF(IsAITest() && (battlerId & BIT_SIDE) == B_SIDE_OPPONENT, "MOVE is not allowed for opponent in AI tests. Use EXPECT_MOVE instead");
|
||||||
|
@ -2116,6 +2149,14 @@ void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx)
|
||||||
MoveGetIdAndSlot(battlerId, &ctx, &moveId, &moveSlot, sourceLine);
|
MoveGetIdAndSlot(battlerId, &ctx, &moveId, &moveSlot, sourceLine);
|
||||||
target = MoveGetTarget(battlerId, moveId, &ctx, sourceLine);
|
target = MoveGetTarget(battlerId, moveId, &ctx, sourceLine);
|
||||||
|
|
||||||
|
if (gMovesInfo[moveId].effect == EFFECT_REVIVAL_BLESSING)
|
||||||
|
requirePartyIndex = MoveGetFirstFainted(battlerId) != PARTY_SIZE;
|
||||||
|
|
||||||
|
// Check party menu moves.
|
||||||
|
INVALID_IF(requirePartyIndex && !ctx.explicitPartyIndex, "%S requires explicit party index", GetMoveName(moveId));
|
||||||
|
INVALID_IF(requirePartyIndex && ctx.partyIndex >= ((battlerId & BIT_SIDE) == B_SIDE_PLAYER ? DATA.playerPartySize : DATA.opponentPartySize), \
|
||||||
|
"MOVE to invalid party index");
|
||||||
|
|
||||||
if (ctx.explicitHit)
|
if (ctx.explicitHit)
|
||||||
DATA.battleRecordTurns[DATA.turns][battlerId].hit = 1 + ctx.hit;
|
DATA.battleRecordTurns[DATA.turns][battlerId].hit = 1 + ctx.hit;
|
||||||
if (ctx.explicitCriticalHit)
|
if (ctx.explicitCriticalHit)
|
||||||
|
@ -2136,6 +2177,9 @@ void Move(u32 sourceLine, struct BattlePokemon *battler, struct MoveContext ctx)
|
||||||
PushBattlerAction(sourceLine, battlerId, RECORDED_MOVE_TARGET, target);
|
PushBattlerAction(sourceLine, battlerId, RECORDED_MOVE_TARGET, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.explicitPartyIndex)
|
||||||
|
PushBattlerAction(sourceLine, battlerId, RECORDED_PARTY_INDEX, ctx.partyIndex);
|
||||||
|
|
||||||
if (DATA.turnState == TURN_OPEN)
|
if (DATA.turnState == TURN_OPEN)
|
||||||
{
|
{
|
||||||
if (!DATA.hasExplicitSpeeds)
|
if (!DATA.hasExplicitSpeeds)
|
||||||
|
|
Loading…
Reference in a new issue