Sky Drop clean up and tests (#6218)
Co-authored-by: Bassoonian <iasperbassoonian@gmail.com>
This commit is contained in:
parent
6b8e680139
commit
db7e45f1d6
@ -172,6 +172,19 @@ enum SleepClauseBlock
|
||||
BLOCKED_BY_SLEEP_CLAUSE,
|
||||
};
|
||||
|
||||
enum SkyDropState
|
||||
{
|
||||
SKY_DROP_IGNORE,
|
||||
SKY_DROP_ATTACKCANCELLER_CHECK,
|
||||
SKY_DROP_GRAVITY_ON_AIRBORNE,
|
||||
SKY_DROP_CANCEL_MULTI_TURN_MOVES,
|
||||
SKY_DROP_STATUS_YAWN,
|
||||
SKY_DROP_STATUS_FREEZE_SLEEP,
|
||||
};
|
||||
|
||||
#define SKY_DROP_NO_TARGET 0xFF
|
||||
#define SKY_DROP_RELEASED_TARGET 0xFE
|
||||
|
||||
void HandleAction_ThrowBall(void);
|
||||
u32 GetCurrentBattleWeather(void);
|
||||
bool32 EndOrContinueWeather(void);
|
||||
@ -195,7 +208,7 @@ u8 GetBattlerForBattleScript(u8 caseId);
|
||||
bool32 IsBattlerMarkedForControllerExec(u32 battler);
|
||||
void MarkBattlerForControllerExec(u32 battler);
|
||||
void MarkBattlerReceivedLinkData(u32 battler);
|
||||
const u8* CancelMultiTurnMoves(u32 battler);
|
||||
const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState);
|
||||
bool32 WasUnableToUseMove(u32 battler);
|
||||
void PrepareStringBattle(enum StringID stringId, u32 battler);
|
||||
void ResetSentPokesToOpponentValue(void);
|
||||
|
||||
@ -445,7 +445,7 @@ static bool32 HandleEndTurnFirstEventBlock(u32 battler)
|
||||
gBattleMons[battler].status2 -= STATUS2_LOCK_CONFUSE_TURN(1);
|
||||
if (WasUnableToUseMove(battler))
|
||||
{
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
}
|
||||
else if (!(gBattleMons[battler].status2 & STATUS2_LOCK_CONFUSE) && (gBattleMons[battler].status2 & STATUS2_MULTIPLETURNS))
|
||||
{
|
||||
@ -993,7 +993,7 @@ static bool32 HandleEndTurnYawn(u32 battler)
|
||||
&& !UproarWakeUpCheck(battler)
|
||||
&& !IsLeafGuardProtected(battler, ability))
|
||||
{
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_STATUS_YAWN);
|
||||
gEffectBattler = gBattlerTarget = battler;
|
||||
if (IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
|
||||
{
|
||||
@ -1379,7 +1379,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
|
||||
gBattleMons[battler].status2 -= STATUS2_UPROAR_TURN(1); // uproar timer goes down
|
||||
if (WasUnableToUseMove(battler))
|
||||
{
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS;
|
||||
}
|
||||
else if (gBattleMons[battler].status2 & STATUS2_UPROAR)
|
||||
@ -1390,7 +1390,7 @@ static bool32 HandleEndTurnThirdEventBlock(u32 battler)
|
||||
else
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS;
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
}
|
||||
BattleScriptExecute(BattleScript_PrintUproarOverTurns);
|
||||
effect = TRUE;
|
||||
|
||||
@ -3007,7 +3007,7 @@ static void BattleStartClearSetData(void)
|
||||
gBattleStruct->lastTakenMoveFrom[i][2] = MOVE_NONE;
|
||||
gBattleStruct->lastTakenMoveFrom[i][3] = MOVE_NONE;
|
||||
gBattleStruct->AI_monToSwitchIntoId[i] = PARTY_SIZE;
|
||||
gBattleStruct->skyDropTargets[i] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[i] = SKY_DROP_NO_TARGET;
|
||||
}
|
||||
|
||||
gLastUsedMove = 0;
|
||||
@ -3357,14 +3357,14 @@ const u8* FaintClearSetData(u32 battler)
|
||||
TryBattleFormChange(battler, FORM_CHANGE_FAINT);
|
||||
|
||||
// If the fainted mon was involved in a Sky Drop
|
||||
if (gBattleStruct->skyDropTargets[battler] != 0xFF)
|
||||
if (gBattleStruct->skyDropTargets[battler] != SKY_DROP_NO_TARGET)
|
||||
{
|
||||
// Get battler id of the other Pokemon involved in this Sky Drop
|
||||
u8 otherSkyDropper = gBattleStruct->skyDropTargets[battler];
|
||||
|
||||
// Clear Sky Drop data
|
||||
gBattleStruct->skyDropTargets[battler] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[otherSkyDropper] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET;
|
||||
|
||||
// If the other Pokemon involved in this Sky Drop was the target, not the attacker
|
||||
if (gStatuses3[otherSkyDropper] & STATUS3_SKY_DROPPED)
|
||||
@ -3915,7 +3915,7 @@ static void HandleEndTurn_ContinueBattle(void)
|
||||
{
|
||||
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
|
||||
if ((gBattleMons[i].status1 & STATUS1_SLEEP) && (gBattleMons[i].status2 & STATUS2_MULTIPLETURNS))
|
||||
CancelMultiTurnMoves(i);
|
||||
CancelMultiTurnMoves(i, SKY_DROP_IGNORE);
|
||||
}
|
||||
gBattleStruct->eventBlockCounter = 0;
|
||||
gBattleStruct->turnEffectsBattlerId = 0;
|
||||
|
||||
@ -1319,7 +1319,7 @@ static void Cmd_attackcanceler(void)
|
||||
gBattlescriptCurrInstr = BattleScript_FailedFromAtkString;
|
||||
|
||||
if (!gBattleMoveEffects[effect].twoTurnEffect || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1423,7 +1423,7 @@ static void Cmd_attackcanceler(void)
|
||||
{
|
||||
if (IsMoveMakingContact(gCurrentMove, gBattlerAttacker))
|
||||
gProtectStructs[gBattlerAttacker].touchedProtectLike = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattleStruct->moveResultFlags[gBattlerTarget] |= MOVE_RESULT_MISSED;
|
||||
gLastLandedMoves[gBattlerTarget] = 0;
|
||||
gLastHitByType[gBattlerTarget] = 0;
|
||||
@ -1504,14 +1504,14 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler)
|
||||
// If the attacker has the ability No Guard and they aren't targeting a Pokemon involved in a Sky Drop with the move Sky Drop, move hits.
|
||||
else if (GetBattlerAbility(gBattlerAttacker) == ABILITY_NO_GUARD
|
||||
&& !(gStatuses3[battler] & STATUS3_COMMANDER)
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == 0xFF))
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == SKY_DROP_NO_TARGET))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
}
|
||||
// If the target has the ability No Guard and they aren't involved in a Sky Drop or the current move isn't Sky Drop, move hits.
|
||||
else if (GetBattlerAbility(battler) == ABILITY_NO_GUARD
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == 0xFF))
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battler] == SKY_DROP_NO_TARGET))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
@ -3303,7 +3303,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
if (!CanBeSlept(gEffectBattler, GetBattlerAbility(gEffectBattler), BLOCKED_BY_SLEEP_CLAUSE) && !gBattleStruct->battlerState[gEffectBattler].sleepClauseEffectExempt)
|
||||
break;
|
||||
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler);
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler, SKY_DROP_STATUS_FREEZE_SLEEP);
|
||||
if (cancelMultiTurnMovesResult)
|
||||
gBattlescriptCurrInstr = cancelMultiTurnMovesResult;
|
||||
statusChanged = TRUE;
|
||||
@ -3397,7 +3397,7 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
if (!CanBeFrozen(gEffectBattler))
|
||||
break;
|
||||
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler);
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(gEffectBattler, SKY_DROP_STATUS_FREEZE_SLEEP);
|
||||
if (cancelMultiTurnMovesResult)
|
||||
gBattlescriptCurrInstr = cancelMultiTurnMovesResult;
|
||||
statusChanged = TRUE;
|
||||
@ -4320,8 +4320,8 @@ void SetMoveEffect(bool32 primary, bool32 certain)
|
||||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
}
|
||||
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)
|
||||
CancelMultiTurnMoves(gBattlerTarget);
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == SKY_DROP_NO_TARGET)
|
||||
CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_IGNORE);
|
||||
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectEerieSpell;
|
||||
@ -6986,7 +6986,7 @@ static void Cmd_moveend(void)
|
||||
case MOVEEND_SKY_DROP_CONFUSE: // If a Pokemon was released from Sky Drop and was in LOCK_CONFUSE, go to "confused due to fatigue" scripts and clear Sky Drop data.
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattleStruct->skyDropTargets[i] == 0xFE)
|
||||
if (gBattleStruct->skyDropTargets[i] == SKY_DROP_RELEASED_TARGET)
|
||||
{
|
||||
u8 targetId;
|
||||
// Find the battler id of the Pokemon that was held by Sky Drop
|
||||
@ -7003,8 +7003,8 @@ static void Cmd_moveend(void)
|
||||
gBattlescriptCurrInstr = BattleScript_ThrashConfuses;
|
||||
|
||||
// Clear skyDropTargets data
|
||||
gBattleStruct->skyDropTargets[i] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[targetId] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[i] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[targetId] = SKY_DROP_NO_TARGET;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -7544,7 +7544,7 @@ static void Cmd_moveend(void)
|
||||
&& MoveHasAdditionalEffectSelf(gCurrentMove, MOVE_EFFECT_THRASH) // If we're rampaging
|
||||
&& gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT // And it is unusable
|
||||
&& (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn
|
||||
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it
|
||||
|
||||
if (gBattleStruct->savedAttackerCount > 0)
|
||||
{
|
||||
@ -10442,7 +10442,7 @@ static void Cmd_various(void)
|
||||
VARIOUS_ARGS();
|
||||
// Cancel all multiturn moves of IN_AIR Pokemon except those being targeted by Sky Drop.
|
||||
if (gStatuses3[battler] & STATUS3_ON_AIR && !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_GRAVITY_ON_AIRBORNE);
|
||||
|
||||
gStatuses3[battler] &= ~(STATUS3_MAGNET_RISE | STATUS3_TELEKINESIS | STATUS3_ON_AIR | STATUS3_SKY_DROPPED);
|
||||
break;
|
||||
@ -10483,7 +10483,7 @@ static void Cmd_various(void)
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
const u8 *result;
|
||||
result = CancelMultiTurnMoves(battler);
|
||||
result = CancelMultiTurnMoves(battler, SKY_DROP_CANCEL_MULTI_TURN_MOVES);
|
||||
if (result)
|
||||
{
|
||||
gBattlescriptCurrInstr = result;
|
||||
@ -11505,12 +11505,12 @@ static void Cmd_various(void)
|
||||
VARIOUS_ARGS(const u8 *failInstr);
|
||||
// Check to see if the initial target of this Sky Drop fainted before the 2nd turn of Sky Drop.
|
||||
// If so, make the move fail. If not, clear all of the statuses and continue the move.
|
||||
if (gBattleStruct->skyDropTargets[gBattlerAttacker] == 0xFF)
|
||||
if (gBattleStruct->skyDropTargets[gBattlerAttacker] == SKY_DROP_NO_TARGET)
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
else
|
||||
{
|
||||
gBattleStruct->skyDropTargets[gBattlerAttacker] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[gBattlerTarget] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[gBattlerAttacker] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[gBattlerTarget] = SKY_DROP_NO_TARGET;
|
||||
gStatuses3[gBattlerTarget] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
@ -11523,14 +11523,14 @@ static void Cmd_various(void)
|
||||
case VARIOUS_SKY_DROP_YAWN: // If the mon that's sleeping due to Yawn was holding a Pokemon in Sky Drop, release the target and clear Sky Drop data.
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
if (gBattleStruct->skyDropTargets[gEffectBattler] != 0xFF && !(gStatuses3[gEffectBattler] & STATUS3_SKY_DROPPED))
|
||||
if (gBattleStruct->skyDropTargets[gEffectBattler] != SKY_DROP_NO_TARGET && !(gStatuses3[gEffectBattler] & STATUS3_SKY_DROPPED))
|
||||
{
|
||||
// Set the target of Sky Drop as gEffectBattler
|
||||
gEffectBattler = gBattleStruct->skyDropTargets[gEffectBattler];
|
||||
|
||||
// Clear skyDropTargets data
|
||||
gBattleStruct->skyDropTargets[gBattleStruct->skyDropTargets[gEffectBattler]] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[gEffectBattler] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[gBattleStruct->skyDropTargets[gEffectBattler]] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[gEffectBattler] = SKY_DROP_NO_TARGET;
|
||||
|
||||
// If the target was in the middle of Outrage/Thrash/etc. when targeted by Sky Drop, confuse them on release and do proper animation
|
||||
if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE && CanBeConfused(gEffectBattler))
|
||||
@ -14046,8 +14046,8 @@ static void Cmd_tryspiteppreduce(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
|
||||
// Don't cut off Sky Drop if pp is brought to zero.
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == 0xFF)
|
||||
CancelMultiTurnMoves(gBattlerTarget);
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == SKY_DROP_NO_TARGET)
|
||||
CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_IGNORE);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -14237,7 +14237,7 @@ static void Cmd_handlerollout(void)
|
||||
|
||||
if (gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
{
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveMissedPause;
|
||||
}
|
||||
else
|
||||
|
||||
@ -1024,7 +1024,68 @@ void MarkBattlerReceivedLinkData(u32 battler)
|
||||
gBattleControllerExecFlags &= ~(1u << (28 + battler));
|
||||
}
|
||||
|
||||
const u8* CancelMultiTurnMoves(u32 battler)
|
||||
const u8 *CheckSkyDropState(u32 battler, enum SkyDropState skyDropState)
|
||||
{
|
||||
const u8 *result = NULL;
|
||||
|
||||
u8 otherSkyDropper = gBattleStruct->skyDropTargets[battler];
|
||||
gStatuses3[otherSkyDropper] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
|
||||
|
||||
// Makes both attacker and target's sprites visible
|
||||
gSprites[gBattlerSpriteIds[battler]].invisible = FALSE;
|
||||
gSprites[gBattlerSpriteIds[otherSkyDropper]].invisible = FALSE;
|
||||
|
||||
// If target was sky dropped in the middle of Outrage/Thrash/Petal Dance,
|
||||
// confuse them upon release and display "confused by fatigue" message & animation.
|
||||
// Don't do this if this CancelMultiTurnMoves is caused by falling asleep via Yawn.
|
||||
if (gBattleMons[otherSkyDropper].status2 & STATUS2_LOCK_CONFUSE && skyDropState != SKY_DROP_STATUS_YAWN)
|
||||
{
|
||||
gBattleMons[otherSkyDropper].status2 &= ~(STATUS2_LOCK_CONFUSE);
|
||||
|
||||
// If the target can be confused, confuse them.
|
||||
// Don't use CanBeConfused, can cause issues in edge cases.
|
||||
if (!(GetBattlerAbility(otherSkyDropper) == ABILITY_OWN_TEMPO
|
||||
|| gBattleMons[otherSkyDropper].status2 & STATUS2_CONFUSION
|
||||
|| IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN)))
|
||||
{
|
||||
// Set confused status
|
||||
gBattleMons[otherSkyDropper].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2);
|
||||
|
||||
if (skyDropState == SKY_DROP_ATTACKCANCELLER_CHECK)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET;
|
||||
}
|
||||
else if (skyDropState == SKY_DROP_GRAVITY_ON_AIRBORNE)
|
||||
{
|
||||
// Reapplying STATUS3_SKY_DROPPED allows for avoiding unecessary messages when Gravity is applied to the target.
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET;
|
||||
gStatuses3[otherSkyDropper] |= STATUS3_SKY_DROPPED;
|
||||
}
|
||||
else if (skyDropState == SKY_DROP_CANCEL_MULTI_TURN_MOVES)
|
||||
{
|
||||
gBattlerAttacker = otherSkyDropper;
|
||||
result = BattleScript_ThrashConfuses;
|
||||
}
|
||||
else if (skyDropState == SKY_DROP_STATUS_FREEZE_SLEEP)
|
||||
{
|
||||
gBattlerAttacker = otherSkyDropper;
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
result = BattleScript_ThrashConfuses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear skyDropTargets data, unless this CancelMultiTurnMoves is caused by Yawn, attackcanceler, or VARIOUS_GRAVITY_ON_AIRBORNE_MONS
|
||||
if (!(gBattleMons[otherSkyDropper].status2 & STATUS2_LOCK_CONFUSE) && gBattleStruct->skyDropTargets[battler] < 4)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const u8 *CancelMultiTurnMoves(u32 battler, enum SkyDropState skyDropState)
|
||||
{
|
||||
const u8 *result = NULL;
|
||||
gBattleMons[battler].status2 &= ~(STATUS2_UPROAR);
|
||||
@ -1045,70 +1106,8 @@ const u8* CancelMultiTurnMoves(u32 battler)
|
||||
if (!(gStatuses3[battler] & STATUS3_SKY_DROPPED))
|
||||
gStatuses3[battler] &= ~(STATUS3_SEMI_INVULNERABLE);
|
||||
|
||||
// Check to see if this Pokemon was in the middle of using Sky Drop. If so, release the target.
|
||||
if (gBattleStruct->skyDropTargets[battler] != 0xFF && !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
|
||||
{
|
||||
// Get the target's battler id
|
||||
u8 otherSkyDropper = gBattleStruct->skyDropTargets[battler];
|
||||
|
||||
// Clears sky_dropped and on_air statuses
|
||||
gStatuses3[otherSkyDropper] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
|
||||
|
||||
// Makes both attacker and target's sprites visible
|
||||
gSprites[gBattlerSpriteIds[battler]].invisible = FALSE;
|
||||
gSprites[gBattlerSpriteIds[otherSkyDropper]].invisible = FALSE;
|
||||
|
||||
// If target was sky dropped in the middle of Outrage/Thrash/Petal Dance,
|
||||
// confuse them upon release and display "confused by fatigue" message & animation.
|
||||
// Don't do this if this CancelMultiTurnMoves is caused by falling asleep via Yawn.
|
||||
if (gBattleMons[otherSkyDropper].status2 & STATUS2_LOCK_CONFUSE && gBattleStruct->eventBlockCounter != 24)
|
||||
{
|
||||
gBattleMons[otherSkyDropper].status2 &= ~(STATUS2_LOCK_CONFUSE);
|
||||
|
||||
// If the target can be confused, confuse them.
|
||||
// Don't use CanBeConfused, can cause issues in edge cases.
|
||||
if (!(GetBattlerAbility(otherSkyDropper) == ABILITY_OWN_TEMPO
|
||||
|| gBattleMons[otherSkyDropper].status2 & STATUS2_CONFUSION
|
||||
|| IsBattlerTerrainAffected(otherSkyDropper, STATUS_FIELD_MISTY_TERRAIN)))
|
||||
{
|
||||
// Set confused status
|
||||
gBattleMons[otherSkyDropper].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2);
|
||||
|
||||
// If this CancelMultiTurnMoves is occuring due to attackcanceller
|
||||
if (gBattlescriptCurrInstr[0] == 0x0)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = 0xFE;
|
||||
}
|
||||
// If this CancelMultiTurnMoves is occuring due to VARIOUS_GRAVITY_ON_AIRBORNE_MONS
|
||||
// Reapplying STATUS3_SKY_DROPPED allows for avoiding unecessary messages when Gravity is applied to the target.
|
||||
else if (gBattlescriptCurrInstr[0] == 0x76 && gBattlescriptCurrInstr[2] == 76)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = 0xFE;
|
||||
gStatuses3[otherSkyDropper] |= STATUS3_SKY_DROPPED;
|
||||
}
|
||||
// If this CancelMultiTurnMoves is occuring due to cancelmultiturnmoves script
|
||||
else if (gBattlescriptCurrInstr[0] == 0x76 && gBattlescriptCurrInstr[2] == 0)
|
||||
{
|
||||
gBattlerAttacker = otherSkyDropper;
|
||||
result = BattleScript_ThrashConfuses;
|
||||
}
|
||||
// If this CancelMultiTurnMoves is occuring due to receiving Sleep/Freeze status
|
||||
else if (gBattleScripting.moveEffect <= PRIMARY_STATUS_MOVE_EFFECT)
|
||||
{
|
||||
gBattlerAttacker = otherSkyDropper;
|
||||
BattleScriptPush(gBattlescriptCurrInstr + 1);
|
||||
result = BattleScript_ThrashConfuses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear skyDropTargets data, unless this CancelMultiTurnMoves is caused by Yawn, attackcanceler, or VARIOUS_GRAVITY_ON_AIRBORNE_MONS
|
||||
if (!(gBattleMons[otherSkyDropper].status2 & STATUS2_LOCK_CONFUSE) && gBattleStruct->skyDropTargets[battler] < 4)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = 0xFF;
|
||||
gBattleStruct->skyDropTargets[otherSkyDropper] = 0xFF;
|
||||
}
|
||||
}
|
||||
if (gBattleStruct->skyDropTargets[battler] != SKY_DROP_NO_TARGET && !(gStatuses3[battler] & STATUS3_SKY_DROPPED))
|
||||
result = CheckSkyDropState(battler, skyDropState);
|
||||
|
||||
gDisableStructs[battler].rolloutTimer = 0;
|
||||
gDisableStructs[battler].furyCutterCounter = 0;
|
||||
@ -1303,7 +1302,7 @@ u32 TrySetCantSelectMoveBattleScript(u32 battler)
|
||||
|
||||
if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && move == gLastMoves[battler] && move != MOVE_STRUGGLE && (gBattleMons[battler].status2 & STATUS2_TORMENT))
|
||||
{
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
{
|
||||
gPalaceSelectionBattleScripts[battler] = BattleScript_SelectingTormentedMoveInPalace;
|
||||
@ -1672,7 +1671,7 @@ bool32 BattleArenaTurnEnd(void)
|
||||
&& IsBattlerAlive(B_POSITION_PLAYER_LEFT) && IsBattlerAlive(B_POSITION_OPPONENT_LEFT))
|
||||
{
|
||||
for (u32 battler = 0; battler < 2; battler++)
|
||||
CancelMultiTurnMoves(battler);
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
|
||||
gBattlescriptCurrInstr = BattleScript_ArenaDoJudgment;
|
||||
BattleScriptExecute(BattleScript_ArenaDoJudgment);
|
||||
@ -1875,7 +1874,7 @@ static void CancellerRecharge(u32 *effect)
|
||||
{
|
||||
gBattleMons[gBattlerAttacker].status2 &= ~STATUS2_RECHARGE;
|
||||
gDisableStructs[gBattlerAttacker].rechargeTimer = 0;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2011,7 +2010,7 @@ static void CancellerTruant(u32 *effect)
|
||||
{
|
||||
if (GetBattlerAbility(gBattlerAttacker) == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
|
||||
{
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING;
|
||||
gBattlerAbility = gBattlerAttacker;
|
||||
@ -2026,7 +2025,7 @@ static void CancellerFlinch(u32 *effect)
|
||||
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].flinchImmobility = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2047,7 +2046,7 @@ static void CancellerInLove(u32 *effect)
|
||||
BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack);
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
gProtectStructs[gBattlerAttacker].loveImmobility = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
}
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove;
|
||||
*effect = 1;
|
||||
@ -2060,7 +2059,7 @@ static void CancellerDisabled(u32 *effect)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].usedDisabledMove = TRUE;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2073,7 +2072,7 @@ static void CancellerHealBlocked(u32 *effect)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].usedHealBlockedMove = TRUE;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2086,7 +2085,7 @@ static void CancellerGravity(u32 *effect)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].usedGravityPreventedMove = TRUE;
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2098,7 +2097,7 @@ static void CancellerThroatChop(u32 *effect)
|
||||
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].throatChopTimer > gBattleTurnCounter && IsSoundMove(gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].usedThroatChopPreventedMove = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2110,7 +2109,7 @@ static void CancellerTaunted(u32 *effect)
|
||||
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && gDisableStructs[gBattlerAttacker].tauntTimer && IsBattleMoveStatus(gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].usedTauntedMove = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2122,7 +2121,7 @@ static void CancellerImprisoned(u32 *effect)
|
||||
if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove))
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].usedImprisonedMove = TRUE;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2181,7 +2180,7 @@ static void CancellerParalysed(u32 *effect)
|
||||
{
|
||||
gProtectStructs[gBattlerAttacker].prlzImmobility = TRUE;
|
||||
// This is removed in FRLG and Emerald for some reason
|
||||
//CancelMultiTurnMoves(gBattlerAttacker);
|
||||
//CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2327,7 +2326,7 @@ static void CancellerPsychicTerrain(u32 *effect)
|
||||
&& GetMoveTarget(gCurrentMove) != MOVE_TARGET_OPPONENTS_FIELD
|
||||
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gBattlerTarget))
|
||||
{
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELLER_CHECK);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedPsychicTerrainPrevents;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
*effect = 1;
|
||||
@ -2972,7 +2971,7 @@ bool32 CanAbilityBlockMove(u32 battlerAtk, u32 battlerDef, u32 abilityAtk, u32 a
|
||||
&& !(IsBattleMoveStatus(move) && (abilityDef == ABILITY_MAGIC_BOUNCE || gProtectStructs[battlerDef].bounceMove)))
|
||||
{
|
||||
if (option == ABILITY_RUN_SCRIPT && !IsSpreadMove(GetBattlerMoveTargetType(battlerAtk, move)))
|
||||
CancelMultiTurnMoves(battlerAtk); // Don't cancel moves that can hit two targets bc one target might not be protected
|
||||
CancelMultiTurnMoves(battlerAtk, SKY_DROP_ATTACKCANCELLER_CHECK); // Don't cancel moves that can hit two targets bc one target might not be protected
|
||||
|
||||
battleScriptBlocksMove = BattleScript_DarkTypePreventsPrankster;
|
||||
}
|
||||
|
||||
124
test/battle/move_effect/sky_drop.c
Normal file
124
test/battle/move_effect/sky_drop.c
Normal file
@ -0,0 +1,124 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
ASSUMPTIONS
|
||||
{
|
||||
ASSUME(GetMoveEffect(MOVE_SKY_DROP) == EFFECT_SKY_DROP);
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop does no damage to Flying type Pokémon")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_PIDGEY].weight < 2000);
|
||||
ASSUME(gSpeciesInfo[SPECIES_PIDGEY].types[1] == TYPE_FLYING);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SKY_DROP); }
|
||||
TURN { SKIP_TURN(player); }
|
||||
} SCENE {
|
||||
MESSAGE("Wobbuffet took the opposing Pidgey into the sky!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, player);
|
||||
NOT HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop fails if target is behind a substitute")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUBSTITUTE); MOVE(player, MOVE_SKY_DROP); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUBSTITUTE, opponent);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, player);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop fails if target is in a Semi-Invulnerable state")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_FLY); MOVE(player, MOVE_SKY_DROP); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FLY, opponent);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, player);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sky Drop is cancelled if Gravity activated")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_SKY_DROP, target: opponentLeft);
|
||||
MOVE(playerRight, MOVE_GRAVITY);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_GRAVITY, playerRight);
|
||||
MESSAGE("Wobbuffet fell from the sky due to the gravity!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop fails on heavy targets")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_METAGROSS].weight >= 2000);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_METAGROSS);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_SKY_DROP); }
|
||||
} SCENE {
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, player);
|
||||
MESSAGE("The opposing Metagross is too heavy to be lifted!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop cancels targets two turn moves")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(opponent, MOVE_SOLAR_BEAM);
|
||||
MOVE(player, MOVE_SKY_DROP);
|
||||
}
|
||||
TURN { SKIP_TURN(player); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SOLAR_BEAM, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, player);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_SOLAR_BEAM, opponent);
|
||||
HP_BAR(opponent);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop stops the confusion count until the target is dropped")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THRASH); }
|
||||
TURN { SKIP_TURN(player); }
|
||||
TURN { SKIP_TURN(player); }
|
||||
TURN { MOVE(opponent, MOVE_SKY_DROP); }
|
||||
TURN { SKIP_TURN(opponent); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, opponent);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user