mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
Made Reflect Type handle 3rd types (#3303)
* Made Reflect Type handle 3rd types Misc: -Turned VARIOUS_TRY_REFLECT_TYPE into a callnative (BS_TryReflectType) -Introduced a macro to to check for typeless Pokémon (Pokémon who have Mystery in all 3 type slots) in battle. -Made the new BS_TryReflectType take into account the forms for Arceus and Silvally, rather than just their default form.
This commit is contained in:
parent
77e2b0dd2c
commit
cd59e055c2
@ -1456,6 +1456,11 @@
|
|||||||
.4byte \jumpInstr
|
.4byte \jumpInstr
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro tryreflecttype failInstr:req
|
||||||
|
callnative BS_TryReflectType
|
||||||
|
.4byte \failInstr
|
||||||
|
.endm
|
||||||
|
|
||||||
@ various command changed to more readable macros
|
@ various command changed to more readable macros
|
||||||
.macro cancelmultiturnmoves battler:req
|
.macro cancelmultiturnmoves battler:req
|
||||||
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES
|
various \battler, VARIOUS_CANCEL_MULTI_TURN_MOVES
|
||||||
@ -1686,11 +1691,6 @@
|
|||||||
.4byte \failInstr
|
.4byte \failInstr
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro tryreflecttype failInstr:req
|
|
||||||
various BS_ATTACKER, VARIOUS_TRY_REFLECT_TYPE
|
|
||||||
.4byte \failInstr
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.macro trysoak failInstr:req
|
.macro trysoak failInstr:req
|
||||||
various BS_ATTACKER, VARIOUS_TRY_SOAK
|
various BS_ATTACKER, VARIOUS_TRY_SOAK
|
||||||
.4byte \failInstr
|
.4byte \failInstr
|
||||||
|
@ -724,12 +724,16 @@ STATIC_ASSERT(sizeof(((struct BattleStruct *)0)->palaceFlags) * 8 >= MAX_BATTLER
|
|||||||
#define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0))
|
#define BATTLER_DAMAGED(battlerId) ((gSpecialStatuses[battlerId].physicalDmg != 0 || gSpecialStatuses[battlerId].specialDmg != 0))
|
||||||
|
|
||||||
#define IS_BATTLER_OF_TYPE(battlerId, type)((GetBattlerType(battlerId, 0) == type || GetBattlerType(battlerId, 1) == type || (GetBattlerType(battlerId, 2) != TYPE_MYSTERY && GetBattlerType(battlerId, 2) == type)))
|
#define IS_BATTLER_OF_TYPE(battlerId, type)((GetBattlerType(battlerId, 0) == type || GetBattlerType(battlerId, 1) == type || (GetBattlerType(battlerId, 2) != TYPE_MYSTERY && GetBattlerType(battlerId, 2) == type)))
|
||||||
|
|
||||||
|
#define IS_BATTLER_TYPELESS(battlerId)(GetBattlerType(battlerId, 0) == TYPE_MYSTERY && GetBattlerType(battlerId, 1) == TYPE_MYSTERY && GetBattlerType(battlerId, 2) == TYPE_MYSTERY)
|
||||||
|
|
||||||
#define SET_BATTLER_TYPE(battlerId, type) \
|
#define SET_BATTLER_TYPE(battlerId, type) \
|
||||||
{ \
|
{ \
|
||||||
gBattleMons[battlerId].type1 = type; \
|
gBattleMons[battlerId].type1 = type; \
|
||||||
gBattleMons[battlerId].type2 = type; \
|
gBattleMons[battlerId].type2 = type; \
|
||||||
gBattleMons[battlerId].type3 = TYPE_MYSTERY; \
|
gBattleMons[battlerId].type3 = TYPE_MYSTERY; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RESTORE_BATTLER_TYPE(battlerId) \
|
#define RESTORE_BATTLER_TYPE(battlerId) \
|
||||||
{ \
|
{ \
|
||||||
gBattleMons[battlerId].type1 = gSpeciesInfo[gBattleMons[battlerId].species].types[0]; \
|
gBattleMons[battlerId].type1 = gSpeciesInfo[gBattleMons[battlerId].species].types[0]; \
|
||||||
|
@ -9409,37 +9409,6 @@ static void Cmd_various(void)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case VARIOUS_TRY_REFLECT_TYPE:
|
|
||||||
{
|
|
||||||
VARIOUS_ARGS(const u8 *failInstr);
|
|
||||||
if (gBattleMons[gBattlerTarget].species == SPECIES_ARCEUS || gBattleMons[gBattlerTarget].species == SPECIES_SILVALLY)
|
|
||||||
{
|
|
||||||
gBattlescriptCurrInstr = cmd->failInstr;
|
|
||||||
}
|
|
||||||
else if (GetBattlerType(gBattlerTarget, 0) == TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) != TYPE_MYSTERY)
|
|
||||||
{
|
|
||||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 1);
|
|
||||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 1);
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
|
||||||
}
|
|
||||||
else if (GetBattlerType(gBattlerTarget, 0) != TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) == TYPE_MYSTERY)
|
|
||||||
{
|
|
||||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 0);
|
|
||||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 0);
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
|
||||||
}
|
|
||||||
else if (GetBattlerType(gBattlerTarget, 0) == TYPE_MYSTERY && GetBattlerType(gBattlerTarget, 1) == TYPE_MYSTERY)
|
|
||||||
{
|
|
||||||
gBattlescriptCurrInstr = cmd->failInstr;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gBattleMons[gBattlerAttacker].type1 = GetBattlerType(gBattlerTarget, 0);
|
|
||||||
gBattleMons[gBattlerAttacker].type2 = GetBattlerType(gBattlerTarget, 1);
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case VARIOUS_TRY_SOAK:
|
case VARIOUS_TRY_SOAK:
|
||||||
{
|
{
|
||||||
VARIOUS_ARGS(const u8 *failInstr);
|
VARIOUS_ARGS(const u8 *failInstr);
|
||||||
@ -16331,3 +16300,49 @@ void BS_JumpIfTerrainAffected(void)
|
|||||||
else
|
else
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BS_TryReflectType(void)
|
||||||
|
{
|
||||||
|
NATIVE_ARGS(const u8 *failInstr);
|
||||||
|
u16 targetBaseSpecies = GET_BASE_SPECIES_ID(gBattleMons[gBattlerTarget].species);
|
||||||
|
u8 targetType1 = GetBattlerType(gBattlerTarget, 0);
|
||||||
|
u8 targetType2 = GetBattlerType(gBattlerTarget, 1);
|
||||||
|
u8 targetType3 = GetBattlerType(gBattlerTarget, 2);
|
||||||
|
|
||||||
|
if (targetBaseSpecies == SPECIES_ARCEUS || targetBaseSpecies == SPECIES_SILVALLY)
|
||||||
|
{
|
||||||
|
gBattlescriptCurrInstr = cmd->failInstr;
|
||||||
|
}
|
||||||
|
else if (IS_BATTLER_TYPELESS(gBattlerTarget))
|
||||||
|
{
|
||||||
|
gBattlescriptCurrInstr = cmd->failInstr;
|
||||||
|
}
|
||||||
|
else if (targetType1 == TYPE_MYSTERY && targetType2 == TYPE_MYSTERY && targetType3 != TYPE_MYSTERY)
|
||||||
|
{
|
||||||
|
gBattleMons[gBattlerAttacker].type1 = TYPE_NORMAL;
|
||||||
|
gBattleMons[gBattlerAttacker].type2 = TYPE_NORMAL;
|
||||||
|
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||||
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
|
}
|
||||||
|
else if (targetType1 == TYPE_MYSTERY && targetType2 != TYPE_MYSTERY)
|
||||||
|
{
|
||||||
|
gBattleMons[gBattlerAttacker].type1 = targetType2;
|
||||||
|
gBattleMons[gBattlerAttacker].type2 = targetType2;
|
||||||
|
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||||
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
|
}
|
||||||
|
else if (targetType1 != TYPE_MYSTERY && targetType2 == TYPE_MYSTERY)
|
||||||
|
{
|
||||||
|
gBattleMons[gBattlerAttacker].type1 = targetType1;
|
||||||
|
gBattleMons[gBattlerAttacker].type2 = targetType1;
|
||||||
|
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||||
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gBattleMons[gBattlerAttacker].type1 = targetType1;
|
||||||
|
gBattleMons[gBattlerAttacker].type2 = targetType2;
|
||||||
|
gBattleMons[gBattlerAttacker].type3 = targetType3;
|
||||||
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
186
test/battle/move_effect/reflect_type.c
Normal file
186
test/battle/move_effect/reflect_type.c
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test/battle.h"
|
||||||
|
|
||||||
|
TO_DO_BATTLE_TEST("Reflect Type fails if the user is Terastallized");
|
||||||
|
TO_DO_BATTLE_TEST("Reflect Type succeeds against a Terastallized target and copies its Tera type");
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Reflect Type does not affect any of Arceus' forms")
|
||||||
|
{
|
||||||
|
u32 j;
|
||||||
|
static const u16 sArceusFormSpeciesIdTable[] = {
|
||||||
|
SPECIES_ARCEUS,
|
||||||
|
SPECIES_ARCEUS_FIGHTING,
|
||||||
|
SPECIES_ARCEUS_FLYING,
|
||||||
|
SPECIES_ARCEUS_POISON,
|
||||||
|
SPECIES_ARCEUS_GROUND,
|
||||||
|
SPECIES_ARCEUS_ROCK,
|
||||||
|
SPECIES_ARCEUS_BUG,
|
||||||
|
SPECIES_ARCEUS_GHOST,
|
||||||
|
SPECIES_ARCEUS_STEEL,
|
||||||
|
SPECIES_ARCEUS_FIRE,
|
||||||
|
SPECIES_ARCEUS_WATER,
|
||||||
|
SPECIES_ARCEUS_GRASS,
|
||||||
|
SPECIES_ARCEUS_ELECTRIC,
|
||||||
|
SPECIES_ARCEUS_PSYCHIC,
|
||||||
|
SPECIES_ARCEUS_ICE,
|
||||||
|
SPECIES_ARCEUS_DRAGON,
|
||||||
|
SPECIES_ARCEUS_DARK,
|
||||||
|
SPECIES_ARCEUS_FAIRY,
|
||||||
|
};
|
||||||
|
u16 species = SPECIES_NONE;
|
||||||
|
|
||||||
|
for (j = 0; j < ARRAY_COUNT(sArceusFormSpeciesIdTable); j++)
|
||||||
|
{
|
||||||
|
PARAMETRIZE { species = sArceusFormSpeciesIdTable[j]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(species);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Reflect Type!");
|
||||||
|
MESSAGE("But it failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Reflect Type does not affect any of Silvally's forms")
|
||||||
|
{
|
||||||
|
u32 j;
|
||||||
|
static const u16 sSilvallyFormSpeciesIdTable[] = {
|
||||||
|
SPECIES_SILVALLY,
|
||||||
|
SPECIES_SILVALLY_FIGHTING,
|
||||||
|
SPECIES_SILVALLY_FLYING,
|
||||||
|
SPECIES_SILVALLY_POISON,
|
||||||
|
SPECIES_SILVALLY_GROUND,
|
||||||
|
SPECIES_SILVALLY_ROCK,
|
||||||
|
SPECIES_SILVALLY_BUG,
|
||||||
|
SPECIES_SILVALLY_GHOST,
|
||||||
|
SPECIES_SILVALLY_STEEL,
|
||||||
|
SPECIES_SILVALLY_FIRE,
|
||||||
|
SPECIES_SILVALLY_WATER,
|
||||||
|
SPECIES_SILVALLY_GRASS,
|
||||||
|
SPECIES_SILVALLY_ELECTRIC,
|
||||||
|
SPECIES_SILVALLY_PSYCHIC,
|
||||||
|
SPECIES_SILVALLY_ICE,
|
||||||
|
SPECIES_SILVALLY_DRAGON,
|
||||||
|
SPECIES_SILVALLY_DARK,
|
||||||
|
SPECIES_SILVALLY_FAIRY,
|
||||||
|
};
|
||||||
|
u16 species = SPECIES_NONE;
|
||||||
|
|
||||||
|
for (j = 0; j < ARRAY_COUNT(sSilvallyFormSpeciesIdTable); j++)
|
||||||
|
{
|
||||||
|
PARAMETRIZE { species = sSilvallyFormSpeciesIdTable[j]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(species);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Reflect Type!");
|
||||||
|
MESSAGE("But it failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Reflect Type does not affect Pokémon with no types")
|
||||||
|
{
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[0] == TYPE_WATER);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[1] == TYPE_FIGHTING);
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_ARCANINE);
|
||||||
|
OPPONENT(SPECIES_POLIWRATH);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_BURN_UP); MOVE(opponent, MOVE_REFLECT_TYPE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Arcanine used Burn Up!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, player);
|
||||||
|
HP_BAR(opponent);
|
||||||
|
MESSAGE("Arcanine burned itself out!");
|
||||||
|
MESSAGE("Foe Poliwrath used Reflect Type!");
|
||||||
|
MESSAGE("But it failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Reflect Type copies a target's dual types")
|
||||||
|
{
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[0] == TYPE_WATER);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_POLIWRATH].types[1] == TYPE_FIGHTING);
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_ARCANINE);
|
||||||
|
OPPONENT(SPECIES_POLIWRATH);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Arcanine used Reflect Type!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, player);
|
||||||
|
MESSAGE("Arcanine's type changed to match the Foe Poliwrath's!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->type1, TYPE_WATER);
|
||||||
|
EXPECT_EQ(player->type2, TYPE_FIGHTING);
|
||||||
|
EXPECT_EQ(player->type3, TYPE_MYSTERY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Reflect Type copies a target's pure type")
|
||||||
|
{
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_SUDOWOODO].types[0] == TYPE_ROCK);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_SUDOWOODO].types[1] == TYPE_ROCK);
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_ARCANINE);
|
||||||
|
OPPONENT(SPECIES_SUDOWOODO);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Arcanine used Reflect Type!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, player);
|
||||||
|
MESSAGE("Arcanine's type changed to match the Foe Sudowoodo's!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->type1, TYPE_ROCK);
|
||||||
|
EXPECT_EQ(player->type2, TYPE_ROCK);
|
||||||
|
EXPECT_EQ(player->type3, TYPE_MYSTERY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Reflect Type defaults to Normal type for the user's type1 and type2 if the target only has a 3rd type")
|
||||||
|
{
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[0] == TYPE_PSYCHIC);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_WOBBUFFET].types[1] == TYPE_PSYCHIC);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[0] == TYPE_FIRE);
|
||||||
|
ASSUME(gSpeciesInfo[SPECIES_ARCANINE].types[1] == TYPE_FIRE);
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_ARCANINE);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_BURN_UP); }
|
||||||
|
TURN { MOVE(player, MOVE_FORESTS_CURSE); }
|
||||||
|
TURN { MOVE(player, MOVE_REFLECT_TYPE); }
|
||||||
|
} SCENE {
|
||||||
|
// Turn 1
|
||||||
|
MESSAGE("Foe Arcanine used Burn Up!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_BURN_UP, opponent);
|
||||||
|
HP_BAR(player);
|
||||||
|
MESSAGE("Foe Arcanine burned itself out!");
|
||||||
|
// Turn 2
|
||||||
|
MESSAGE("Wobbuffet used Forest'sCurs!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_FORESTS_CURSE, player);
|
||||||
|
MESSAGE("Grass type was added to Foe Arcanine!");
|
||||||
|
// Turn 3
|
||||||
|
MESSAGE("Wobbuffet used Reflect Type!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_REFLECT_TYPE, player);
|
||||||
|
MESSAGE("Wobbuffet's type changed to match the Foe Arcanine's!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->type1, TYPE_NORMAL);
|
||||||
|
EXPECT_EQ(player->type2, TYPE_NORMAL);
|
||||||
|
EXPECT_EQ(player->type3, TYPE_GRASS);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user