mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 03:34:15 +01:00
Merge branch 'RHH/master' into RHH/upcoming
# Conflicts: # .github/ISSUE_TEMPLATE/01_battle_engine_bugs.yaml # .github/ISSUE_TEMPLATE/02_battle_ai_issues.yaml # .github/ISSUE_TEMPLATE/04_other_errors.yaml
This commit is contained in:
commit
952bacd858
@ -23,8 +23,9 @@ body:
|
|||||||
label: Version
|
label: Version
|
||||||
description: What version of pokeemerald-expansion are you using as a base?
|
description: What version of pokeemerald-expansion are you using as a base?
|
||||||
options:
|
options:
|
||||||
- 1.5.1 (Default)
|
- 1.5.2 (Default)
|
||||||
- upcoming (Edge)
|
- upcoming (Edge)
|
||||||
|
- 1.5.1
|
||||||
- 1.5.0
|
- 1.5.0
|
||||||
- 1.4.3
|
- 1.4.3
|
||||||
- 1.4.2
|
- 1.4.2
|
||||||
|
@ -23,8 +23,9 @@ body:
|
|||||||
label: Version
|
label: Version
|
||||||
description: What version of pokeemerald-expansion are you using as a base?
|
description: What version of pokeemerald-expansion are you using as a base?
|
||||||
options:
|
options:
|
||||||
- 1.5.1 (Default)
|
- 1.5.2 (Default)
|
||||||
- upcoming (Edge)
|
- upcoming (Edge)
|
||||||
|
- 1.5.1
|
||||||
- 1.5.0
|
- 1.5.0
|
||||||
- 1.4.3
|
- 1.4.3
|
||||||
- 1.4.2
|
- 1.4.2
|
||||||
|
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
3
.github/ISSUE_TEMPLATE/04_other_errors.yaml
vendored
@ -23,8 +23,9 @@ body:
|
|||||||
label: Version
|
label: Version
|
||||||
description: What version of pokeemerald-expansion are you using as a base?
|
description: What version of pokeemerald-expansion are you using as a base?
|
||||||
options:
|
options:
|
||||||
- 1.5.1 (Default)
|
- 1.5.2 (Default)
|
||||||
- upcoming (Edge)
|
- upcoming (Edge)
|
||||||
|
- 1.5.1
|
||||||
- 1.5.0
|
- 1.5.0
|
||||||
- 1.4.3
|
- 1.4.3
|
||||||
- 1.4.2
|
- 1.4.2
|
||||||
|
@ -1318,7 +1318,7 @@
|
|||||||
.2byte \holdEffect
|
.2byte \holdEffect
|
||||||
.4byte \jumpInstr
|
.4byte \jumpInstr
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro dostockpilestatchangeswearoff, battler:req, statChangeInstr:req
|
.macro dostockpilestatchangeswearoff, battler:req, statChangeInstr:req
|
||||||
callnative BS_DoStockpileStatChangesWearOff
|
callnative BS_DoStockpileStatChangesWearOff
|
||||||
.byte \battler
|
.byte \battler
|
||||||
@ -1354,7 +1354,7 @@
|
|||||||
.macro setsnow
|
.macro setsnow
|
||||||
callnative BS_SetSnow
|
callnative BS_SetSnow
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro setzeffect
|
.macro setzeffect
|
||||||
callnative BS_SetZEffect
|
callnative BS_SetZEffect
|
||||||
.endm
|
.endm
|
||||||
@ -1364,12 +1364,6 @@
|
|||||||
callnative BS_TrySymbiosis
|
callnative BS_TrySymbiosis
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
@ returns TRUE or FALSE to gBattleCommunication[0]
|
|
||||||
.macro canteleport battler:req
|
|
||||||
callnative BS_CanTeleport
|
|
||||||
.byte \battler
|
|
||||||
.endm
|
|
||||||
|
|
||||||
@ returns B_SIDE_x to gBattleCommunication[0]
|
@ returns B_SIDE_x to gBattleCommunication[0]
|
||||||
.macro getbattlerside battler:req
|
.macro getbattlerside battler:req
|
||||||
callnative BS_GetBattlerSide
|
callnative BS_GetBattlerSide
|
||||||
@ -2083,7 +2077,7 @@
|
|||||||
.macro swapsidestatuses
|
.macro swapsidestatuses
|
||||||
various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES
|
various BS_ATTACKER, VARIOUS_SWAP_SIDE_STATUSES
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro swapstats stat:req
|
.macro swapstats stat:req
|
||||||
various BS_ATTACKER, VARIOUS_SWAP_STATS
|
various BS_ATTACKER, VARIOUS_SWAP_STATS
|
||||||
.byte \stat
|
.byte \stat
|
||||||
@ -2184,6 +2178,11 @@
|
|||||||
jumpifbyte CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_NO_EFFECT, \jumpInstr
|
jumpifbyte CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_NO_EFFECT, \jumpInstr
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
|
.macro jumpifside battler:req, side:req, equalJumpInstr:req
|
||||||
|
getbattlerside \battler
|
||||||
|
jumpifbyte CMP_EQUAL, gBattleCommunication, \side, \equalJumpInstr
|
||||||
|
.endm
|
||||||
|
|
||||||
.macro jumpifbattletype flags:req, jumpInstr:req
|
.macro jumpifbattletype flags:req, jumpInstr:req
|
||||||
jumpifword CMP_COMMON_BITS, gBattleTypeFlags, \flags, \jumpInstr
|
jumpifword CMP_COMMON_BITS, gBattleTypeFlags, \flags, \jumpInstr
|
||||||
.endm
|
.endm
|
||||||
|
@ -4023,6 +4023,8 @@ BattleScript_MoveMissedDoDamage::
|
|||||||
.if B_CRASH_IF_TARGET_IMMUNE < GEN_4
|
.if B_CRASH_IF_TARGET_IMMUNE < GEN_4
|
||||||
jumpifhalfword CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveEnd
|
jumpifhalfword CMP_COMMON_BITS, gMoveResultFlags, MOVE_RESULT_DOESNT_AFFECT_FOE, BattleScript_MoveEnd
|
||||||
.endif
|
.endif
|
||||||
|
moveendcase MOVEEND_PROTECT_LIKE_EFFECT @ Spiky Shield's damage happens before recoil.
|
||||||
|
jumpifhasnohp BS_ATTACKER, BattleScript_MoveEnd
|
||||||
printstring STRINGID_PKMNCRASHED
|
printstring STRINGID_PKMNCRASHED
|
||||||
waitmessage B_WAIT_TIME_LONG
|
waitmessage B_WAIT_TIME_LONG
|
||||||
damagecalc
|
damagecalc
|
||||||
@ -5300,15 +5302,14 @@ BattleScript_EffectHurricane:
|
|||||||
BattleScript_EffectTeleport:
|
BattleScript_EffectTeleport:
|
||||||
attackcanceler
|
attackcanceler
|
||||||
attackstring
|
attackstring
|
||||||
ppreduce
|
|
||||||
.if B_TELEPORT_BEHAVIOR >= GEN_7
|
.if B_TELEPORT_BEHAVIOR >= GEN_7
|
||||||
canteleport BS_ATTACKER
|
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_EffectBatonPass
|
||||||
jumpifbyte CMP_EQUAL, gBattleCommunication, TRUE, BattleScript_EffectTeleportNew
|
jumpifside BS_ATTACKER, B_SIDE_PLAYER, BattleScript_EffectBatonPass
|
||||||
goto BattleScript_ButItFailed
|
|
||||||
.else
|
.else
|
||||||
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_ButItFailed
|
jumpifbattletype BATTLE_TYPE_TRAINER, BattleScript_ButItFailed
|
||||||
.endif
|
.endif
|
||||||
BattleScript_EffectTeleportTryToRunAway:
|
BattleScript_EffectTeleportTryToRunAway:
|
||||||
|
ppreduce
|
||||||
getifcantrunfrombattle BS_ATTACKER
|
getifcantrunfrombattle BS_ATTACKER
|
||||||
jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FORBIDDEN, BattleScript_ButItFailed
|
jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FORBIDDEN, BattleScript_ButItFailed
|
||||||
jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FAILURE, BattleScript_PrintAbilityMadeIneffective
|
jumpifbyte CMP_EQUAL, gBattleCommunication, BATTLE_RUN_FAILURE, BattleScript_PrintAbilityMadeIneffective
|
||||||
@ -5319,29 +5320,6 @@ BattleScript_EffectTeleportTryToRunAway:
|
|||||||
setoutcomeonteleport BS_ATTACKER
|
setoutcomeonteleport BS_ATTACKER
|
||||||
goto BattleScript_MoveEnd
|
goto BattleScript_MoveEnd
|
||||||
|
|
||||||
BattleScript_EffectTeleportNew:
|
|
||||||
getbattlerside BS_ATTACKER
|
|
||||||
jumpifbyte CMP_EQUAL, gBattleCommunication, B_SIDE_OPPONENT, BattleScript_EffectTeleportTryToRunAway
|
|
||||||
attackanimation
|
|
||||||
waitanimation
|
|
||||||
openpartyscreen BS_ATTACKER, BattleScript_EffectTeleportNewEnd
|
|
||||||
switchoutabilities BS_ATTACKER
|
|
||||||
waitstate
|
|
||||||
switchhandleorder BS_ATTACKER, 2
|
|
||||||
returntoball BS_ATTACKER
|
|
||||||
getswitchedmondata BS_ATTACKER
|
|
||||||
switchindataupdate BS_ATTACKER
|
|
||||||
hpthresholds BS_ATTACKER
|
|
||||||
trytoclearprimalweather
|
|
||||||
printstring STRINGID_EMPTYSTRING3
|
|
||||||
waitmessage 1
|
|
||||||
printstring STRINGID_SWITCHINMON
|
|
||||||
switchinanim BS_ATTACKER, TRUE
|
|
||||||
waitstate
|
|
||||||
switchineffects BS_ATTACKER
|
|
||||||
BattleScript_EffectTeleportNewEnd:
|
|
||||||
goto BattleScript_MoveEnd
|
|
||||||
|
|
||||||
BattleScript_EffectBeatUp::
|
BattleScript_EffectBeatUp::
|
||||||
attackcanceler
|
attackcanceler
|
||||||
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
|
||||||
|
@ -212,6 +212,7 @@ struct SideTimer
|
|||||||
u8 toxicSpikesAmount;
|
u8 toxicSpikesAmount;
|
||||||
u8 stealthRockAmount;
|
u8 stealthRockAmount;
|
||||||
u8 stickyWebAmount;
|
u8 stickyWebAmount;
|
||||||
|
u8 stickyWebBattlerId;
|
||||||
u8 stickyWebBattlerSide; // Used for Court Change
|
u8 stickyWebBattlerSide; // Used for Court Change
|
||||||
u8 auroraVeilTimer;
|
u8 auroraVeilTimer;
|
||||||
u8 auroraVeilBattlerId;
|
u8 auroraVeilBattlerId;
|
||||||
@ -642,7 +643,6 @@ struct BattleStruct
|
|||||||
u8 forcedSwitch:4; // For each battler
|
u8 forcedSwitch:4; // For each battler
|
||||||
u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler
|
u8 switchInAbilityPostponed:4; // To not activate against an empty field, each bit for battler
|
||||||
u8 ballSpriteIds[2]; // item gfx, window gfx
|
u8 ballSpriteIds[2]; // item gfx, window gfx
|
||||||
u8 stickyWebUser;
|
|
||||||
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
||||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||||
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
||||||
|
@ -151,7 +151,7 @@ static void InitSinglePlayerBtlControllers(void)
|
|||||||
|
|
||||||
gBattlerPartyIndexes[0] = 0;
|
gBattlerPartyIndexes[0] = 0;
|
||||||
gBattlerPartyIndexes[1] = 0;
|
gBattlerPartyIndexes[1] = 0;
|
||||||
if (BATTLE_TWO_VS_ONE_OPPONENT)
|
if (BATTLE_TWO_VS_ONE_OPPONENT || WILD_DOUBLE_BATTLE)
|
||||||
{
|
{
|
||||||
gBattlerPartyIndexes[2] = 3;
|
gBattlerPartyIndexes[2] = 3;
|
||||||
gBattlerPartyIndexes[3] = 1;
|
gBattlerPartyIndexes[3] = 1;
|
||||||
|
@ -3187,7 +3187,10 @@ static void BattleStartClearSetData(void)
|
|||||||
|
|
||||||
gBattleStruct->mega.triggerSpriteId = 0xFF;
|
gBattleStruct->mega.triggerSpriteId = 0xFF;
|
||||||
|
|
||||||
gBattleStruct->stickyWebUser = 0xFF;
|
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||||
|
{
|
||||||
|
gSideTimers[i].stickyWebBattlerId = 0xFF;
|
||||||
|
}
|
||||||
gBattleStruct->appearedInBattle = 0;
|
gBattleStruct->appearedInBattle = 0;
|
||||||
gBattleStruct->beatUpSlot = 0;
|
gBattleStruct->beatUpSlot = 0;
|
||||||
|
|
||||||
@ -3293,8 +3296,12 @@ void SwitchInClearSetData(void)
|
|||||||
gBattleStruct->lastMoveFailed &= ~(gBitTable[gActiveBattler]);
|
gBattleStruct->lastMoveFailed &= ~(gBitTable[gActiveBattler]);
|
||||||
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
|
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
|
||||||
|
|
||||||
if (gActiveBattler == gBattleStruct->stickyWebUser)
|
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||||
gBattleStruct->stickyWebUser = 0xFF; // Switched into sticky web user slot so reset it
|
{
|
||||||
|
// Switched into sticky web user slot, so reset stored battler ID
|
||||||
|
if (gSideTimers[i].stickyWebBattlerId == gActiveBattler)
|
||||||
|
gSideTimers[i].stickyWebBattlerId = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < gBattlersCount; i++)
|
for (i = 0; i < gBattlersCount; i++)
|
||||||
{
|
{
|
||||||
@ -3407,8 +3414,12 @@ void FaintClearSetData(void)
|
|||||||
|
|
||||||
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
|
gBattleStruct->palaceFlags &= ~(gBitTable[gActiveBattler]);
|
||||||
|
|
||||||
if (gActiveBattler == gBattleStruct->stickyWebUser)
|
for (i = 0; i < ARRAY_COUNT(gSideTimers); i++)
|
||||||
gBattleStruct->stickyWebUser = 0xFF; // User of sticky web fainted, so reset the stored battler ID
|
{
|
||||||
|
// User of sticky web fainted, so reset the stored battler ID
|
||||||
|
if (gSideTimers[i].stickyWebBattlerId == gActiveBattler)
|
||||||
|
gSideTimers[i].stickyWebBattlerId = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < gBattlersCount; i++)
|
for (i = 0; i < gBattlersCount; i++)
|
||||||
{
|
{
|
||||||
@ -4601,7 +4612,11 @@ static void HandleTurnActionSelectionState(void)
|
|||||||
{
|
{
|
||||||
// if we choose to throw a ball with our second mon, skip the action of the first
|
// if we choose to throw a ball with our second mon, skip the action of the first
|
||||||
// (if we have chosen throw ball with first, second's is already skipped)
|
// (if we have chosen throw ball with first, second's is already skipped)
|
||||||
gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] = B_ACTION_NOTHING_FAINTED;
|
// if throwing a ball in a wild battle with an in-game partner, skip partner's turn when throwing a ball
|
||||||
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||||
|
gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)] = B_ACTION_NOTHING_FAINTED;
|
||||||
|
else
|
||||||
|
gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] = B_ACTION_NOTHING_FAINTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
gBattleMainFunc = SetActionsAndBattlersTurnOrder;
|
gBattleMainFunc = SetActionsAndBattlersTurnOrder;
|
||||||
|
@ -142,8 +142,8 @@ static const u8 sText_PkmnRaisedSpDefALittle[] = _("{B_ATK_PREFIX2}'s {B_CURRENT
|
|||||||
static const u8 sText_PkmnRaisedDef[] = _("{B_ATK_PREFIX2}'s {B_CURRENT_MOVE}\nraised DEFENSE!");
|
static const u8 sText_PkmnRaisedDef[] = _("{B_ATK_PREFIX2}'s {B_CURRENT_MOVE}\nraised DEFENSE!");
|
||||||
static const u8 sText_PkmnRaisedDefALittle[] = _("{B_ATK_PREFIX2}'s {B_CURRENT_MOVE}\nraised DEFENSE a little!");
|
static const u8 sText_PkmnRaisedDefALittle[] = _("{B_ATK_PREFIX2}'s {B_CURRENT_MOVE}\nraised DEFENSE a little!");
|
||||||
static const u8 sText_PkmnCoveredByVeil[] = _("{B_ATK_PREFIX2}'s party is covered\nby a veil!");
|
static const u8 sText_PkmnCoveredByVeil[] = _("{B_ATK_PREFIX2}'s party is covered\nby a veil!");
|
||||||
static const u8 sText_PkmnUsedSafeguard[] = _("{B_DEF_NAME_WITH_PREFIX}'s party is protected\nby SAFEGUARD!");
|
static const u8 sText_PkmnUsedSafeguard[] = _("{B_DEF_NAME_WITH_PREFIX}'s party is protected\nby Safeguard!");
|
||||||
static const u8 sText_PkmnSafeguardExpired[] = _("{B_ATK_PREFIX3}'s party is no longer\nprotected by SAFEGUARD!");
|
static const u8 sText_PkmnSafeguardExpired[] = _("{B_ATK_PREFIX3}'s party is no longer\nprotected by Safeguard!");
|
||||||
static const u8 sText_PkmnWentToSleep[] = _("{B_ATK_NAME_WITH_PREFIX} went\nto sleep!");
|
static const u8 sText_PkmnWentToSleep[] = _("{B_ATK_NAME_WITH_PREFIX} went\nto sleep!");
|
||||||
static const u8 sText_PkmnSleptHealthy[] = _("{B_ATK_NAME_WITH_PREFIX} slept and\nbecame healthy!");
|
static const u8 sText_PkmnSleptHealthy[] = _("{B_ATK_NAME_WITH_PREFIX} slept and\nbecame healthy!");
|
||||||
static const u8 sText_PkmnWhippedWhirlwind[] = _("{B_ATK_NAME_WITH_PREFIX} whipped\nup a whirlwind!");
|
static const u8 sText_PkmnWhippedWhirlwind[] = _("{B_ATK_NAME_WITH_PREFIX} whipped\nup a whirlwind!");
|
||||||
@ -2700,7 +2700,7 @@ void BufferStringBattle(u16 stringID)
|
|||||||
{
|
{
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
|
if (gBattleTypeFlags & BATTLE_TYPE_LEGENDARY)
|
||||||
stringPtr = sText_LegendaryPkmnAppeared;
|
stringPtr = sText_LegendaryPkmnAppeared;
|
||||||
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[BATTLE_PARTNER(gActiveBattler)]])) // interesting, looks like they had something planned for wild double battles
|
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && IsValidForBattle(&gEnemyParty[gBattlerPartyIndexes[GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT)]]))
|
||||||
stringPtr = sText_TwoWildPkmnAppeared;
|
stringPtr = sText_TwoWildPkmnAppeared;
|
||||||
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
|
else if (gBattleTypeFlags & BATTLE_TYPE_WALLY_TUTORIAL)
|
||||||
stringPtr = sText_WildPkmnAppearedPause;
|
stringPtr = sText_WildPkmnAppearedPause;
|
||||||
|
@ -8549,8 +8549,9 @@ static bool32 IsTeatimeAffected(u32 battlerId)
|
|||||||
|
|
||||||
#define UPDATE_COURTCHANGED_BATTLER(structField)\
|
#define UPDATE_COURTCHANGED_BATTLER(structField)\
|
||||||
{ \
|
{ \
|
||||||
sideTimerPlayer->structField ^= BIT_SIDE; \
|
temp = sideTimerPlayer->structField; \
|
||||||
sideTimerOpp->structField ^= BIT_SIDE; \
|
sideTimerPlayer->structField = BATTLE_OPPOSITE(sideTimerOpp->structField); \
|
||||||
|
sideTimerOpp->structField = BATTLE_OPPOSITE(temp); \
|
||||||
} \
|
} \
|
||||||
|
|
||||||
static bool32 CourtChangeSwapSideStatuses(void)
|
static bool32 CourtChangeSwapSideStatuses(void)
|
||||||
@ -8585,9 +8586,7 @@ static bool32 CourtChangeSwapSideStatuses(void)
|
|||||||
UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId);
|
UPDATE_COURTCHANGED_BATTLER(auroraVeilBattlerId);
|
||||||
UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId);
|
UPDATE_COURTCHANGED_BATTLER(tailwindBattlerId);
|
||||||
UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId);
|
UPDATE_COURTCHANGED_BATTLER(luckyChantBattlerId);
|
||||||
|
UPDATE_COURTCHANGED_BATTLER(stickyWebBattlerId);
|
||||||
// For Mirror Armor only
|
|
||||||
gBattleStruct->stickyWebUser = gBattlerAttacker;
|
|
||||||
|
|
||||||
// Track which side originally set the Sticky Web
|
// Track which side originally set the Sticky Web
|
||||||
SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp);
|
SWAP(sideTimerPlayer->stickyWebBattlerSide, sideTimerOpp->stickyWebBattlerSide, temp);
|
||||||
@ -8627,33 +8626,6 @@ static void HandleScriptMegaPrimal(u32 caseId, u32 battlerId, bool32 isMega)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool32 CanTeleport(u8 battlerId)
|
|
||||||
{
|
|
||||||
struct Pokemon *party = GetBattlerParty(battlerId);
|
|
||||||
u32 species, count, i;
|
|
||||||
|
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
|
||||||
{
|
|
||||||
species = GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG);
|
|
||||||
if (species != SPECIES_NONE && species != SPECIES_EGG && GetMonData(&party[i], MON_DATA_HP) != 0)
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (GetBattlerSide(battlerId))
|
|
||||||
{
|
|
||||||
case B_SIDE_OPPONENT:
|
|
||||||
if (count == 1 || gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
|
||||||
return FALSE;
|
|
||||||
break;
|
|
||||||
case B_SIDE_PLAYER:
|
|
||||||
if (count == 1 || (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && count <= 2))
|
|
||||||
return FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return True if the order was changed, and false if the order was not changed(for example because the target would move after the attacker anyway).
|
// Return True if the order was changed, and false if the order was not changed(for example because the target would move after the attacker anyway).
|
||||||
static bool32 ChangeOrderTargetAfterAttacker(void)
|
static bool32 ChangeOrderTargetAfterAttacker(void)
|
||||||
{
|
{
|
||||||
@ -10602,8 +10574,8 @@ static void Cmd_various(void)
|
|||||||
// If Pokémon which set up Sticky Web is not on the field, no Pokémon have their Speed lowered."
|
// If Pokémon which set up Sticky Web is not on the field, no Pokémon have their Speed lowered."
|
||||||
gBattlerAttacker = gBattlerTarget; // Initialize 'fail' condition
|
gBattlerAttacker = gBattlerTarget; // Initialize 'fail' condition
|
||||||
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
SET_STATCHANGER(STAT_SPEED, 1, TRUE);
|
||||||
if (gBattleStruct->stickyWebUser != 0xFF)
|
if (gSideTimers[GetBattlerSide(gActiveBattler)].stickyWebBattlerId != 0xFF)
|
||||||
gBattlerAttacker = gBattleStruct->stickyWebUser;
|
gBattlerAttacker = gSideTimers[GetBattlerSide(gActiveBattler)].stickyWebBattlerId;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VARIOUS_CUT_1_3_HP_RAISE_STATS:
|
case VARIOUS_CUT_1_3_HP_RAISE_STATS:
|
||||||
@ -13865,9 +13837,9 @@ static void Cmd_setstickyweb(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB;
|
gSideStatuses[targetSide] |= SIDE_STATUS_STICKY_WEB;
|
||||||
|
gSideTimers[targetSide].stickyWebBattlerId = gBattlerAttacker; // For Mirror Armor
|
||||||
gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side
|
gSideTimers[targetSide].stickyWebBattlerSide = GetBattlerSide(gBattlerAttacker); // For Court Change/Defiant - set this to the user's side
|
||||||
gSideTimers[targetSide].stickyWebAmount = 1;
|
gSideTimers[targetSide].stickyWebAmount = 1;
|
||||||
gBattleStruct->stickyWebUser = gBattlerAttacker; // For Mirror Armor
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16132,13 +16104,6 @@ void BS_GetBattlerSide(void)
|
|||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BS_CanTeleport(void)
|
|
||||||
{
|
|
||||||
NATIVE_ARGS(u8 battler);
|
|
||||||
gBattleCommunication[0] = CanTeleport(cmd->battler);
|
|
||||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BS_TrySymbiosis(void)
|
void BS_TrySymbiosis(void)
|
||||||
{
|
{
|
||||||
NATIVE_ARGS();
|
NATIVE_ARGS();
|
||||||
|
@ -3823,14 +3823,15 @@ u8 AtkCanceller_UnableToUseMove2(void)
|
|||||||
|
|
||||||
bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
||||||
{
|
{
|
||||||
u8 playerId, flankId;
|
u32 i, side, playerId, flankId;
|
||||||
struct Pokemon *party;
|
struct Pokemon *party;
|
||||||
s32 i;
|
|
||||||
|
|
||||||
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (BATTLE_TWO_VS_ONE_OPPONENT && GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
side = GetBattlerSide(battler);
|
||||||
|
|
||||||
|
if (BATTLE_TWO_VS_ONE_OPPONENT && side == B_SIDE_OPPONENT)
|
||||||
{
|
{
|
||||||
flankId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
flankId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
||||||
playerId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
playerId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
||||||
@ -3843,9 +3844,7 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
|||||||
|
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (GetMonData(&party[i], MON_DATA_HP) != 0
|
if (IsValidForBattle(&party[i])
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
|
||||||
&& i != partyIdBattlerOn1 && i != partyIdBattlerOn2
|
&& i != partyIdBattlerOn1 && i != partyIdBattlerOn2
|
||||||
&& i != *(gBattleStruct->monToSwitchIntoId + flankId) && i != playerId[gBattleStruct->monToSwitchIntoId])
|
&& i != *(gBattleStruct->monToSwitchIntoId + flankId) && i != playerId[gBattleStruct->monToSwitchIntoId])
|
||||||
break;
|
break;
|
||||||
@ -3855,22 +3854,41 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
|||||||
else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
else if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
|
||||||
{
|
{
|
||||||
party = GetBattlerParty(battler);
|
party = GetBattlerParty(battler);
|
||||||
|
if (side == B_SIDE_OPPONENT && WILD_DOUBLE_BATTLE)
|
||||||
playerId = ((battler & BIT_FLANK) / 2);
|
|
||||||
for (i = playerId * MULTI_PARTY_SIZE; i < playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE; i++)
|
|
||||||
{
|
{
|
||||||
if (GetMonData(&party[i], MON_DATA_HP) != 0
|
flankId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
playerId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG)
|
|
||||||
break;
|
if (partyIdBattlerOn1 == PARTY_SIZE)
|
||||||
|
partyIdBattlerOn1 = gBattlerPartyIndexes[flankId];
|
||||||
|
if (partyIdBattlerOn2 == PARTY_SIZE)
|
||||||
|
partyIdBattlerOn2 = gBattlerPartyIndexes[playerId];
|
||||||
|
|
||||||
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (IsValidForBattle(&party[i])
|
||||||
|
&& i != partyIdBattlerOn1 && i != partyIdBattlerOn2
|
||||||
|
&& i != *(gBattleStruct->monToSwitchIntoId + flankId) && i != playerId[gBattleStruct->monToSwitchIntoId])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (i == PARTY_SIZE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playerId = ((battler & BIT_FLANK) / 2);
|
||||||
|
for (i = playerId * MULTI_PARTY_SIZE; i < playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE; i++)
|
||||||
|
{
|
||||||
|
if (IsValidForBattle(&party[i]))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (i == playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE);
|
||||||
}
|
}
|
||||||
return (i == playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE);
|
|
||||||
}
|
}
|
||||||
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
|
||||||
{
|
{
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_TOWER_LINK_MULTI)
|
if (gBattleTypeFlags & BATTLE_TYPE_TOWER_LINK_MULTI)
|
||||||
{
|
{
|
||||||
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
|
if (side == B_SIDE_PLAYER)
|
||||||
{
|
{
|
||||||
party = gPlayerParty;
|
party = gPlayerParty;
|
||||||
flankId = GetBattlerMultiplayerId(battler);
|
flankId = GetBattlerMultiplayerId(battler);
|
||||||
@ -3894,14 +3912,12 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
|||||||
|
|
||||||
for (i = playerId * MULTI_PARTY_SIZE; i < playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE; i++)
|
for (i = playerId * MULTI_PARTY_SIZE; i < playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (GetMonData(&party[i], MON_DATA_HP) != 0
|
if (IsValidForBattle(&party[i]))
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (i == playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE);
|
return (i == playerId * MULTI_PARTY_SIZE + MULTI_PARTY_SIZE);
|
||||||
}
|
}
|
||||||
else if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
else if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && side == B_SIDE_OPPONENT)
|
||||||
{
|
{
|
||||||
party = gEnemyParty;
|
party = gEnemyParty;
|
||||||
|
|
||||||
@ -3912,16 +3928,14 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
|||||||
|
|
||||||
for (i = playerId; i < playerId + MULTI_PARTY_SIZE; i++)
|
for (i = playerId; i < playerId + MULTI_PARTY_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (GetMonData(&party[i], MON_DATA_HP) != 0
|
if (IsValidForBattle(&party[i]))
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (i == playerId + 3);
|
return (i == playerId + 3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
|
if (side == B_SIDE_OPPONENT)
|
||||||
{
|
{
|
||||||
flankId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
flankId = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
|
||||||
playerId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
playerId = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
||||||
@ -3941,9 +3955,7 @@ bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
|
|||||||
|
|
||||||
for (i = 0; i < PARTY_SIZE; i++)
|
for (i = 0; i < PARTY_SIZE; i++)
|
||||||
{
|
{
|
||||||
if (GetMonData(&party[i], MON_DATA_HP) != 0
|
if (IsValidForBattle(&party[i])
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_NONE
|
|
||||||
&& GetMonData(&party[i], MON_DATA_SPECIES_OR_EGG) != SPECIES_EGG
|
|
||||||
&& i != partyIdBattlerOn1 && i != partyIdBattlerOn2
|
&& i != partyIdBattlerOn1 && i != partyIdBattlerOn2
|
||||||
&& i != *(gBattleStruct->monToSwitchIntoId + flankId) && i != playerId[gBattleStruct->monToSwitchIntoId])
|
&& i != *(gBattleStruct->monToSwitchIntoId + flankId) && i != playerId[gBattleStruct->monToSwitchIntoId])
|
||||||
break;
|
break;
|
||||||
@ -7954,7 +7966,7 @@ u8 IsMonDisobedient(void)
|
|||||||
|
|
||||||
if (IsBattlerModernFatefulEncounter(gBattlerAttacker)) // only false if illegal Mew or Deoxys
|
if (IsBattlerModernFatefulEncounter(gBattlerAttacker)) // only false if illegal Mew or Deoxys
|
||||||
{
|
{
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(gBattlerAttacker) == 2)
|
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(gBattlerAttacker) == B_POSITION_PLAYER_RIGHT)
|
||||||
return 0;
|
return 0;
|
||||||
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
|
||||||
return 0;
|
return 0;
|
||||||
|
0
src/script_pokemon_util.c
Executable file → Normal file
0
src/script_pokemon_util.c
Executable file → Normal file
202
test/ability_mirror_armor.c
Normal file
202
test/ability_mirror_armor.c
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test_battle.h"
|
||||||
|
|
||||||
|
ASSUMPTIONS
|
||||||
|
{
|
||||||
|
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor lowers a stat of the attacking pokemon")
|
||||||
|
{
|
||||||
|
u16 move, statId;
|
||||||
|
|
||||||
|
PARAMETRIZE { move = MOVE_LEER; statId = STAT_DEF; }
|
||||||
|
PARAMETRIZE { move = MOVE_GROWL; statId = STAT_ATK; }
|
||||||
|
PARAMETRIZE { move = MOVE_SWEET_SCENT; statId = STAT_EVASION; }
|
||||||
|
PARAMETRIZE { move = MOVE_SAND_ATTACK; statId = STAT_ACC; }
|
||||||
|
PARAMETRIZE { move = MOVE_CONFIDE; statId = STAT_SPATK; }
|
||||||
|
PARAMETRIZE { move = MOVE_FAKE_TEARS; statId = STAT_SPDEF; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR);}
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, move); }
|
||||||
|
} SCENE {
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
switch (statId)
|
||||||
|
{
|
||||||
|
case STAT_DEF:
|
||||||
|
MESSAGE("Foe Wynaut's Defense fell!");
|
||||||
|
break;
|
||||||
|
case STAT_ATK:
|
||||||
|
MESSAGE("Foe Wynaut's Attack fell!");
|
||||||
|
break;
|
||||||
|
case STAT_EVASION:
|
||||||
|
MESSAGE("Foe Wynaut's evasiveness harshly fell!");
|
||||||
|
break;
|
||||||
|
case STAT_ACC:
|
||||||
|
MESSAGE("Foe Wynaut's accuracy fell!");
|
||||||
|
break;
|
||||||
|
case STAT_SPATK:
|
||||||
|
MESSAGE("Foe Wynaut's Sp. Atk fell!");
|
||||||
|
break;
|
||||||
|
case STAT_SPDEF:
|
||||||
|
MESSAGE("Foe Wynaut's Sp. Def harshly fell!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[statId], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[statId], (statId == STAT_SPDEF || statId == STAT_EVASION) ? DEFAULT_STAT_STAGE - 2 : DEFAULT_STAT_STAGE - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor triggers even if the attacking Pokemon also has Mirror Armor ability")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||||
|
OPPONENT(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_LEER); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Corviknigh used Leer!");
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Corviknigh's Defense fell!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stats of an attacking Pokemon with the Clear Body ability")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||||
|
OPPONENT(SPECIES_WYNAUT) { Ability(ABILITY_CLEAR_BODY); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_LEER); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Wynaut used Leer!");
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
ABILITY_POPUP(opponent, ABILITY_CLEAR_BODY);
|
||||||
|
MESSAGE("Foe Wynaut's Clear Body prevents stat loss!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor lowers the Attack of Pokemon with Intimidate")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||||
|
OPPONENT(SPECIES_GYARADOS) { Ability(ABILITY_INTIMIDATE); }
|
||||||
|
} WHEN {
|
||||||
|
TURN {}
|
||||||
|
} SCENE {
|
||||||
|
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Gyarados's Attack fell!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_ATK], DEFAULT_STAT_STAGE - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsure whether this should or should not fail, as Showdown has conflicting information. Needs testing in gen8 games.
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stats of an attacking Pokemon behind Substitute")
|
||||||
|
{
|
||||||
|
KNOWN_FAILING;
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); }
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_SUBSTITUTE); }
|
||||||
|
TURN { MOVE(opponent, MOVE_LEER); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Wynaut used Substitute!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
|
||||||
|
MESSAGE("Foe Wynaut used Leer!");
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor raises the stat of an attacking Pokemon with Contrary")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR);}
|
||||||
|
OPPONENT(SPECIES_SHUCKLE) {Ability(ABILITY_CONTRARY);}
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_LEER); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Shuckle used Leer!");
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Shuckle's Defense rose!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Mirror Armor doesn't lower the stat of the attacking Pokemon if it is already at -6")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR);}
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_SCREECH); }
|
||||||
|
TURN { MOVE(player, MOVE_SCREECH); }
|
||||||
|
TURN { MOVE(player, MOVE_SCREECH); }
|
||||||
|
TURN { MOVE(opponent, MOVE_LEER); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Corviknigh used Screech!");
|
||||||
|
MESSAGE("Corviknigh used Screech!");
|
||||||
|
MESSAGE("Corviknigh used Screech!");
|
||||||
|
MESSAGE("Foe Wynaut used Leer!");
|
||||||
|
ABILITY_POPUP(player, ABILITY_MIRROR_ARMOR);
|
||||||
|
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wynaut's Defense won't go lower!");
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponent->statStages[STAT_DEF], MIN_STAT_STAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This behaviour needs to be verified in the actual games. Currently it's written to follow Showdown's logic.
|
||||||
|
DOUBLE_BATTLE_TEST("Mirror Armor lowers Speed of the partner Pokemon after Court Change was used by the opponent after it set up Sticky Web")
|
||||||
|
{
|
||||||
|
KNOWN_FAILING;
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(gBattleMoves[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB);
|
||||||
|
ASSUME(gBattleMoves[MOVE_COURT_CHANGE].effect == EFFECT_COURT_CHANGE);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); }
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(playerLeft, MOVE_STICKY_WEB); }
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); }
|
||||||
|
TURN { SWITCH(playerRight, 2);}
|
||||||
|
TURN { }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Sticky Web!");
|
||||||
|
MESSAGE("Foe Wynaut used Court Change!");
|
||||||
|
MESSAGE("Foe Wynaut swapped the battle effects affecting each side!");
|
||||||
|
MESSAGE("Go! Corviknigh!");
|
||||||
|
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||||
|
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||||
|
MESSAGE("Wobbuffet's Speed fell!");
|
||||||
|
}
|
||||||
|
}
|
@ -112,7 +112,7 @@ SINGLE_BATTLE_TEST("Berserk Gene does not confuse when Safeguard is active")
|
|||||||
} SCENE {
|
} SCENE {
|
||||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||||
MESSAGE("Using Berserk Gene, the Attack of Wobbuffet sharply rose!");
|
MESSAGE("Using Berserk Gene, the Attack of Wobbuffet sharply rose!");
|
||||||
MESSAGE("Wobbuffet's party is protected by SAFEGUARD!");
|
MESSAGE("Wobbuffet's party is protected by Safeguard!");
|
||||||
NOT MESSAGE("Wobbuffet became confused!");
|
NOT MESSAGE("Wobbuffet became confused!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
153
test/move_effect_court_change.c
Normal file
153
test/move_effect_court_change.c
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test_battle.h"
|
||||||
|
|
||||||
|
ASSUMPTIONS
|
||||||
|
{
|
||||||
|
ASSUME(gBattleMoves[MOVE_COURT_CHANGE].effect == EFFECT_COURT_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the opponent")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); MOVE(opponentRight, MOVE_STEALTH_ROCK); }
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_SPIKES); MOVE(opponentRight, MOVE_TOXIC_SPIKES); }
|
||||||
|
TURN { MOVE(playerLeft, MOVE_COURT_CHANGE); }
|
||||||
|
TURN { SWITCH(playerLeft, 2); SWITCH(opponentLeft, 2); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Wobbuffet used Sticky Web!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Stealth Rock!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Spikes!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Toxic Spikes!");
|
||||||
|
MESSAGE("Wynaut used Court Change!");
|
||||||
|
MESSAGE("Wynaut swapped the battle effects affecting each side!");
|
||||||
|
MESSAGE("Go! Wynaut!");
|
||||||
|
NONE_OF {
|
||||||
|
MESSAGE("Wynaut is hurt by spikes!");
|
||||||
|
MESSAGE("Pointed stones dug into Wynaut!");
|
||||||
|
MESSAGE("Wynaut was poisoned!");
|
||||||
|
MESSAGE("Wynaut was caught in a Sticky Web!");
|
||||||
|
}
|
||||||
|
MESSAGE("2 sent out Wobbuffet!");
|
||||||
|
MESSAGE("Foe Wobbuffet is hurt by spikes!");
|
||||||
|
MESSAGE("Pointed stones dug into Foe Wobbuffet!");
|
||||||
|
MESSAGE("Foe Wobbuffet was poisoned!");
|
||||||
|
MESSAGE("Foe Wobbuffet was caught in a Sticky Web!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Court Change swaps entry hazards used by the player")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(playerLeft, MOVE_STICKY_WEB); MOVE(playerRight, MOVE_STEALTH_ROCK); }
|
||||||
|
TURN { MOVE(playerLeft, MOVE_SPIKES); MOVE(playerRight, MOVE_TOXIC_SPIKES); }
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); }
|
||||||
|
TURN { SWITCH(opponentLeft, 2); SWITCH(playerLeft, 2); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Sticky Web!");
|
||||||
|
MESSAGE("Wobbuffet used Stealth Rock!");
|
||||||
|
MESSAGE("Wobbuffet used Spikes!");
|
||||||
|
MESSAGE("Wobbuffet used Toxic Spikes!");
|
||||||
|
MESSAGE("Foe Wynaut used Court Change!");
|
||||||
|
MESSAGE("Foe Wynaut swapped the battle effects affecting each side!");
|
||||||
|
MESSAGE("Go! Wobbuffet!");
|
||||||
|
MESSAGE("Wobbuffet is hurt by spikes!");
|
||||||
|
MESSAGE("Pointed stones dug into Wobbuffet!");
|
||||||
|
MESSAGE("Wobbuffet was poisoned!");
|
||||||
|
MESSAGE("Wobbuffet was caught in a Sticky Web!");
|
||||||
|
MESSAGE("2 sent out Wynaut!");
|
||||||
|
NONE_OF {
|
||||||
|
MESSAGE("Foe Wynaut is hurt by spikes!");
|
||||||
|
MESSAGE("Pointed stones dug into Foe Wynaut!");
|
||||||
|
MESSAGE("Foe Wynaut was poisoned!");
|
||||||
|
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Court Change used by the player swaps Mist, Safeguard, Lucky Chant, Reflect, Light Screen, Tailwind")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_MIST); MOVE(opponentRight, MOVE_SAFEGUARD); }
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_LUCKY_CHANT); MOVE(opponentRight, MOVE_REFLECT); }
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_LIGHT_SCREEN); MOVE(opponentRight, MOVE_TAILWIND); }
|
||||||
|
TURN { MOVE(playerLeft, MOVE_COURT_CHANGE); }
|
||||||
|
TURN { }
|
||||||
|
TURN { }
|
||||||
|
TURN { }
|
||||||
|
TURN { }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Foe Wobbuffet used Mist!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Safeguard!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Lucky Chant!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Reflect!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Light Screen!");
|
||||||
|
MESSAGE("Foe Wobbuffet used Tailwind!");
|
||||||
|
MESSAGE("Wynaut used Court Change!");
|
||||||
|
MESSAGE("Wynaut swapped the battle effects affecting each side!");
|
||||||
|
// The effects now end for the player side.
|
||||||
|
MESSAGE("Ally's Mist wore off!");
|
||||||
|
MESSAGE("Ally's party is no longer protected by Safeguard!");
|
||||||
|
MESSAGE("Ally's Reflect wore off!");
|
||||||
|
MESSAGE("Your team's Lucky Chant wore off!");
|
||||||
|
MESSAGE("Your team's tailwind petered out!");
|
||||||
|
MESSAGE("Ally's Light Screen wore off!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Court Change used by the opponent swaps Mist, Safeguard, Lucky Chant, Reflect, Light Screen, Tailwind")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(playerLeft, MOVE_MIST); MOVE(playerRight, MOVE_SAFEGUARD); }
|
||||||
|
TURN { MOVE(playerLeft, MOVE_LUCKY_CHANT); MOVE(playerRight, MOVE_REFLECT); }
|
||||||
|
TURN { MOVE(playerLeft, MOVE_LIGHT_SCREEN); MOVE(playerRight, MOVE_TAILWIND); }
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_COURT_CHANGE); }
|
||||||
|
TURN { }
|
||||||
|
TURN { }
|
||||||
|
TURN { }
|
||||||
|
TURN { }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Mist!");
|
||||||
|
MESSAGE("Wobbuffet used Safeguard!");
|
||||||
|
MESSAGE("Wobbuffet used Lucky Chant!");
|
||||||
|
MESSAGE("Wobbuffet used Reflect!");
|
||||||
|
MESSAGE("Wobbuffet used Light Screen!");
|
||||||
|
MESSAGE("Wobbuffet used Tailwind!");
|
||||||
|
MESSAGE("Foe Wynaut used Court Change!");
|
||||||
|
MESSAGE("Foe Wynaut swapped the battle effects affecting each side!");
|
||||||
|
// The effects now end for the player side.
|
||||||
|
MESSAGE("Foe's Mist wore off!");
|
||||||
|
MESSAGE("Foe's party is no longer protected by Safeguard!");
|
||||||
|
MESSAGE("Foe's Reflect wore off!");
|
||||||
|
MESSAGE("The opposing team's Lucky Chant wore off!");
|
||||||
|
MESSAGE("The opposing team's tailwind petered out!");
|
||||||
|
MESSAGE("Foe's Light Screen wore off!");
|
||||||
|
}
|
||||||
|
}
|
@ -125,7 +125,7 @@ DOUBLE_BATTLE_TEST("Defog lowers evasiveness by 1 and removes Mist and Safeguard
|
|||||||
STATUS_ICON(opponentRight, badPoison: TRUE);
|
STATUS_ICON(opponentRight, badPoison: TRUE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
MESSAGE("Foe Wobbuffet's party is protected by SAFEGUARD!");
|
MESSAGE("Foe Wobbuffet's party is protected by Safeguard!");
|
||||||
NOT STATUS_ICON(opponentRight, badPoison: TRUE);
|
NOT STATUS_ICON(opponentRight, badPoison: TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ ASSUMPTIONS
|
|||||||
|
|
||||||
SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
|
SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
|
||||||
{
|
{
|
||||||
s16 recoil;
|
|
||||||
GIVEN {
|
GIVEN {
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
OPPONENT(SPECIES_WOBBUFFET);
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
@ -25,7 +24,6 @@ SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on miss")
|
|||||||
|
|
||||||
SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on protect")
|
SINGLE_BATTLE_TEST("Jump Kick has 50% recoil on protect")
|
||||||
{
|
{
|
||||||
s16 recoil;
|
|
||||||
GIVEN {
|
GIVEN {
|
||||||
ASSUME(!gBattleMoves[MOVE_JUMP_KICK].ignoresProtect);
|
ASSUME(!gBattleMoves[MOVE_JUMP_KICK].ignoresProtect);
|
||||||
PLAYER(SPECIES_WOBBUFFET);
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
@ -55,3 +53,48 @@ SINGLE_BATTLE_TEST("Jump Kick has no recoil if no target")
|
|||||||
NOT HP_BAR(player, damage: maxHP / 2);
|
NOT HP_BAR(player, damage: maxHP / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Jump Kick's recoil happens after Spiky Shield damage and Pokemon can faint from either of these")
|
||||||
|
{
|
||||||
|
s16 hp, maxHp = 256;
|
||||||
|
bool32 faintOnSpiky = FALSE, faintOnJumpKick = FALSE;
|
||||||
|
|
||||||
|
PARAMETRIZE { hp = maxHp; }
|
||||||
|
PARAMETRIZE { hp = maxHp / 2; faintOnJumpKick = TRUE; } // Faints after Jump Kick's recoil
|
||||||
|
PARAMETRIZE { hp = maxHp / 8; faintOnSpiky = TRUE; } // Faints after Spiky Shield's recoil
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(gBattleMoves[MOVE_SPIKY_SHIELD].effect == EFFECT_PROTECT);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) { HP(hp); MaxHP(maxHp); }
|
||||||
|
PLAYER(SPECIES_WYNAUT);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
if (!faintOnJumpKick && !faintOnSpiky) {
|
||||||
|
TURN { MOVE(opponent, MOVE_SPIKY_SHIELD); MOVE(player, MOVE_JUMP_KICK, hit: FALSE); }
|
||||||
|
} else {
|
||||||
|
TURN { MOVE(opponent, MOVE_SPIKY_SHIELD); MOVE(player, MOVE_JUMP_KICK, hit: FALSE); SEND_OUT(player, 1); }
|
||||||
|
}
|
||||||
|
TURN { ; }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPIKY_SHIELD, opponent);
|
||||||
|
MESSAGE("Wobbuffet used Jump Kick!");
|
||||||
|
MESSAGE("Foe Wobbuffet protected itself!");
|
||||||
|
HP_BAR(player, damage: maxHp / 8);
|
||||||
|
MESSAGE("Wobbuffet was hurt by Foe Wobbuffet's Spiky Shield!");
|
||||||
|
if (faintOnSpiky){
|
||||||
|
MESSAGE("Wobbuffet fainted!");
|
||||||
|
MESSAGE("Go! Wynaut!");
|
||||||
|
NONE_OF {
|
||||||
|
MESSAGE("Wobbuffet kept going and crashed!");
|
||||||
|
HP_BAR(player);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MESSAGE("Wobbuffet kept going and crashed!");
|
||||||
|
HP_BAR(player);
|
||||||
|
if (faintOnJumpKick) {
|
||||||
|
MESSAGE("Wobbuffet fainted!");
|
||||||
|
MESSAGE("Go! Wynaut!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
237
test/move_effect_sticky_web.c
Normal file
237
test/move_effect_sticky_web.c
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test_battle.h"
|
||||||
|
|
||||||
|
ASSUMPTIONS
|
||||||
|
{
|
||||||
|
ASSUME(gBattleMoves[MOVE_STICKY_WEB].effect == EFFECT_STICKY_WEB);
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Sticky Web lowers Speed by 1 on switch-in")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||||
|
TURN { SWITCH(opponent, 1); }
|
||||||
|
TURN {}
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
MESSAGE("2 sent out Wynaut!");
|
||||||
|
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Wynaut's Speed fell!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Sticky Web can only be set up 1 time")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||||
|
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("Wobbuffet used Sticky Web!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
|
||||||
|
MESSAGE("Wobbuffet used Sticky Web!");
|
||||||
|
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||||
|
MESSAGE("But it failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Sticky Web lowers Speed by 1 in a double battle after Explosion fainting both mons")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(gBattleMoves[MOVE_EXPLOSION].effect == EFFECT_EXPLOSION);
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) {Speed(5);}
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) {HP(1500); Speed(10);}
|
||||||
|
PLAYER(SPECIES_WOBBUFFET) {Speed(10);}
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET) {HP(1); Speed(1);}
|
||||||
|
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||||
|
OPPONENT(SPECIES_WYNAUT) {Speed(10);}
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(playerRight, MOVE_STICKY_WEB); MOVE(playerLeft, MOVE_EXPLOSION); SEND_OUT(playerLeft, 2); SEND_OUT(opponentLeft, 2); SEND_OUT(opponentRight, 3); }
|
||||||
|
TURN {}
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerRight);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_EXPLOSION, playerLeft);
|
||||||
|
MESSAGE("2 sent out Wynaut!");
|
||||||
|
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||||
|
MESSAGE("Foe Wynaut's Speed fell!");
|
||||||
|
MESSAGE("2 sent out Wynaut!");
|
||||||
|
MESSAGE("Foe Wynaut was caught in a Sticky Web!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||||
|
MESSAGE("Foe Wynaut's Speed fell!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Sticky Web raises Speed by 1 for a Pokemon with Contrary")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_SHUCKLE) { Ability(ABILITY_CONTRARY); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_STICKY_WEB); }
|
||||||
|
TURN { SWITCH(opponent, 1); }
|
||||||
|
TURN {}
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, player);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
MESSAGE("2 sent out Shuckle!");
|
||||||
|
MESSAGE("Foe Shuckle was caught in a Sticky Web!");
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
|
||||||
|
MESSAGE("Foe Shuckle's Speed rose!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BATTLER_OPPONENT (opponentSetUpper == 0 ? opponentLeft : opponentRight)
|
||||||
|
#define BATTLER_PLAYER (playerSetUpper == 0 ? playerLeft : playerRight)
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - the battler which set up Sticky Web has its Speed lowered instead")
|
||||||
|
{
|
||||||
|
u8 playerSetUpper, opponentSetUpper; // 0 left, 1 right
|
||||||
|
|
||||||
|
PARAMETRIZE {playerSetUpper = 0; opponentSetUpper = 0; }
|
||||||
|
PARAMETRIZE {playerSetUpper = 0; opponentSetUpper = 1; }
|
||||||
|
PARAMETRIZE {playerSetUpper = 1; opponentSetUpper = 0; }
|
||||||
|
PARAMETRIZE {playerSetUpper = 1; opponentSetUpper = 1; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||||
|
PLAYER(SPECIES_SQUIRTLE);
|
||||||
|
PLAYER(SPECIES_CHARMANDER);
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
|
||||||
|
OPPONENT(SPECIES_CATERPIE);
|
||||||
|
OPPONENT(SPECIES_WEEDLE);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(BATTLER_OPPONENT, MOVE_STICKY_WEB); }
|
||||||
|
TURN { MOVE(BATTLER_PLAYER, MOVE_STICKY_WEB); }
|
||||||
|
TURN { SWITCH(playerRight, 2); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, BATTLER_OPPONENT);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, BATTLER_PLAYER);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
|
||||||
|
MESSAGE("Go! Corviknigh!");
|
||||||
|
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||||
|
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||||
|
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, BATTLER_OPPONENT);
|
||||||
|
if (opponentSetUpper == 0) {
|
||||||
|
MESSAGE("Foe Caterpie's Speed fell!");
|
||||||
|
} else {
|
||||||
|
MESSAGE("Foe Weedle's Speed fell!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef BATTLER_OPPONENT
|
||||||
|
#undef BATTLER_PLAYER
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no one has their Speed lowered if the set upper switched")
|
||||||
|
{
|
||||||
|
u16 speedPlayer, speedOpponent;
|
||||||
|
|
||||||
|
// We need to make sure Sticky Web user saves for both sides, so it doesn't matter who sets it first.
|
||||||
|
PARAMETRIZE { speedPlayer = 5; speedOpponent = 10; }
|
||||||
|
PARAMETRIZE { speedPlayer = 10; speedOpponent = 5; }
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||||
|
PLAYER(SPECIES_SQUIRTLE) { Speed(speedPlayer); }
|
||||||
|
PLAYER(SPECIES_CHARMANDER) { Speed(speedPlayer); }
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) { Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); Speed(speedOpponent); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
|
||||||
|
OPPONENT(SPECIES_CATERPIE) { Speed(speedOpponent); }
|
||||||
|
OPPONENT(SPECIES_WEEDLE) { Speed(speedOpponent); }
|
||||||
|
OPPONENT(SPECIES_PIDGEY) { Speed(speedOpponent); } // Flying type,so not affected by Sticky Web.
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); MOVE(playerRight, MOVE_STICKY_WEB); }
|
||||||
|
TURN { SWITCH(opponentLeft, 2); }
|
||||||
|
TURN { SWITCH(playerRight, 2); }
|
||||||
|
} SCENE {
|
||||||
|
if (speedPlayer > speedOpponent) {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerRight);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||||
|
} else {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, playerRight);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around the opposing team!");
|
||||||
|
}
|
||||||
|
|
||||||
|
MESSAGE("Go! Corviknigh!");
|
||||||
|
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||||
|
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||||
|
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||||
|
} THEN {
|
||||||
|
EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUBLE_BATTLE_TEST("Sticky Web has correct interactions with Mirror Armor - no one has their Speed lowered if the set upper fainted")
|
||||||
|
{
|
||||||
|
bool8 hasReplacement;
|
||||||
|
|
||||||
|
// We need to make sure Sticky Web user saves for both sides, so it doesn't matter who sets it first.
|
||||||
|
PARAMETRIZE {hasReplacement = TRUE;}
|
||||||
|
PARAMETRIZE {hasReplacement = FALSE;}
|
||||||
|
|
||||||
|
GIVEN {
|
||||||
|
ASSUME(P_GEN_8_POKEMON == TRUE);
|
||||||
|
ASSUME(gBattleMoves[MOVE_MEMENTO].effect == EFFECT_MEMENTO);
|
||||||
|
PLAYER(SPECIES_SQUIRTLE) {Speed(5); }
|
||||||
|
PLAYER(SPECIES_CHARMANDER) {Speed(5); }
|
||||||
|
PLAYER(SPECIES_CORVIKNIGHT) {Ability(ABILITY_MIRROR_ARMOR); Item(ITEM_IRON_BALL); Speed(5); } // Iron Ball, so that flying type Corviknight is affected by Sticky Web.
|
||||||
|
OPPONENT(SPECIES_CATERPIE) {Speed(7); }
|
||||||
|
OPPONENT(SPECIES_WEEDLE) {Speed(7); }
|
||||||
|
if (hasReplacement) {
|
||||||
|
OPPONENT(SPECIES_PIDGEY) {Speed(7); }
|
||||||
|
}
|
||||||
|
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_STICKY_WEB); }
|
||||||
|
if (hasReplacement) {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_MEMENTO, target:playerLeft); SEND_OUT(opponentLeft, 2); }
|
||||||
|
} else {
|
||||||
|
TURN { MOVE(opponentLeft, MOVE_MEMENTO, target:playerLeft);}
|
||||||
|
}
|
||||||
|
TURN { SWITCH(playerRight, 2); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_STICKY_WEB, opponentLeft);
|
||||||
|
MESSAGE("A sticky web spreads out on the ground around your team!");
|
||||||
|
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_MEMENTO, opponentLeft);
|
||||||
|
MESSAGE("Foe Caterpie fainted!");
|
||||||
|
if (hasReplacement) {
|
||||||
|
MESSAGE("2 sent out Pidgey!");
|
||||||
|
}
|
||||||
|
|
||||||
|
MESSAGE("Go! Corviknigh!");
|
||||||
|
MESSAGE("Corviknigh was caught in a Sticky Web!");
|
||||||
|
ABILITY_POPUP(playerRight, ABILITY_MIRROR_ARMOR);
|
||||||
|
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||||
|
} THEN {
|
||||||
|
if (hasReplacement) {
|
||||||
|
EXPECT_EQ(opponentLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(playerLeft->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(playerRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
EXPECT_EQ(opponentRight->statStages[STAT_SPEED], DEFAULT_STAT_STAGE);
|
||||||
|
}
|
||||||
|
}
|
61
test/move_effect_teleport.c
Normal file
61
test/move_effect_teleport.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include "global.h"
|
||||||
|
#include "test_battle.h"
|
||||||
|
|
||||||
|
ASSUMPTIONS
|
||||||
|
{
|
||||||
|
ASSUME(gBattleMoves[MOVE_TELEPORT].effect == EFFECT_TELEPORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Teleport fails when there is no pokemon to switch in")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_TELEPORT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("But it failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Teleport fails when there no alive pokemon left")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WYNAUT) { HP(0); }
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_TELEPORT); }
|
||||||
|
} SCENE {
|
||||||
|
MESSAGE("But it failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Teleport forces the pokemon to switch out")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(opponent, MOVE_TELEPORT); SEND_OUT(opponent, 1); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEPORT, opponent);
|
||||||
|
MESSAGE("2 sent out Wynaut!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SINGLE_BATTLE_TEST("Teleport does not fail if the user is trapped")
|
||||||
|
{
|
||||||
|
GIVEN {
|
||||||
|
PLAYER(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WOBBUFFET);
|
||||||
|
OPPONENT(SPECIES_WYNAUT);
|
||||||
|
} WHEN {
|
||||||
|
TURN { MOVE(player, MOVE_FIRE_SPIN); MOVE(opponent, MOVE_TELEPORT); SEND_OUT(opponent, 1); }
|
||||||
|
} SCENE {
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_FIRE_SPIN, player);
|
||||||
|
ANIMATION(ANIM_TYPE_MOVE, MOVE_TELEPORT, opponent);
|
||||||
|
MESSAGE("2 sent out Wynaut!");
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "characters.h"
|
#include "characters.h"
|
||||||
#include "gpu_regs.h"
|
#include "gpu_regs.h"
|
||||||
|
#include "load_save.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
#include "random.h"
|
#include "random.h"
|
||||||
@ -114,6 +115,10 @@ void CB2_TestRunner(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MoveSaveBlocks_ResetHeap();
|
||||||
|
ClearSav1();
|
||||||
|
ClearSav2();
|
||||||
|
|
||||||
gIntrTable[7] = Intr_Timer2;
|
gIntrTable[7] = Intr_Timer2;
|
||||||
|
|
||||||
// The current test restarted the ROM (e.g. by jumping to NULL).
|
// The current test restarted the ROM (e.g. by jumping to NULL).
|
||||||
|
Loading…
Reference in New Issue
Block a user