mirror of
https://github.com/rh-hideout/pokeemerald-expansion.git
synced 2026-03-21 18:04:50 -05:00
Refactor Sky Drop and rampage confusion (#9249)
This commit is contained in:
parent
a338550479
commit
c114dfbc84
|
|
@ -1204,6 +1204,11 @@
|
|||
.byte B_SCR_OP_TRY_SYNCHRONIZE
|
||||
.endm
|
||||
|
||||
.macro tryconfusionafterskydrop battler:req
|
||||
.byte B_SCR_OP_TRY_CONFUSION_AFTER_SKY_DROP
|
||||
.byte \battler
|
||||
.endm
|
||||
|
||||
.macro callnative func:req
|
||||
.byte B_SCR_OP_CALLNATIVE
|
||||
.4byte \func
|
||||
|
|
@ -2082,10 +2087,6 @@
|
|||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro skydropyawn
|
||||
callnative BS_SkyDropYawn
|
||||
.endm
|
||||
|
||||
.macro jumpifpranksterblocked jumpInstr:req
|
||||
callnative BS_JumpIfPranksterBlocked
|
||||
.4byte \jumpInstr
|
||||
|
|
|
|||
|
|
@ -2118,6 +2118,8 @@ BattleScript_EffectGravitySuccess::
|
|||
selectfirstvalidtarget
|
||||
BattleScript_GravityLoop:
|
||||
jumpfifsemiinvulnerable BS_TARGET, STATE_ON_AIR, BattleScript_GravityLoopDrop
|
||||
jumpfifsemiinvulnerable BS_TARGET, STATE_SKY_DROP_ATTACKER, BattleScript_GravityLoopDrop
|
||||
jumpfifsemiinvulnerable BS_TARGET, STATE_SKY_DROP_TARGET, BattleScript_GravityLoopDrop
|
||||
jumpifvolatile BS_TARGET, VOLATILE_MAGNET_RISE, BattleScript_GravityLoopDrop
|
||||
jumpifvolatile BS_TARGET, VOLATILE_TELEKINESIS, BattleScript_GravityLoopDrop
|
||||
goto BattleScript_GravityLoopEnd
|
||||
|
|
@ -2832,18 +2834,6 @@ BattleScript_SkyDropFlyingType::
|
|||
printstring STRINGID_ITDOESNTAFFECT
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
makevisible BS_ATTACKER
|
||||
jumpifvolatile BS_TARGET, VOLATILE_CONFUSION, BattleScript_SkyDropFlyingAlreadyConfused
|
||||
jumpifvolatile BS_TARGET, VOLATILE_RAMPAGE_TURNS, BattleScript_SkyDropFlyingConfuseLock
|
||||
return
|
||||
|
||||
BattleScript_SkyDropFlyingConfuseLock:
|
||||
seteffectprimary BS_ATTACKER, BS_TARGET, MOVE_EFFECT_CONFUSION
|
||||
BattleScript_SkyDropFlyingAlreadyConfused:
|
||||
clearvolatile BS_TARGET, VOLATILE_RAMPAGE_TURNS
|
||||
jumpifvolatile BS_TARGET, VOLATILE_CONFUSION, BattleScript_SkyDropFlyingAlreadyConfusedRet
|
||||
setbyte BS_ATTACKER, BS_TARGET
|
||||
call BattleScript_ThrashConfusesRet
|
||||
BattleScript_SkyDropFlyingAlreadyConfusedRet:
|
||||
return
|
||||
|
||||
BattleScript_SkyDropNoTarget::
|
||||
|
|
@ -3978,6 +3968,7 @@ BattleScript_FaintBattler::
|
|||
dofaintanimation BS_FAINTED
|
||||
copybyte sBATTLER, gBattlerFainted @ for message
|
||||
printstring STRINGID_BATTLERFAINTED
|
||||
tryconfusionafterskydrop BS_FAINTED
|
||||
cleareffectsonfaint BS_FAINTED
|
||||
trytoclearprimalweather
|
||||
tryrevertweatherform
|
||||
|
|
@ -5705,7 +5696,7 @@ BattleScript_ThrashConfuses::
|
|||
waitmessage B_WAIT_TIME_LONG
|
||||
end2
|
||||
|
||||
BattleScript_ThrashConfusesRet::
|
||||
BattleScript_ConfusionAfterRampage::
|
||||
volatileanimation BS_SCRIPTING, VOLATILE_CONFUSION
|
||||
printstring STRINGID_PKMNFATIGUECONFUSION
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
|
|
@ -5837,9 +5828,8 @@ BattleScript_YawnMakesAsleepEnd2::
|
|||
updatestatusicon BS_EFFECT_BATTLER
|
||||
waitstate
|
||||
tryactivateitem BS_EFFECT_BATTLER, ACTIVATION_ON_STATUS_CHANGE
|
||||
jumpfifsemiinvulnerable BS_EFFECT_BATTLER, STATE_SKY_DROP, BattleScript_YawnEnd
|
||||
jumpfifsemiinvulnerable BS_EFFECT_BATTLER, STATE_SKY_DROP_TARGET, BattleScript_YawnEnd
|
||||
makevisible BS_EFFECT_BATTLER
|
||||
skydropyawn
|
||||
BattleScript_YawnEnd:
|
||||
end2
|
||||
|
||||
|
|
|
|||
|
|
@ -653,7 +653,6 @@ struct BattleStruct
|
|||
u8 throwingPokeBall:1;
|
||||
u8 ballSpriteIds[2]; // item gfx, window gfx
|
||||
u8 moveInfoSpriteId; // move info, window gfx
|
||||
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.
|
||||
u16 beatUpSpecies[PARTY_SIZE]; // Species for Gen5+ Beat Up, otherwise party indexes
|
||||
u8 attackerBeforeBounce:2;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ void AnimSetCenterToCornerVecX(struct Sprite *sprite);
|
|||
void BeginBattleIntroDummy(void);
|
||||
void BeginBattleIntro(void);
|
||||
void SwitchInClearSetData(enum BattlerId battler, struct Volatiles *volatilesCopy);
|
||||
const u8 *FaintClearSetData(enum BattlerId battler);
|
||||
void FaintClearSetData(enum BattlerId battler);
|
||||
void BattleTurnPassed(void);
|
||||
u8 IsRunningFromBattleImpossible(enum BattlerId battler);
|
||||
void SwitchTwoBattlersInParty(enum BattlerId battler, enum BattlerId battler2);
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ extern const u8 BattleScript_MoveUsedIsParalyzed[];
|
|||
extern const u8 BattleScript_MoveUsedFlinched[];
|
||||
extern const u8 BattleScript_PrintUproarOverTurns[];
|
||||
extern const u8 BattleScript_ThrashConfuses[];
|
||||
extern const u8 BattleScript_ThrashConfusesRet[];
|
||||
extern const u8 BattleScript_ConfusionAfterRampage[];
|
||||
extern const u8 BattleScript_MoveUsedIsConfused[];
|
||||
extern const u8 BattleScript_MoveUsedIsConfusedNoMore[];
|
||||
extern const u8 BattleScript_PrintPayDayMoneyString[];
|
||||
|
|
|
|||
|
|
@ -152,19 +152,6 @@ enum SleepClauseBlock
|
|||
BLOCKED_BY_SLEEP_CLAUSE,
|
||||
};
|
||||
|
||||
enum SkyDropState
|
||||
{
|
||||
SKY_DROP_IGNORE,
|
||||
SKY_DROP_ATTACKCANCELER_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
|
||||
|
||||
enum EjectPackTiming
|
||||
{
|
||||
START_OF_TURN,
|
||||
|
|
@ -197,7 +184,7 @@ enum BattlerId GetBattlerForBattleScript(u8 caseId);
|
|||
bool32 IsBattlerMarkedForControllerExec(enum BattlerId battler);
|
||||
void MarkBattlerForControllerExec(enum BattlerId battler);
|
||||
void MarkBattlerReceivedLinkData(enum BattlerId battler);
|
||||
const u8 *CancelMultiTurnMoves(enum BattlerId battler, enum SkyDropState skyDropState);
|
||||
void CancelMultiTurnMoves(enum BattlerId battler);
|
||||
bool32 IsLastMonToMove(enum BattlerId battler);
|
||||
bool32 ShouldDefiantCompetitiveActivate(enum BattlerId battler, enum Ability ability);
|
||||
void PrepareStringBattle(enum StringID stringId, enum BattlerId battler);
|
||||
|
|
@ -349,7 +336,7 @@ bool32 CanBeParalyzed(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum
|
|||
bool32 CanBeFrozen(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityDef);
|
||||
bool32 CanGetFrostbite(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityDef);
|
||||
bool32 CanSetNonVolatileStatus(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum MoveEffect secondaryMoveEffect, enum ResultOption option);
|
||||
bool32 CanBeConfused(enum BattlerId battler);
|
||||
bool32 CanBeConfused(enum BattlerId battlerAtk, enum BattlerId effectBattler);
|
||||
bool32 IsSafeguardProtected(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityAtk);
|
||||
u32 GetBattlerAffectionHearts(enum BattlerId battler);
|
||||
void TryToRevertMimicryAndFlags(void);
|
||||
|
|
@ -405,6 +392,7 @@ bool32 DoesMoveMissTarget(struct BattleCalcValues *cv);
|
|||
bool32 IsSemiInvulnerable(enum BattlerId battler, enum SemiInvulnerableExclusion excludeCommander);
|
||||
bool32 CanBreakThroughSemiInvulnerablity(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum Move move);
|
||||
bool32 BreaksThroughSemiInvulnerableState(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum Move move, enum SemiInvulnerableState state);
|
||||
bool32 IsBattlerOnAir(enum BattlerId battler);
|
||||
bool32 HasPartnerTrainer(enum BattlerId battler);
|
||||
bool32 IsAffectedByPowderMove(enum BattlerId battler, enum Ability ability, enum HoldEffect holdEffect);
|
||||
enum Move GetNaturePowerMove(void);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@
|
|||
#define B_SKILL_SWAP GEN_LATEST // In Gen4+, Skill Swap triggers switch-in abilities after use.
|
||||
#define B_BRICK_BREAK GEN_LATEST // In Gen4+, you can destroy your own side's screens. In Gen 5+, screens are not removed if the target is immune.
|
||||
#define B_WISH_HP_SOURCE GEN_LATEST // In Gen5+, Wish heals half of the user's max HP instead of the target's.
|
||||
#define B_RAMPAGE_CANCELLING GEN_LATEST // In Gen5+, a failed Thrash, etc, will cancel except on its last turn.
|
||||
#define B_RAMPAGE_CONFUSION GEN_LATEST // In Gen5+, Rampage is canceled after the move (as opposed to End Turn) and a failed rampage move will cancel the counter unless it is the last turn
|
||||
#define B_HEAL_BLOCKING GEN_LATEST // In Gen5+, Heal Block prevents healing by Black Sludge, Leftovers, Shell Bell. Affected Pokémon will not consume held HP-restoring Berries or Berry Juice.
|
||||
// Draining abilities will not heal but will prevent damage. In Gen6+, Heal Block prevents the use of most HP-draining moves.
|
||||
#define B_ROOTED_GROUNDING GEN_LATEST // In Gen4+, Ingrain causes the affected Pokémon to become grounded.
|
||||
|
|
|
|||
|
|
@ -183,6 +183,8 @@ enum VolatileFlags
|
|||
F(VOLATILE_BIDE, bideTurns, (u32, 3)) \
|
||||
F(VOLATILE_RAMPAGE_TURNS, rampageTurns, (u32, B_RAMPAGE_TURNS + 1)) \
|
||||
F(VOLATILE_MULTIPLETURNS, multipleTurns, (u32, 1)) \
|
||||
F(VOLATILE_SKY_DROP_TARGET, skyDropTarget, (enum BattlerId, MAX_BATTLERS_COUNT)) \
|
||||
F(VOLATILE_CONFUSE_AFTER_DROP, confuseAfterDrop, (u32, 1)) \
|
||||
F(VOLATILE_WRAPPED, wrapped, (u32, 1)) \
|
||||
F(VOLATILE_WRAPPED_BY, wrappedBy, (enum BattlerId, MAX_BITS(MAX_BATTLERS_COUNT))) \
|
||||
F(VOLATILE_WRAPPED_MOVE, wrappedMove, (u32, MOVES_COUNT_ALL - 1)) \
|
||||
|
|
@ -318,7 +320,8 @@ enum SemiInvulnerableState
|
|||
STATE_UNDERWATER,
|
||||
STATE_ON_AIR,
|
||||
STATE_PHANTOM_FORCE,
|
||||
STATE_SKY_DROP,
|
||||
STATE_SKY_DROP_ATTACKER,
|
||||
STATE_SKY_DROP_TARGET,
|
||||
STATE_COMMANDER,
|
||||
SEMI_INVULNERABLE_COUNT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ enum MoveEndState
|
|||
MOVEEND_SYMBIOSIS,
|
||||
MOVEEND_SUBSTITUTE,
|
||||
MOVEEND_FAINT_BLOCK,
|
||||
MOVEEND_SKY_DROP_CONFUSE,
|
||||
MOVEEND_UPDATE_LAST_MOVES,
|
||||
MOVEEND_MIRROR_MOVE,
|
||||
MOVEEND_NEXT_TARGET, // Everything up until here is handled for each strike of a spread move
|
||||
|
|
@ -121,6 +120,8 @@ enum MoveEndState
|
|||
MOVEEND_OPPORTUNIST,
|
||||
MOVEEND_MIRROR_HERB,
|
||||
MOVEEND_THIRD_MOVE_BLOCK,
|
||||
MOVEEND_RAMPAGE,
|
||||
MOVEEND_CONFUSION_AFTER_SKY_DROP, // If target was previously rampaging, it should be confused when dropped
|
||||
MOVEEND_EJECT_PACK,
|
||||
MOVEEND_CLEAR_BITS,
|
||||
MOVEEND_DANCER,
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ enum BattleScriptOpcode
|
|||
B_SCR_OP_SETNONVOLATILESTATUS,
|
||||
B_SCR_OP_TRYOVERWRITEABILITY,
|
||||
B_SCR_OP_TRY_SYNCHRONIZE,
|
||||
B_SCR_OP_TRY_CONFUSION_AFTER_SKY_DROP,
|
||||
|
||||
// Expansion users, please don't use any of the unused commands.
|
||||
// They are reserved for expansion usage.
|
||||
|
|
@ -261,7 +262,6 @@ enum BattleScriptOpcode
|
|||
B_SCR_OP_UNUSED_29,
|
||||
B_SCR_OP_UNUSED_30,
|
||||
B_SCR_OP_UNUSED_31,
|
||||
B_SCR_OP_UNUSED_32,
|
||||
B_SCR_OP_CALLNATIVE,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@
|
|||
F(B_SKILL_SWAP, skillSwap, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_BRICK_BREAK, brickBreak, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_WISH_HP_SOURCE, wishHpSource, (u32, GEN_COUNT - 1)) \
|
||||
F(B_RAMPAGE_CANCELLING, rampageCancelling, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_RAMPAGE_CONFUSION, rampageConfusion, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_HEAL_BLOCKING, healBlocking, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_ROOTED_GROUNDING, rootedGrounding, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
F(B_METRONOME_MOVES, metronomeMoves, (u32, GEN_COUNT - 1)) /* TODO: use in tests */ \
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ bool32 ShouldUseItem(enum BattlerId battler)
|
|||
|
||||
// If teaming up with player and Pokemon is on the right, or Pokemon is currently held by Sky Drop
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(battler) == B_POSITION_PLAYER_RIGHT)
|
||||
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
return FALSE;
|
||||
|
||||
if (gBattleMons[battler].volatiles.embargo)
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ bool32 IsBattlerTrapped(enum BattlerId battlerAtk, enum BattlerId battlerDef)
|
|||
return TRUE;
|
||||
if (gBattleMons[battlerDef].volatiles.escapePrevention)
|
||||
return TRUE;
|
||||
if (gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
if (gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
return TRUE;
|
||||
if (gBattleMons[battlerDef].volatiles.root)
|
||||
return TRUE;
|
||||
|
|
@ -3696,7 +3696,7 @@ bool32 AI_CanBeConfused(enum BattlerId battlerAtk, enum BattlerId battlerDef, en
|
|||
if (gBattleMons[battlerDef].volatiles.confusionTurns > 0
|
||||
|| (abilityDef == ABILITY_OWN_TEMPO && !DoesBattlerIgnoreAbilityChecks(battlerAtk, gAiLogicData->abilities[battlerAtk], move))
|
||||
|| IsMistyTerrainAffected(battlerDef, abilityDef, gAiLogicData->holdEffects[battlerDef], gFieldStatuses)
|
||||
|| gSideStatuses[GetBattlerSide(battlerDef)] & SIDE_STATUS_SAFEGUARD
|
||||
|| IsSafeguardProtected(battlerAtk, battlerDef, gAiLogicData->abilities[battlerAtk])
|
||||
|| DoesSubstituteBlockMove(battlerAtk, battlerDef, move))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -6583,24 +6583,6 @@ static void ReloadBattlerSprites(enum BattlerId battler, struct Pokemon *party)
|
|||
}
|
||||
}
|
||||
|
||||
static void TrySwapSkyDropTargets(enum BattlerId battlerAtk, enum BattlerId battlerPartner)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
// battlerAtk is using Ally Switch
|
||||
// check if our partner is the target of sky drop
|
||||
// If so, change that index to battlerAtk
|
||||
for (enum BattlerId i = 0; i < gBattlersCount; i++) {
|
||||
if (gBattleStruct->skyDropTargets[i] == battlerPartner) {
|
||||
gBattleStruct->skyDropTargets[i] = battlerAtk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Then swap our own sky drop targets with the partner in case our partner is mid-skydrop
|
||||
SWAP(gBattleStruct->skyDropTargets[battlerAtk], gBattleStruct->skyDropTargets[battlerPartner], temp);
|
||||
}
|
||||
|
||||
#define TRY_SIDE_TIMER_BATTLER_ID_SWAP(battlerAtk, battlerPartner, side, field) \
|
||||
if (gSideTimers[side].field == battlerAtk) \
|
||||
gSideTimers[side].field = battlerPartner; \
|
||||
|
|
@ -6748,7 +6730,6 @@ static void AnimTask_AllySwitchDataSwap(u8 taskId)
|
|||
SwitchTwoBattlersInParty(battlerAtk, battlerPartner);
|
||||
SWAP(gBattlerPartyIndexes[battlerAtk], gBattlerPartyIndexes[battlerPartner], temp);
|
||||
|
||||
TrySwapSkyDropTargets(battlerAtk, battlerPartner);
|
||||
TrySwapStickyWebBattlerId(battlerAtk, battlerPartner);
|
||||
TrySwapWishBattlerIds(battlerAtk, battlerPartner);
|
||||
TrySwapAttractBattlerIds(battlerAtk, battlerPartner);
|
||||
|
|
|
|||
|
|
@ -329,12 +329,14 @@ static bool32 HandleEndTurnFirstEventBlock(enum BattlerId battler)
|
|||
gBattleStruct->eventState.endTurnBlock++;
|
||||
break;
|
||||
case FIRST_EVENT_BLOCK_THRASH:
|
||||
if (gBattleMons[battler].volatiles.rampageTurns && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
|
||||
if (B_RAMPAGE_CONFUSION < GEN_5
|
||||
&& gBattleMons[battler].volatiles.rampageTurns
|
||||
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP_TARGET)
|
||||
{
|
||||
gBattleMons[battler].volatiles.rampageTurns--;
|
||||
if (gBattleMons[battler].volatiles.unableToUseMove)
|
||||
{
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
CancelMultiTurnMoves(battler);
|
||||
}
|
||||
else if (!gBattleMons[battler].volatiles.rampageTurns && gBattleMons[battler].volatiles.multipleTurns)
|
||||
{
|
||||
|
|
@ -905,7 +907,7 @@ static bool32 HandleEndTurnYawn(enum BattlerId battler)
|
|||
else
|
||||
gBattleMons[battler].status1 |= (RandomUniform(RNG_SLEEP_TURNS, 2, 8));
|
||||
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_STATUS_YAWN);
|
||||
CancelMultiTurnMoves(battler);
|
||||
TryActivateSleepClause(battler, gBattlerPartyIndexes[battler]);
|
||||
BtlController_EmitSetMonData(battler, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
|
||||
MarkBattlerForControllerExec(battler);
|
||||
|
|
@ -1241,7 +1243,7 @@ static bool32 HandleEndTurnThirdEventBlock(enum BattlerId battler)
|
|||
gBattleMons[battler].volatiles.uproarTurns--; // uproar timer goes down
|
||||
if (gBattleMons[battler].volatiles.unableToUseMove)
|
||||
{
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
CancelMultiTurnMoves(battler);
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS;
|
||||
}
|
||||
else if (gBattleMons[battler].volatiles.uproarTurns)
|
||||
|
|
@ -1252,7 +1254,7 @@ static bool32 HandleEndTurnThirdEventBlock(enum BattlerId battler)
|
|||
else
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_UPROAR_ENDS;
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
CancelMultiTurnMoves(battler);
|
||||
}
|
||||
BattleScriptExecute(BattleScript_PrintUproarOverTurns);
|
||||
effect = TRUE;
|
||||
|
|
|
|||
|
|
@ -3084,7 +3084,6 @@ 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] = SKY_DROP_NO_TARGET;
|
||||
}
|
||||
|
||||
gLastUsedMove = 0;
|
||||
|
|
@ -3328,10 +3327,8 @@ void SwitchInClearSetData(enum BattlerId battler, struct Volatiles *volatilesCop
|
|||
Ai_UpdateSwitchInData(battler);
|
||||
}
|
||||
|
||||
const u8* FaintClearSetData(enum BattlerId battler)
|
||||
void FaintClearSetData(enum BattlerId battler)
|
||||
{
|
||||
const u8 *result = NULL;
|
||||
|
||||
for (enum Stat i = 0; i < NUM_BATTLE_STATS; i++)
|
||||
gBattleMons[battler].statStages[i] = DEFAULT_STAT_STAGE;
|
||||
|
||||
|
|
@ -3427,48 +3424,6 @@ const u8* FaintClearSetData(enum BattlerId battler)
|
|||
|
||||
Ai_UpdateFaintData(battler);
|
||||
TryBattleFormChange(battler, FORM_CHANGE_FAINT, GetBattlerAbility(battler));
|
||||
|
||||
// If the fainted mon was involved in a Sky Drop
|
||||
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] = 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 (gBattleMons[otherSkyDropper].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
{
|
||||
// Release the target and take them out of the semi-invulnerable state
|
||||
gBattleMons[otherSkyDropper].volatiles.semiInvulnerable = STATE_NONE;
|
||||
|
||||
// Make the target's sprite visible
|
||||
gSprites[gBattlerSpriteIds[otherSkyDropper]].invisible = FALSE;
|
||||
|
||||
// If the target was sky dropped in the middle of using Outrage/Petal Dance/Thrash,
|
||||
// confuse them upon release and print "confused via fatigue" message and animation.
|
||||
if (gBattleMons[otherSkyDropper].volatiles.rampageTurns)
|
||||
{
|
||||
gBattleMons[otherSkyDropper].volatiles.rampageTurns = 0;
|
||||
|
||||
// If the released mon can be confused, do so.
|
||||
// Don't use CanBeConfused here, since it can cause issues in edge cases.
|
||||
enum Ability ability = GetBattlerAbility(otherSkyDropper);
|
||||
if (!(ability == ABILITY_OWN_TEMPO
|
||||
|| gBattleMons[otherSkyDropper].volatiles.confusionTurns
|
||||
|| IsMistyTerrainAffected(otherSkyDropper, ability, GetBattlerHoldEffect(otherSkyDropper), gFieldStatuses)))
|
||||
{
|
||||
gBattleMons[otherSkyDropper].volatiles.confusionTurns = ((Random()) % 4) + 2;
|
||||
gBattlerAttacker = otherSkyDropper;
|
||||
result = BattleScript_ThrashConfuses;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void DoBattleIntro(void)
|
||||
|
|
@ -3964,7 +3919,7 @@ static void HandleEndTurn_ContinueBattle(void)
|
|||
{
|
||||
gBattleMons[battler].volatiles.flinched = FALSE;
|
||||
if ((gBattleMons[battler].status1 & STATUS1_SLEEP) && (gBattleMons[battler].volatiles.multipleTurns))
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
CancelMultiTurnMoves(battler);
|
||||
}
|
||||
gBattleStruct->eventState.endTurnBlock = 0;
|
||||
gBattleStruct->eventState.endTurnBattler = 0;
|
||||
|
|
@ -4298,7 +4253,7 @@ static void HandleTurnActionSelectionState(void)
|
|||
| BATTLE_TYPE_RECORDED_LINK))
|
||||
&& !gTestRunnerEnabled)
|
||||
// Or if currently held by Sky Drop
|
||||
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
|| gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
{
|
||||
RecordedBattle_ClearBattlerAction(battler, 1);
|
||||
gSelectionBattleScripts[battler] = BattleScript_ActionSelectionItemsCantBeUsed;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ static enum CancelerResult CancelerStanceChangeOne(struct BattleContext *ctx)
|
|||
static enum CancelerResult CancelerSkyDrop(struct BattleContext *ctx)
|
||||
{
|
||||
// If Pokemon is being held in Sky Drop
|
||||
if (gBattleMons[ctx->battlerAtk].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
if (gBattleMons[ctx->battlerAtk].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEnd;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
|
|
@ -80,7 +80,7 @@ static enum CancelerResult CancelerRecharge(struct BattleContext *ctx)
|
|||
{
|
||||
if (gBattleMons[ctx->battlerAtk].volatiles.rechargeTimer > 0)
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -251,7 +251,7 @@ static enum CancelerResult CancelerTruant(struct BattleContext *ctx)
|
|||
{
|
||||
if (GetBattlerAbility(ctx->battlerAtk) == ABILITY_TRUANT && gBattleMons[ctx->battlerAtk].volatiles.truantCounter)
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_LOAFING;
|
||||
gBattlerAbility = ctx->battlerAtk;
|
||||
gBattlescriptCurrInstr = BattleScript_TruantLoafingAround;
|
||||
|
|
@ -273,7 +273,7 @@ static enum CancelerResult CancelerFocus(struct BattleContext *ctx)
|
|||
&& (focusPunchFailureConfig == GEN_5 || focusPunchFailureConfig == GEN_6 || GetMoveEffect(ctx->move) == EFFECT_FOCUS_PUNCH)
|
||||
&& !gProtectStructs[ctx->battlerAtk].survivedOHKO)
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_FocusPunchLostFocus;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -298,7 +298,7 @@ static enum CancelerResult CancelerFlinch(struct BattleContext *ctx)
|
|||
{
|
||||
if (gBattleMons[ctx->battlerAtk].volatiles.flinched)
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -312,7 +312,7 @@ static enum CancelerResult CancelerDisabled(struct BattleContext *ctx)
|
|||
&& gBattleMons[ctx->battlerAtk].volatiles.disabledMove != MOVE_NONE)
|
||||
{
|
||||
gBattleScripting.battler = ctx->battlerAtk;
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -326,20 +326,20 @@ static enum CancelerResult CancelerVolatileBlocked(struct BattleContext *ctx)
|
|||
&& IsHealBlockPreventingMove(ctx->battlerAtk, ctx->move))
|
||||
{
|
||||
gBattleScripting.battler = ctx->battlerAtk;
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
else if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(ctx->move))
|
||||
{
|
||||
gBattleScripting.battler = ctx->battlerAtk;
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
else if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && gBattleMons[ctx->battlerAtk].volatiles.throatChopTimer > 0 && IsSoundMove(ctx->move))
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsThroatChopPrevented;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -353,7 +353,7 @@ static enum CancelerResult CancelerTaunted(struct BattleContext *ctx)
|
|||
&& IsBattleMoveStatus(ctx->move)
|
||||
&& (GetConfig(B_TAUNT_ME_FIRST) < GEN_5 || GetMoveEffect(ctx->move) != EFFECT_ME_FIRST))
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -364,7 +364,7 @@ static enum CancelerResult CancelerImprisoned(struct BattleContext *ctx)
|
|||
{
|
||||
if (GetActiveGimmick(ctx->battlerAtk) != GIMMICK_Z_MOVE && GetImprisonedMovesCount(ctx->battlerAtk, ctx->move))
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -433,7 +433,7 @@ static enum CancelerResult CancelerParalyzed(struct BattleContext *ctx)
|
|||
&& !(B_MAGIC_GUARD == GEN_4 && IsAbilityAndRecord(ctx->battlerAtk, ctx->abilityAtk, ABILITY_MAGIC_GUARD))
|
||||
&& !RandomPercentage(RNG_PARALYSIS, 75))
|
||||
{
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -453,7 +453,7 @@ static enum CancelerResult CancelerInfatuation(struct BattleContext *ctx)
|
|||
else
|
||||
{
|
||||
BattleScriptPush(BattleScript_MoveUsedIsInLoveCantAttack);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -1015,7 +1015,7 @@ static enum CancelerResult CancelerSkyBattle(struct BattleContext *ctx)
|
|||
{
|
||||
if (gBattleStruct->isSkyBattle && IsMoveSkyBattleBanned(gCurrentMove))
|
||||
{
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_ButItFailed;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
|
@ -1042,7 +1042,7 @@ static enum CancelerResult CancelerWeatherPrimal(struct BattleContext *ctx)
|
|||
if (result == CANCELER_RESULT_FAILURE)
|
||||
{
|
||||
gProtectStructs[ctx->battlerAtk].chargingTurn = FALSE;
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
gBattlescriptCurrInstr = BattleScript_PrimalWeatherBlocksMove;
|
||||
}
|
||||
}
|
||||
|
|
@ -1492,17 +1492,16 @@ static enum CancelerResult HandleSkyDropResult(struct BattleContext *ctx)
|
|||
gBattleScripting.animTargetsHit = 0;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.multipleTurns = FALSE;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.semiInvulnerable = STATE_NONE;
|
||||
gBattleMons[ctx->battlerDef].volatiles.semiInvulnerable = STATE_NONE;
|
||||
gBattleStruct->skyDropTargets[gBattlerTarget] = SKY_DROP_NO_TARGET;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.skyDropTarget = 0;
|
||||
|
||||
// Sky Drop fails if target already fainted
|
||||
if (gBattleStruct->skyDropTargets[ctx->battlerAtk] == SKY_DROP_NO_TARGET)
|
||||
// Sky Drop fails if target already left the field
|
||||
if (gBattleMons[ctx->battlerDef].volatiles.semiInvulnerable == STATE_NONE)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_SkyDropNoTarget;
|
||||
return CANCELER_RESULT_FAILURE;
|
||||
}
|
||||
|
||||
gBattleStruct->skyDropTargets[ctx->battlerAtk] = SKY_DROP_NO_TARGET;
|
||||
gBattleMons[ctx->battlerDef].volatiles.semiInvulnerable = STATE_NONE;
|
||||
return CANCELER_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -1528,22 +1527,19 @@ static enum CancelerResult HandleSkyDropResult(struct BattleContext *ctx)
|
|||
}
|
||||
|
||||
// First turn
|
||||
gBattleMons[ctx->battlerDef].volatiles.multipleTurns = 0;
|
||||
gBattleMons[ctx->battlerDef].volatiles.uproarTurns = 0;
|
||||
gBattleMons[ctx->battlerDef].volatiles.bideTurns = 0;
|
||||
gBattleMons[ctx->battlerDef].volatiles.rolloutTimer = 0;
|
||||
gBattleMons[ctx->battlerDef].volatiles.furyCutterCounter = 0;
|
||||
|
||||
if (gSideTimers[GetBattlerSide(ctx->battlerDef)].followmeTimer != 0 && gSideTimers[GetBattlerSide(ctx->battlerDef)].followmeTarget == ctx->battlerDef)
|
||||
gSideTimers[GetBattlerSide(ctx->battlerDef)].followmeTimer = 0;
|
||||
if (gBattleMons[ctx->battlerDef].volatiles.rampageTurns > 0)
|
||||
gBattleMons[ctx->battlerDef].volatiles.confuseAfterDrop = TRUE;
|
||||
|
||||
gBattleStruct->skyDropTargets[ctx->battlerAtk] = ctx->battlerDef;
|
||||
gBattleStruct->skyDropTargets[ctx->battlerDef] = ctx->battlerAtk;
|
||||
CancelMultiTurnMoves(ctx->battlerDef);
|
||||
gLockedMoves[ctx->battlerAtk] = ctx->move;
|
||||
gProtectStructs[ctx->battlerAtk].chargingTurn = TRUE;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.multipleTurns = TRUE;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.semiInvulnerable = STATE_ON_AIR;
|
||||
gBattleMons[ctx->battlerDef].volatiles.semiInvulnerable = STATE_SKY_DROP;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.skyDropTarget = ctx->battlerDef + 1;
|
||||
gBattleMons[ctx->battlerAtk].volatiles.semiInvulnerable = STATE_SKY_DROP_ATTACKER;
|
||||
gBattleMons[ctx->battlerDef].volatiles.semiInvulnerable = STATE_SKY_DROP_TARGET;
|
||||
if (gSideTimers[GetBattlerSide(ctx->battlerDef)].followmeTimer != 0 && gSideTimers[GetBattlerSide(ctx->battlerDef)].followmeTarget == ctx->battlerDef)
|
||||
gSideTimers[GetBattlerSide(ctx->battlerDef)].followmeTimer = 0;
|
||||
|
||||
gBattlescriptCurrInstr = BattleScript_SkyDropCharging;
|
||||
return CANCELER_RESULT_BREAK;
|
||||
|
|
@ -1803,7 +1799,7 @@ static enum CancelerResult CancelerTargetFailure(struct BattleContext *ctx)
|
|||
gLastHitByType[gBattlerTarget] = 0;
|
||||
gBattleScripting.battler = ctx->battlerDef;
|
||||
gBattleStruct->pledgeMove = FALSE;
|
||||
CancelMultiTurnMoves(ctx->battlerAtk, SKY_DROP_ATTACKCANCELER_CHECK);
|
||||
CancelMultiTurnMoves(ctx->battlerAtk);
|
||||
return CANCELER_RESULT_PAUSE;
|
||||
}
|
||||
}
|
||||
|
|
@ -2343,7 +2339,7 @@ static enum MoveEndResult MoveEndAttackerVisible(void)
|
|||
|
||||
if (IsBattlerUnaffectedByMove(gBattlerTarget)
|
||||
|| !IsSemiInvulnerable(gBattlerAttacker, CHECK_ALL)
|
||||
|| (gBattleStruct->unableToUseMove && gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable != STATE_SKY_DROP))
|
||||
|| (gBattleStruct->unableToUseMove && gBattleMons[gBattlerAttacker].volatiles.semiInvulnerable != STATE_SKY_DROP_TARGET))
|
||||
{
|
||||
BtlController_EmitSpriteInvisibility(gBattlerAttacker, B_COMM_TO_CONTROLLER, FALSE);
|
||||
MarkBattlerForControllerExec(gBattlerAttacker);
|
||||
|
|
@ -2574,37 +2570,6 @@ static enum MoveEndResult MoveEndFaintBlock(void)
|
|||
return result;
|
||||
}
|
||||
|
||||
static enum MoveEndResult MoveEndSkyDropConfuse(void)
|
||||
{
|
||||
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
|
||||
|
||||
for (enum BattlerId battler = 0; battler < gBattlersCount; battler++)
|
||||
{
|
||||
if (gBattleStruct->skyDropTargets[battler] == SKY_DROP_RELEASED_TARGET)
|
||||
{
|
||||
// Find the battler id of the Pokemon that was held by Sky Drop
|
||||
enum BattlerId targetId;
|
||||
for (targetId = 0; targetId < gBattlersCount; targetId++)
|
||||
{
|
||||
if (gBattleStruct->skyDropTargets[targetId] == battler)
|
||||
break;
|
||||
}
|
||||
|
||||
gBattleScripting.battler = targetId;
|
||||
BattleScriptCall(BattleScript_ThrashConfusesRet); // Jump to "confused due to fatigue" script
|
||||
|
||||
// Clear skyDropTargets data
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[targetId] = SKY_DROP_NO_TARGET;
|
||||
result = MOVEEND_RESULT_RUN_SCRIPT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gBattleScripting.moveendState++;
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum MoveEndResult MoveEndUpdateLastMoves(void)
|
||||
{
|
||||
if (!IsOnPlayerSide(gBattlerAttacker))
|
||||
|
|
@ -3654,6 +3619,58 @@ static bool32 ShouldSetStompingTantrumTimer(void)
|
|||
return numNotAffectedTargets == gBattleStruct->numSpreadTargets;
|
||||
}
|
||||
|
||||
static enum MoveEndResult MoveEndRampage(void)
|
||||
{
|
||||
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
|
||||
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.rampageTurns == 0
|
||||
|| gSpecialStatuses[gBattlerAttacker].dancerUsedMove
|
||||
|| B_RAMPAGE_CONFUSION < GEN_5)
|
||||
{
|
||||
result = MOVEEND_RESULT_CONTINUE;
|
||||
}
|
||||
else if (--gBattleMons[gBattlerAttacker].volatiles.rampageTurns == 0)
|
||||
{
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
if (CanBeConfused(gBattlerAttacker, gBattlerAttacker))
|
||||
{
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
gBattleMons[gBattlerAttacker].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
|
||||
BattleScriptCall(BattleScript_ConfusionAfterRampage);
|
||||
result = MOVEEND_RESULT_BREAK;
|
||||
}
|
||||
}
|
||||
else if (IsBattlerUnaffectedByMove(gBattlerTarget))
|
||||
{
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
result = MOVEEND_RESULT_CONTINUE;
|
||||
}
|
||||
|
||||
gBattleScripting.moveendState++;
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum MoveEndResult MoveEndConfusionAfterSkyDrop(void)
|
||||
{
|
||||
enum MoveEndResult result = MOVEEND_RESULT_CONTINUE;
|
||||
|
||||
if (gBattleMons[gBattlerTarget].volatiles.confuseAfterDrop
|
||||
&& gBattleMons[gBattlerTarget].volatiles.semiInvulnerable != STATE_SKY_DROP_TARGET)
|
||||
{
|
||||
gBattleMons[gBattlerTarget].volatiles.confuseAfterDrop = FALSE;
|
||||
if (CanBeConfused(gBattlerTarget, gBattlerTarget))
|
||||
{
|
||||
gBattleScripting.battler = gBattlerTarget;
|
||||
gBattleMons[gBattlerTarget].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
|
||||
BattleScriptCall(BattleScript_ConfusionAfterRampage);
|
||||
result = MOVEEND_RESULT_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
gBattleScripting.moveendState++;
|
||||
return result;
|
||||
}
|
||||
|
||||
static enum MoveEndResult MoveEndClearBits(void)
|
||||
{
|
||||
ValidateBattlers();
|
||||
|
|
@ -3672,12 +3689,6 @@ static enum MoveEndResult MoveEndClearBits(void)
|
|||
if (originallyUsedMove != MOVE_NONE)
|
||||
TryUpdateEvolutionTracker(IF_USED_MOVE_X_TIMES, 1, originallyUsedMove);
|
||||
|
||||
if (B_RAMPAGE_CANCELLING >= GEN_5
|
||||
&& MoveHasAdditionalEffectSelf(gCurrentMove, MOVE_EFFECT_THRASH) // If we're rampaging
|
||||
&& IsBattlerUnaffectedByMove(gBattlerTarget) // And it is unusable
|
||||
&& gBattleMons[gBattlerAttacker].volatiles.rampageTurns != 1) // And won't end this turn
|
||||
CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_IGNORE); // Cancel it
|
||||
|
||||
SetSameMoveTurnValues(moveEffect);
|
||||
TryClearChargeVolatile(moveType);
|
||||
gProtectStructs[gBattlerAttacker].shellTrap = FALSE;
|
||||
|
|
@ -3699,6 +3710,7 @@ static enum MoveEndResult MoveEndClearBits(void)
|
|||
SetActiveGimmick(gBattlerAttacker, GIMMICK_NONE);
|
||||
if (gBattleMons[gBattlerAttacker].volatiles.destinyBond > 0)
|
||||
gBattleMons[gBattlerAttacker].volatiles.destinyBond--;
|
||||
|
||||
// check if Stellar type boost should be used up
|
||||
if (GetActiveGimmick(gBattlerAttacker) == GIMMICK_TERA
|
||||
&& GetBattlerTeraType(gBattlerAttacker) == TYPE_STELLAR
|
||||
|
|
@ -3789,7 +3801,6 @@ static enum MoveEndResult (*const sMoveEndHandlers[])(void) =
|
|||
[MOVEEND_SYMBIOSIS] = MoveEndSymbiosis,
|
||||
[MOVEEND_SUBSTITUTE] = MoveEndSubstitute,
|
||||
[MOVEEND_FAINT_BLOCK] = MoveEndFaintBlock,
|
||||
[MOVEEND_SKY_DROP_CONFUSE] = MoveEndSkyDropConfuse,
|
||||
[MOVEEND_UPDATE_LAST_MOVES] = MoveEndUpdateLastMoves,
|
||||
[MOVEEND_MIRROR_MOVE] = MoveEndMirrorMove,
|
||||
[MOVEEND_NEXT_TARGET] = MoveEndNextTarget,
|
||||
|
|
@ -3807,14 +3818,16 @@ static enum MoveEndResult (*const sMoveEndHandlers[])(void) =
|
|||
[MOVEEND_LIFE_ORB_SHELL_BELL] = MoveEndLifeOrbShellBell,
|
||||
[MOVEEND_FORM_CHANGE] = MoveEndFormChange,
|
||||
[MOVEEND_EMERGENCY_EXIT] = MoveEndEmergencyExit,
|
||||
[MOVEEND_EJECT_PACK] = MoveEndEjectPack,
|
||||
[MOVEEND_HIT_ESCAPE] = MoveEndHitEscape,
|
||||
[MOVEEND_PICKPOCKET] = MoveEndPickpocket,
|
||||
[MOVEEND_ITEMS_EFFECTS_ALL] = MoveEndItemsEffectsAll,
|
||||
[MOVEEND_WHITE_HERB] = MoveEndWhiteHerb,
|
||||
[MOVEEND_OPPORTUNIST] = MoveEndOpportunist,
|
||||
[MOVEEND_MIRROR_HERB] = MoveEndMirrorHerb,
|
||||
[MOVEEND_THIRD_MOVE_BLOCK] = MoveEndThirdMoveBlock,
|
||||
[MOVEEND_PICKPOCKET] = MoveEndPickpocket,
|
||||
[MOVEEND_RAMPAGE] = MoveEndRampage,
|
||||
[MOVEEND_CONFUSION_AFTER_SKY_DROP] = MoveEndConfusionAfterSkyDrop,
|
||||
[MOVEEND_EJECT_PACK] = MoveEndEjectPack,
|
||||
[MOVEEND_CLEAR_BITS] = MoveEndClearBits,
|
||||
[MOVEEND_DANCER] = MoveEndDancer,
|
||||
[MOVEEND_PURSUIT_NEXT_ACTION] = MoveEndPursuitNextAction,
|
||||
|
|
|
|||
|
|
@ -576,6 +576,7 @@ static void Cmd_jumpifcaptivateaffected(void);
|
|||
static void Cmd_setnonvolatilestatus(void);
|
||||
static void Cmd_tryoverwriteability(void);
|
||||
static void Cmd_trysynchronize(void);
|
||||
static void Cmd_tryconfusionafterskydrop(void);
|
||||
static void Cmd_dummy(void);
|
||||
static void Cmd_callnative(void);
|
||||
|
||||
|
|
@ -804,6 +805,7 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
|||
[B_SCR_OP_SETNONVOLATILESTATUS] = Cmd_setnonvolatilestatus,
|
||||
[B_SCR_OP_TRYOVERWRITEABILITY] = Cmd_tryoverwriteability,
|
||||
[B_SCR_OP_TRY_SYNCHRONIZE] = Cmd_trysynchronize,
|
||||
[B_SCR_OP_TRY_CONFUSION_AFTER_SKY_DROP] = Cmd_tryconfusionafterskydrop,
|
||||
[B_SCR_OP_UNUSED_1] = Cmd_dummy,
|
||||
[B_SCR_OP_UNUSED_2] = Cmd_dummy,
|
||||
[B_SCR_OP_UNUSED_3] = Cmd_dummy,
|
||||
|
|
@ -835,7 +837,6 @@ void (*const gBattleScriptingCommandsTable[])(void) =
|
|||
[B_SCR_OP_UNUSED_29] = Cmd_dummy,
|
||||
[B_SCR_OP_UNUSED_30] = Cmd_dummy,
|
||||
[B_SCR_OP_UNUSED_31] = Cmd_dummy,
|
||||
[B_SCR_OP_UNUSED_32] = Cmd_dummy,
|
||||
[B_SCR_OP_CALLNATIVE] = Cmd_callnative,
|
||||
};
|
||||
|
||||
|
|
@ -2321,14 +2322,8 @@ static void SetNonVolatileStatus(enum BattlerId battlerAtk, enum BattlerId effec
|
|||
{
|
||||
gEffectBattler = effectBattler;
|
||||
|
||||
if (effect == MOVE_EFFECT_SLEEP
|
||||
|| effect == MOVE_EFFECT_FREEZE)
|
||||
{
|
||||
const u8 *cancelMultiTurnMovesResult = NULL;
|
||||
cancelMultiTurnMovesResult = CancelMultiTurnMoves(effectBattler, SKY_DROP_STATUS_FREEZE_SLEEP);
|
||||
if (cancelMultiTurnMovesResult)
|
||||
gBattlescriptCurrInstr = cancelMultiTurnMovesResult;
|
||||
}
|
||||
if (effect == MOVE_EFFECT_SLEEP || effect == MOVE_EFFECT_FREEZE)
|
||||
CancelMultiTurnMoves(effectBattler);
|
||||
|
||||
BattleScriptPush(battleScript);
|
||||
|
||||
|
|
@ -2518,29 +2513,15 @@ void SetMoveEffect(enum BattlerId battlerAtk, enum BattlerId effectBattler, enum
|
|||
}
|
||||
break;
|
||||
case MOVE_EFFECT_CONFUSION:
|
||||
if (!CanBeConfused(gEffectBattler)
|
||||
|| gBattleMons[gEffectBattler].volatiles.confusionTurns
|
||||
|| (IsSafeguardProtected(gBattlerAttacker, gEffectBattler, GetBattlerAbility(gBattlerAttacker)) && !primary))
|
||||
if (!CanBeConfused(gBattlerAttacker, gEffectBattler))
|
||||
{
|
||||
gBattlescriptCurrInstr = battleScript;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleMons[gEffectBattler].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
|
||||
|
||||
// If the confusion is activating due to being released from Sky Drop, go to "confused due to fatigue" script.
|
||||
// Otherwise, do normal confusion script.
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_SKY_DROP)
|
||||
{
|
||||
gBattleMons[gEffectBattler].volatiles.rampageTurns = 0;
|
||||
gBattlerAttacker = gEffectBattler;
|
||||
gBattlescriptCurrInstr = BattleScript_ThrashConfuses;
|
||||
}
|
||||
else
|
||||
{
|
||||
BattleScriptPush(battleScript);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectConfusion;
|
||||
}
|
||||
BattleScriptPush(battleScript);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectConfusion;
|
||||
}
|
||||
break;
|
||||
case MOVE_EFFECT_FLINCH:
|
||||
|
|
@ -3184,8 +3165,8 @@ void SetMoveEffect(enum BattlerId battlerAtk, enum BattlerId effectBattler, enum
|
|||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
}
|
||||
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0 && gBattleStruct->skyDropTargets[gBattlerTarget] == SKY_DROP_NO_TARGET)
|
||||
CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_IGNORE);
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0)
|
||||
CancelMultiTurnMoves(gBattlerTarget);
|
||||
|
||||
BattleScriptPush(battleScript);
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectEerieSpell;
|
||||
|
|
@ -3977,7 +3958,6 @@ static void Cmd_cleareffectsonfaint(void)
|
|||
if (gBattleControllerExecFlags == 0)
|
||||
{
|
||||
enum BattlerId battler = GetBattlerForBattleScript(cmd->battler);
|
||||
const u8 *clearDataResult = NULL;
|
||||
if (!(gBattleTypeFlags & BATTLE_TYPE_ARENA) || !IsBattlerAlive(battler))
|
||||
{
|
||||
gBattleMons[battler].status1 = 0;
|
||||
|
|
@ -3985,11 +3965,8 @@ static void Cmd_cleareffectsonfaint(void)
|
|||
MarkBattlerForControllerExec(battler);
|
||||
}
|
||||
|
||||
clearDataResult = FaintClearSetData(battler); // Effects like attractions, trapping, etc.
|
||||
if (clearDataResult)
|
||||
gBattlescriptCurrInstr = clearDataResult;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
FaintClearSetData(battler); // Effects like attractions, trapping, etc.
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -9100,9 +9077,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] == SKY_DROP_NO_TARGET)
|
||||
CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_IGNORE);
|
||||
if (gBattleMons[gBattlerTarget].pp[i] == 0)
|
||||
CancelMultiTurnMoves(gBattlerTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -11632,6 +11608,43 @@ static void Cmd_trysynchronize(void)
|
|||
}
|
||||
}
|
||||
|
||||
// If target was dropped due to attacker fainting and was previously rampaging, try to confuse
|
||||
static void Cmd_tryconfusionafterskydrop(void)
|
||||
{
|
||||
CMD_ARGS(u8 battler);
|
||||
enum BattlerId faintBattler = GetBattlerForBattleScript(cmd->battler);
|
||||
enum BattlerId skyDropTarget = gBattleMons[faintBattler].volatiles.skyDropTarget - 1;
|
||||
bool32 shouldConfuse = FALSE;
|
||||
|
||||
if (gBattleMons[faintBattler].volatiles.semiInvulnerable != STATE_SKY_DROP_ATTACKER)
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else if (gBattleMons[skyDropTarget].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
{
|
||||
BtlController_EmitSpriteInvisibility(skyDropTarget, B_COMM_TO_CONTROLLER, FALSE);
|
||||
MarkBattlerForControllerExec(skyDropTarget);
|
||||
gBattleMons[skyDropTarget].volatiles.semiInvulnerable = STATE_NONE;
|
||||
gSpecialStatuses[skyDropTarget].restoredBattlerSprite = TRUE;
|
||||
|
||||
if (gBattleMons[skyDropTarget].volatiles.confuseAfterDrop)
|
||||
{
|
||||
gBattleMons[skyDropTarget].volatiles.confuseAfterDrop = FALSE;
|
||||
|
||||
if (CanBeConfused(skyDropTarget, skyDropTarget))
|
||||
{
|
||||
shouldConfuse = TRUE;
|
||||
gBattleScripting.battler = skyDropTarget;
|
||||
BattleScriptPush(cmd->nextInstr);
|
||||
gBattlescriptCurrInstr = BattleScript_ConfusionAfterRampage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldConfuse)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void Cmd_dummy(void)
|
||||
{
|
||||
}
|
||||
|
|
@ -13172,7 +13185,7 @@ void BS_TrySetConfusion(void)
|
|||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
|
||||
if (CanBeConfused(gBattlerTarget))
|
||||
if (CanBeConfused(gBattlerAttacker, gBattlerTarget))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
|
||||
gBattleCommunication[MULTIUSE_STATE] = 1;
|
||||
|
|
@ -13612,10 +13625,6 @@ void BS_JumpIfNotBerry(void)
|
|||
void BS_GravityOnAirborneMons(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
// Cancel all multiturn moves of IN_AIR Pokemon except those being targeted by Sky Drop.
|
||||
if (gBattleMons[gBattlerTarget].volatiles.semiInvulnerable == STATE_ON_AIR)
|
||||
CancelMultiTurnMoves(gBattlerTarget, SKY_DROP_GRAVITY_ON_AIRBORNE);
|
||||
|
||||
gBattleMons[gBattlerTarget].volatiles.semiInvulnerable = STATE_NONE;
|
||||
gBattleMons[gBattlerTarget].volatiles.magnetRise = FALSE;
|
||||
gBattleMons[gBattlerTarget].volatiles.telekinesis = FALSE;
|
||||
|
|
@ -13651,11 +13660,8 @@ void BS_TryAcupressure(void)
|
|||
void BS_CancelMultiTurnMoves(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
const u8 *result = CancelMultiTurnMoves(gBattlerAttacker, SKY_DROP_CANCEL_MULTI_TURN_MOVES);
|
||||
if (result)
|
||||
gBattlescriptCurrInstr = result;
|
||||
else
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
CancelMultiTurnMoves(gBattlerAttacker);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
void BS_IsRunningImpossible(void)
|
||||
|
|
@ -14219,7 +14225,7 @@ void BS_TryInstruct(void)
|
|||
|| IsMoveInstructBanned(move)
|
||||
|| IsInstructBannedChargingMove(gBattlerTarget)
|
||||
|| gBattleMons[gBattlerTarget].volatiles.bideTurns != 0
|
||||
|| gBattleMons[gBattlerTarget].volatiles.semiInvulnerable == STATE_SKY_DROP
|
||||
|| gBattleMons[gBattlerTarget].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET
|
||||
|| gBattleMoveEffects[GetMoveEffect(move)].twoTurnEffect
|
||||
|| (GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX)
|
||||
|| IsZMove(move)
|
||||
|
|
@ -14643,37 +14649,6 @@ void BS_TryHealQuarterHealth(void)
|
|||
gBattlescriptCurrInstr = cmd->nextInstr; // can heal
|
||||
}
|
||||
|
||||
void BS_SkyDropYawn(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
if (gBattleStruct->skyDropTargets[gEffectBattler] != SKY_DROP_NO_TARGET && gBattleMons[gEffectBattler].volatiles.semiInvulnerable != STATE_SKY_DROP)
|
||||
{
|
||||
// Set the target of Sky Drop as gEffectBattler
|
||||
gEffectBattler = gBattleStruct->skyDropTargets[gEffectBattler];
|
||||
|
||||
// Clear skyDropTargets data
|
||||
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].volatiles.rampageTurns && CanBeConfused(gEffectBattler))
|
||||
{
|
||||
gBattleMons[gEffectBattler].volatiles.rampageTurns = 0;
|
||||
gBattlerAttacker = gEffectBattler;
|
||||
gBattleMons[gBattlerTarget].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
|
||||
gBattlescriptCurrInstr = BattleScript_ThrashConfuses;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
}
|
||||
|
||||
void BS_JumpIfPranksterBlocked(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *jumpInstr);
|
||||
|
|
|
|||
|
|
@ -1072,96 +1072,26 @@ void MarkBattlerReceivedLinkData(enum BattlerId battler)
|
|||
MarkBattleControllerMessageSynchronizedOverLink(battler);
|
||||
}
|
||||
|
||||
const u8 *CheckSkyDropState(enum BattlerId battler, enum SkyDropState skyDropState)
|
||||
void CancelMultiTurnMoves(enum BattlerId battler)
|
||||
{
|
||||
const u8 *result = NULL;
|
||||
|
||||
u8 otherSkyDropper = gBattleStruct->skyDropTargets[battler];
|
||||
gBattleMons[battler].volatiles.semiInvulnerable = STATE_NONE;
|
||||
|
||||
// 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].volatiles.rampageTurns && skyDropState != SKY_DROP_STATUS_YAWN)
|
||||
{
|
||||
gBattleMons[otherSkyDropper].volatiles.rampageTurns = 0;
|
||||
|
||||
// If the target can be confused, confuse them.
|
||||
// Don't use CanBeConfused, can cause issues in edge cases.
|
||||
enum Ability ability = GetBattlerAbility(otherSkyDropper);
|
||||
if (!(gBattleMons[otherSkyDropper].volatiles.confusionTurns > 0
|
||||
|| IsAbilityAndRecord(otherSkyDropper, ability, ABILITY_OWN_TEMPO)
|
||||
|| IsMistyTerrainAffected(otherSkyDropper, ability, GetBattlerHoldEffect(otherSkyDropper), gFieldStatuses)))
|
||||
{
|
||||
gBattleMons[otherSkyDropper].volatiles.confusionTurns = RandomUniform(RNG_CONFUSION_TURNS, 2, B_CONFUSION_TURNS); // 2-5 turns
|
||||
if (skyDropState == SKY_DROP_ATTACKCANCELER_CHECK)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET;
|
||||
}
|
||||
else if (skyDropState == SKY_DROP_GRAVITY_ON_AIRBORNE)
|
||||
{
|
||||
// Reapplying STATE_SKY_DROPPED allows for avoiding unecessary messages when Gravity is applied to the target.
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_RELEASED_TARGET;
|
||||
gBattleMons[otherSkyDropper].volatiles.semiInvulnerable = STATE_SKY_DROP;
|
||||
}
|
||||
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].volatiles.rampageTurns) && gBattleStruct->skyDropTargets[battler] < 4)
|
||||
{
|
||||
gBattleStruct->skyDropTargets[battler] = SKY_DROP_NO_TARGET;
|
||||
gBattleStruct->skyDropTargets[otherSkyDropper] = SKY_DROP_NO_TARGET;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const u8 *CancelMultiTurnMoves(enum BattlerId battler, enum SkyDropState skyDropState)
|
||||
{
|
||||
const u8 *result = NULL;
|
||||
gBattleMons[battler].volatiles.uproarTurns = 0;
|
||||
gBattleMons[battler].volatiles.bideTurns = 0;
|
||||
|
||||
if (B_RAMPAGE_CANCELLING < GEN_5)
|
||||
{
|
||||
gBattleMons[battler].volatiles.multipleTurns = 0;
|
||||
gBattleMons[battler].volatiles.rampageTurns = 0;
|
||||
}
|
||||
else if (!gBattleMons[battler].volatiles.rampageTurns
|
||||
|| gBattleMons[battler].volatiles.rampageTurns > 1)
|
||||
{
|
||||
gBattleMons[battler].volatiles.multipleTurns = 0;
|
||||
}
|
||||
|
||||
// Clear battler's semi-invulnerable bits if they are not held by Sky Drop.
|
||||
if (gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
|
||||
gBattleMons[battler].volatiles.semiInvulnerable = STATE_NONE;
|
||||
|
||||
if (gBattleStruct->skyDropTargets[battler] != SKY_DROP_NO_TARGET && gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
|
||||
result = CheckSkyDropState(battler, skyDropState);
|
||||
|
||||
gBattleMons[battler].volatiles.rolloutTimer = 0;
|
||||
gBattleMons[battler].volatiles.furyCutterCounter = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
if (B_RAMPAGE_CONFUSION < GEN_5
|
||||
|| gBattleMons[battler].volatiles.rampageTurns != 1) // Will be confused at the end of the turn
|
||||
{
|
||||
gLockedMoves[battler] = MOVE_NONE;
|
||||
gBattleMons[battler].volatiles.multipleTurns = 0;
|
||||
gBattleMons[battler].volatiles.rampageTurns = 0;
|
||||
}
|
||||
|
||||
// Clear battler's semi-invulnerable bits if they are not held by Sky Drop.
|
||||
if (gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP_TARGET)
|
||||
gBattleMons[battler].volatiles.semiInvulnerable = STATE_NONE;
|
||||
|
||||
}
|
||||
|
||||
// Returns TRUE if no other battler after this one in turn order will use a move
|
||||
bool32 IsLastMonToMove(enum BattlerId battler)
|
||||
|
|
@ -1425,7 +1355,7 @@ u32 TrySetCantSelectMoveBattleScript(enum BattlerId battler)
|
|||
|
||||
if (DYNAMAX_BYPASS_CHECK && GetActiveGimmick(battler) != GIMMICK_Z_MOVE && move == gLastMoves[battler] && move != MOVE_STRUGGLE && (gBattleMons[battler].volatiles.torment == TRUE))
|
||||
{
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
CancelMultiTurnMoves(battler);
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
{
|
||||
gPalaceSelectionBattleScripts[battler] = BattleScript_SelectingTormentedMoveInPalace;
|
||||
|
|
@ -1808,7 +1738,7 @@ bool32 BattleArenaTurnEnd(void)
|
|||
&& IsBattlerAlive(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)) && IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)))
|
||||
{
|
||||
for (enum BattlerId battler = 0; battler < 2; battler++)
|
||||
CancelMultiTurnMoves(battler, SKY_DROP_IGNORE);
|
||||
CancelMultiTurnMoves(battler);
|
||||
|
||||
gBattlescriptCurrInstr = BattleScript_ArenaDoJudgment;
|
||||
BattleScriptExecute(BattleScript_ArenaDoJudgment);
|
||||
|
|
@ -4418,7 +4348,7 @@ u32 AbilityBattleEffects(enum AbilityEffect caseID, enum BattlerId battler, enum
|
|||
case ABILITY_POISON_PUPPETEER:
|
||||
if (IsRestrictedAbility(gBattlerAttacker, ABILITY_POISON_PUPPETEER)
|
||||
&& gBattleStruct->poisonPuppeteerConfusion == TRUE
|
||||
&& CanBeConfused(gBattlerTarget))
|
||||
&& CanBeConfused(gBattlerAttacker, gBattlerTarget))
|
||||
{
|
||||
gBattleStruct->poisonPuppeteerConfusion = FALSE;
|
||||
gBattleScripting.moveEffect = MOVE_EFFECT_CONFUSION;
|
||||
|
|
@ -5023,7 +4953,7 @@ bool32 CanBattlerEscape(enum BattlerId battler) // no ability check
|
|||
return FALSE;
|
||||
else if (gFieldStatuses & STATUS_FIELD_FAIRY_LOCK)
|
||||
return FALSE;
|
||||
else if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
else if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
return FALSE;
|
||||
else
|
||||
return TRUE;
|
||||
|
|
@ -5512,13 +5442,16 @@ static bool32 CanSleepDueToSleepClause(enum BattlerId battlerAtk, enum BattlerId
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanBeConfused(enum BattlerId battler)
|
||||
bool32 CanBeConfused(enum BattlerId battlerAtk, enum BattlerId effectBattler)
|
||||
{
|
||||
enum Ability ability = GetBattlerAbility(battler);
|
||||
if (gBattleMons[battler].volatiles.confusionTurns > 0
|
||||
|| IsMistyTerrainAffected(battler, ability, GetBattlerHoldEffect(battler), gFieldStatuses)
|
||||
|| IsAbilityAndRecord(battler, ability, ABILITY_OWN_TEMPO))
|
||||
enum Ability effectAbility = GetBattlerAbility(effectBattler);
|
||||
|
||||
if (gBattleMons[effectBattler].volatiles.confusionTurns > 0
|
||||
|| IsSafeguardProtected(battlerAtk, effectBattler, GetBattlerAbility(battlerAtk))
|
||||
|| IsMistyTerrainAffected(effectBattler, effectAbility, GetBattlerHoldEffect(effectBattler), gFieldStatuses)
|
||||
|| IsAbilityAndRecord(effectBattler, effectAbility, ABILITY_OWN_TEMPO))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -7424,7 +7357,7 @@ static inline uq4_12_t GetDiveModifier(enum Move move, enum BattlerId battlerDef
|
|||
|
||||
static inline uq4_12_t GetAirborneModifier(enum Move move, enum BattlerId battlerDef)
|
||||
{
|
||||
if (MoveDamagesAirborneDoubleDamage(move) && gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_ON_AIR)
|
||||
if (MoveDamagesAirborneDoubleDamage(move) && IsBattlerOnAir(battlerDef))
|
||||
return UQ_4_12(2.0);
|
||||
return UQ_4_12(1.0);
|
||||
}
|
||||
|
|
@ -8543,7 +8476,7 @@ bool32 CanMegaEvolve(enum BattlerId battler)
|
|||
return FALSE;
|
||||
|
||||
// Check if battler is currently held by Sky Drop.
|
||||
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
return FALSE;
|
||||
|
||||
// Check if battler is holding a Z-Crystal.
|
||||
|
|
@ -8584,7 +8517,7 @@ bool32 CanUltraBurst(enum BattlerId battler)
|
|||
return FALSE;
|
||||
|
||||
// Check if mon is currently held by Sky Drop
|
||||
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP)
|
||||
if (gBattleMons[battler].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET)
|
||||
return FALSE;
|
||||
|
||||
enum Ability ability = GetBattlerAbility(battler);
|
||||
|
|
@ -10057,7 +9990,7 @@ bool32 EmergencyExitCanBeTriggered(enum BattlerId battler)
|
|||
&& HadMoreThanHalfHpNowDoesnt(battler)
|
||||
&& (CanBattlerSwitch(battler) || !(gBattleTypeFlags & BATTLE_TYPE_TRAINER))
|
||||
&& !(gBattleTypeFlags & BATTLE_TYPE_ARENA)
|
||||
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP)
|
||||
&& gBattleMons[battler].volatiles.semiInvulnerable != STATE_SKY_DROP_TARGET)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
|
|
@ -10259,6 +10192,14 @@ static bool32 CanMoveSkipAccuracyCheck(enum BattlerId battlerAtk, u32 move)
|
|||
return MoveAlwaysHitsOnSameType(move) && IS_BATTLER_OF_TYPE(battlerAtk, GetMoveType(move));
|
||||
}
|
||||
|
||||
static bool32 IsSkyDropInvolved(enum BattlerId battlerDef, enum BattleMoveEffects moveEffect)
|
||||
{
|
||||
if (moveEffect != EFFECT_SKY_DROP)
|
||||
return FALSE;
|
||||
return gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_SKY_DROP_ATTACKER
|
||||
|| gBattleMons[battlerDef].volatiles.semiInvulnerable == STATE_SKY_DROP_TARGET;
|
||||
}
|
||||
|
||||
bool32 CanMoveSkipAccuracyCalc(enum BattlerId battlerAtk, enum BattlerId battlerDef, enum Ability abilityAtk, enum Ability abilityDef, enum Move move, enum ResultOption option)
|
||||
{
|
||||
bool32 effect = FALSE;
|
||||
|
|
@ -10271,17 +10212,14 @@ bool32 CanMoveSkipAccuracyCalc(enum BattlerId battlerAtk, enum BattlerId battler
|
|||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
// 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 (abilityAtk == ABILITY_NO_GUARD
|
||||
&& gBattleMons[battlerDef].volatiles.semiInvulnerable != STATE_COMMANDER
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battlerDef] == SKY_DROP_NO_TARGET))
|
||||
&& !IsSkyDropInvolved(battlerDef, moveEffect))
|
||||
{
|
||||
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 (abilityDef == ABILITY_NO_GUARD
|
||||
&& (moveEffect != EFFECT_SKY_DROP || gBattleStruct->skyDropTargets[battlerDef] == SKY_DROP_NO_TARGET))
|
||||
else if (abilityDef == ABILITY_NO_GUARD && !IsSkyDropInvolved(battlerDef, moveEffect))
|
||||
{
|
||||
effect = TRUE;
|
||||
ability = ABILITY_NO_GUARD;
|
||||
|
|
@ -10569,7 +10507,8 @@ static bool32 CanBreakThroughSemiInvulnerablityInternal(enum BattlerId battlerAt
|
|||
case STATE_UNDERWATER:
|
||||
return MoveDamagesUnderWater(move);
|
||||
case STATE_ON_AIR:
|
||||
case STATE_SKY_DROP:
|
||||
case STATE_SKY_DROP_ATTACKER:
|
||||
case STATE_SKY_DROP_TARGET:
|
||||
return MoveDamagesAirborne(move) || MoveDamagesAirborneDoubleDamage(move);
|
||||
case STATE_PHANTOM_FORCE:
|
||||
return FALSE;
|
||||
|
|
@ -10593,6 +10532,19 @@ bool32 BreaksThroughSemiInvulnerableState(enum BattlerId battlerAtk, enum Battle
|
|||
return CanBreakThroughSemiInvulnerablityInternal(battlerAtk, battlerDef, abilityAtk, abilityDef, move, state);
|
||||
}
|
||||
|
||||
bool32 IsBattlerOnAir(enum BattlerId battler)
|
||||
{
|
||||
switch (gBattleMons[battler].volatiles.semiInvulnerable)
|
||||
{
|
||||
case STATE_ON_AIR:
|
||||
case STATE_SKY_DROP_ATTACKER:
|
||||
case STATE_SKY_DROP_TARGET:
|
||||
return TRUE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
bool32 HasPartnerTrainer(enum BattlerId battler)
|
||||
{
|
||||
if ((GetBattlerSide(battler) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_PLAYER_HAS_PARTNER)
|
||||
|
|
|
|||
|
|
@ -208,3 +208,86 @@ DOUBLE_BATTLE_TEST("Sky Drop does not trigger Volt Absorb on it's charge turn")
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop: If target was locked into a move that would confuse, the target will be freed and confusion occurs immediately")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_TORKOAL) { Ability(ABILITY_DROUGHT); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THRASH); MOVE(opponent, MOVE_SKY_DROP);}
|
||||
TURN { SKIP_TURN(opponent); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_DROUGHT);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, opponent);
|
||||
HP_BAR(player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player);
|
||||
MESSAGE("The sunlight is strong.");
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sky Drop: If target was locked into a move that would confuse, the target will be freed and confusion occurs immediately (attacker faints due to status)")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(2); Status1(STATUS1_BURN); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_THRASH, target: opponentRight);
|
||||
MOVE(opponentLeft, MOVE_SKY_DROP, target: playerLeft);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Sky Drop: If target was locked into a move that would confuse, the target will be freed and confusion occurs immediately (attacker faints due to target ability)")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_SHARPEDO) { Ability(ABILITY_ROUGH_SKIN); }
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); MaxHP(2); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN {
|
||||
MOVE(playerLeft, MOVE_THRASH, target: opponentRight);
|
||||
MOVE(opponentLeft, MOVE_SKY_DROP, target: playerLeft);
|
||||
}
|
||||
TURN {
|
||||
SKIP_TURN(opponentLeft);
|
||||
SEND_OUT(opponentLeft, 2);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, opponentLeft); // 1st turn
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, opponentLeft); // 2nd turn
|
||||
ABILITY_POPUP(playerLeft, ABILITY_ROUGH_SKIN);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, playerLeft);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Sky Drop: Flying types will still get confused if they rampaged before being dropped")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gSpeciesInfo[SPECIES_PIDGEY].weight < 2000);
|
||||
ASSUME(GetSpeciesType(SPECIES_PIDGEY, 1) == TYPE_FLYING);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_THRASH); MOVE(player, MOVE_SKY_DROP); }
|
||||
TURN { SKIP_TURN(player); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, opponent);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SKY_DROP, player);
|
||||
NOT HP_BAR(opponent);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, opponent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ SINGLE_BATTLE_TEST("Thrash does not confuse the user if it is canceled on turn 2
|
|||
SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3, Protect")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(B_RAMPAGE_CANCELLING >= GEN_5);
|
||||
WITH_CONFIG(B_RAMPAGE_CONFUSION, GEN_5);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
|
|
@ -89,7 +89,7 @@ SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3, P
|
|||
SINGLE_BATTLE_TEST("Thrash confuses the user if it is canceled on turn 3 of 3, Immunity")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(B_RAMPAGE_CANCELLING >= GEN_5);
|
||||
WITH_CONFIG(B_RAMPAGE_CONFUSION, GEN_5);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GENGAR);
|
||||
|
|
@ -117,3 +117,24 @@ SINGLE_BATTLE_TEST("Petal Dance does not lock mons that copy the move with Dance
|
|||
EXPECT(!(opponent->volatiles.multipleTurns));
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Thrash confuses the user after it finishes even if move failed")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { MovesWithPP({MOVE_THRASH, 10}); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_GASTLY);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_THRASH); }
|
||||
TURN { SKIP_TURN(player); }
|
||||
TURN { SWITCH(opponent, 1); SKIP_TURN(player); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
NOT ANIMATION(ANIM_TYPE_MOVE, MOVE_THRASH, player);
|
||||
ANIMATION(ANIM_TYPE_STATUS, B_ANIM_STATUS_CONFUSION, player);
|
||||
} THEN {
|
||||
// Check that PP has been consumed correctly
|
||||
EXPECT_EQ(player->pp[0], 9);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user