General MoveEnd clean up and Fell Stinger adjustments (#6674)
This commit is contained in:
parent
1871d16ffa
commit
6fe5f6530a
@ -1954,10 +1954,6 @@
|
||||
various BS_ATTACKER, VARIOUS_TRY_ACTIVATE_SOULHEART
|
||||
.endm
|
||||
|
||||
.macro tryactivatefellstinger battler:req
|
||||
various \battler, VARIOUS_TRY_ACTIVATE_FELL_STINGER
|
||||
.endm
|
||||
|
||||
.macro playmoveanimation battler:req, move:req
|
||||
various \battler, VARIOUS_PLAY_MOVE_ANIMATION
|
||||
.2byte \move
|
||||
|
||||
@ -5233,7 +5233,6 @@ BattleScript_FaintTarget::
|
||||
dofaintanimation BS_TARGET
|
||||
printstring STRINGID_TARGETFAINTED
|
||||
cleareffectsonfaint BS_TARGET
|
||||
tryactivatefellstinger BS_ATTACKER
|
||||
tryactivatesoulheart
|
||||
tryactivatereceiver BS_TARGET
|
||||
trytrainerslidefirstdownmsg BS_TARGET
|
||||
|
||||
@ -121,7 +121,6 @@ enum CmdVarious
|
||||
VARIOUS_INSTANT_HP_DROP,
|
||||
VARIOUS_CLEAR_STATUS,
|
||||
VARIOUS_RESTORE_PP,
|
||||
VARIOUS_TRY_ACTIVATE_FELL_STINGER,
|
||||
VARIOUS_PLAY_MOVE_ANIMATION,
|
||||
VARIOUS_SET_LUCKY_CHANT,
|
||||
VARIOUS_SUCKER_PUNCH_CHECK,
|
||||
@ -262,7 +261,7 @@ enum MoveEndEffects
|
||||
MOVEEND_ATTACKER_VISIBLE,
|
||||
MOVEEND_TARGET_VISIBLE,
|
||||
MOVEEND_ITEM_EFFECTS_TARGET,
|
||||
MOVEEND_MOVE_EFFECTS2,
|
||||
MOVEEND_FIRST_MOVE_BLOCK,
|
||||
MOVEEND_ITEM_EFFECTS_ALL,
|
||||
MOVEEND_SYMBIOSIS,
|
||||
MOVEEND_HIT_SWITCH_TARGET,
|
||||
@ -271,14 +270,13 @@ enum MoveEndEffects
|
||||
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 multi-hit move
|
||||
MOVEEND_NEXT_TARGET, // Everything up until here is handled for each strike of a spread move
|
||||
MOVEEND_MULTIHIT_MOVE,
|
||||
MOVEEND_DEFROST,
|
||||
MOVEEND_RECOIL,
|
||||
MOVEEND_RAPID_SPIN,
|
||||
MOVEEND_SECOND_MOVE_BLOCK,
|
||||
MOVEEND_ITEM_EFFECTS_ATTACKER,
|
||||
MOVEEND_ABILITY_BLOCK,
|
||||
MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Eject Pack
|
||||
MOVEEND_SHEER_FORCE, // If move is Sheer Force affected, skip until Opportunist
|
||||
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
|
||||
MOVEEND_EJECT_BUTTON,
|
||||
MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc
|
||||
|
||||
@ -15,6 +15,7 @@ enum GenConfigTag
|
||||
GEN_CONFIG_MOODY_STATS,
|
||||
GEN_CONFIG_BATTLE_BOND,
|
||||
GEN_CONFIG_ATE_MULTIPLIER,
|
||||
GEN_CONFIG_FELL_STINGER_STAT_RAISE,
|
||||
GEN_CONFIG_COUNT
|
||||
};
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ static const u8 sGenerationalChanges[GEN_CONFIG_COUNT] =
|
||||
[GEN_CONFIG_TELEPORT_BEHAVIOR] = B_TELEPORT_BEHAVIOR,
|
||||
[GEN_CONFIG_MOODY_STATS] = B_MOODY_ACC_EVASION,
|
||||
[GEN_CONFIG_BATTLE_BOND] = B_BATTLE_BOND,
|
||||
[GEN_CONFIG_FELL_STINGER_STAT_RAISE] = B_FELL_STINGER_STAT_RAISE,
|
||||
[GEN_CONFIG_ATE_MULTIPLIER] = B_ATE_MULTIPLIER,
|
||||
};
|
||||
|
||||
|
||||
@ -1540,8 +1540,18 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler)
|
||||
gBattleStruct->moveResultFlags[battler] |= MOVE_RESULT_MISSED;
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (B_MINIMIZE_DMG_ACC >= GEN_6
|
||||
&& (gStatuses3[battler] & STATUS3_MINIMIZED)
|
||||
&& MoveIncreasesPowerToMinimizedTargets(move))
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetMoveAccuracy(move) == 0)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
|
||||
if (HasWeatherEffect())
|
||||
if (!effect && HasWeatherEffect())
|
||||
{
|
||||
if ((moveEffect == EFFECT_THUNDER || moveEffect == EFFECT_RAIN_ALWAYS_HIT)
|
||||
&& IsBattlerWeatherAffected(battler, B_WEATHER_RAIN))
|
||||
@ -1553,17 +1563,6 @@ static bool32 AccuracyCalcHelper(u32 move, u32 battler)
|
||||
return effect;
|
||||
}
|
||||
|
||||
if (B_MINIMIZE_DMG_ACC >= GEN_6
|
||||
&& (gStatuses3[battler] & STATUS3_MINIMIZED)
|
||||
&& MoveIncreasesPowerToMinimizedTargets(move))
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (GetMoveAccuracy(move) == 0)
|
||||
{
|
||||
effect = TRUE;
|
||||
}
|
||||
|
||||
if (ability != ABILITY_NONE)
|
||||
RecordAbilityBattle(gBattlerAttacker, ABILITY_NO_GUARD);
|
||||
|
||||
@ -6210,7 +6209,6 @@ static bool32 HandleMoveEndAbilityBlock(u32 battlerAtk, u32 battlerDef, u32 move
|
||||
if (gBattleStruct->battleBondBoost[side] & (1u << gBattlerPartyIndexes[battlerAtk]))
|
||||
break;
|
||||
|
||||
|
||||
if (GetGenConfig(GEN_CONFIG_BATTLE_BOND) < GEN_9 && gBattleMons[battlerAtk].species == SPECIES_GRENINJA_BATTLE_BOND)
|
||||
{
|
||||
// TODO: Convert this to a proper FORM_CHANGE type.
|
||||
@ -6381,13 +6379,7 @@ static void Cmd_moveend(void)
|
||||
effect = 1;
|
||||
}
|
||||
break;
|
||||
case PROTECT_NONE:
|
||||
case PROTECT_NORMAL:
|
||||
case PROTECT_MAX_GUARD:
|
||||
case PROTECT_WIDE_GUARD:
|
||||
case PROTECT_QUICK_GUARD:
|
||||
case PROTECT_CRAFTY_SHIELD:
|
||||
case PROTECT_MAT_BLOCK:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -6410,33 +6402,27 @@ static void Cmd_moveend(void)
|
||||
case MOVEEND_ABSORB:
|
||||
if (moveEffect == EFFECT_ABSORB
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& !(gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget))
|
||||
{
|
||||
if (gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && IsHealingMove(gCurrentMove))
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100));
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]);
|
||||
gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE;
|
||||
effect = TRUE;
|
||||
if (GetBattlerAbility(gBattlerTarget) == ABILITY_LIQUID_OOZE)
|
||||
{
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] *= -1;
|
||||
gHitMarker |= HITMARKER_PASSIVE_DAMAGE;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB_OOZE;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EffectAbsorbLiquidOoze;
|
||||
}
|
||||
else if (IsBattlerAlive(gBattlerAttacker) && !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
else
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, (gBattleStruct->moveDamage[gBattlerTarget] * GetMoveAbsorbPercentage(gCurrentMove) / 100));
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetDrainedBigRootHp(gBattlerAttacker, gBattleStruct->moveDamage[gBattlerAttacker]);
|
||||
gHitMarker |= HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_IGNORE_DISGUISE;
|
||||
effect = TRUE;
|
||||
if (GetBattlerAbility(gBattlerTarget) == ABILITY_LIQUID_OOZE)
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] *= -1;
|
||||
gHitMarker |= HITMARKER_PASSIVE_DAMAGE;
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB_OOZE;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EffectAbsorbLiquidOoze;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EffectAbsorb;
|
||||
}
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ABSORB;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_EffectAbsorb;
|
||||
}
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
@ -6458,109 +6444,6 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_DEFROST: // defrosting check
|
||||
if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& gBattlerAttacker != gBattlerTarget
|
||||
&& (moveType == TYPE_FIRE || CanBurnHitThaw(gCurrentMove))
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FREEZE;
|
||||
BtlController_EmitSetMonData(gBattlerTarget, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
|
||||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove;
|
||||
effect = TRUE;
|
||||
}
|
||||
if (gBattleMons[gBattlerTarget].status1 & STATUS1_FROSTBITE
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& gBattlerAttacker != gBattlerTarget
|
||||
&& MoveThawsUser(originallyUsedMove)
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE;
|
||||
BtlController_EmitSetMonData(gBattlerTarget, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
|
||||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_FrostbiteHealedViaFireMove;
|
||||
effect = TRUE;
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_RECOIL:
|
||||
{
|
||||
u32 moveRecoil = GetMoveRecoil(gCurrentMove);
|
||||
if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
{
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
else if (GetMoveEffect(gCurrentMove) == EFFECT_RECOIL_IF_MISS
|
||||
&& (!IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& !gBattleStruct->noTargetPresent
|
||||
&& IsBattlerAlive(gBattlerAttacker))
|
||||
{
|
||||
if (B_RECOIL_IF_MISS_DMG >= GEN_5 || (B_CRASH_IF_TARGET_IMMUNE == GEN_4 && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_DOESNT_AFFECT_FOE))
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
|
||||
else if (B_RECOIL_IF_MISS_DMG == GEN_4 && (GetNonDynamaxMaxHP(gBattlerTarget) / 2) < gBattleStruct->moveDamage[gBattlerTarget])
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
|
||||
else // Fallback if B_RECOIL_IF_MISS_DMG is set to gen3 or lower.
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
|
||||
|
||||
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = 1;
|
||||
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_RecoilIfMiss;
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (moveEffect == EFFECT_RECOIL
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget))
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleStruct->moveDamage[gBattlerTarget] * max(1, moveRecoil) / 100);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil;
|
||||
effect = TRUE;
|
||||
}
|
||||
else if (moveEffect == EFFECT_EXPLOSION && !IsAbilityOnField(ABILITY_DAMP))
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = 0;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_FaintAttackerForExplosion;
|
||||
effect = TRUE;
|
||||
}
|
||||
else if ((moveEffect == EFFECT_MAX_HP_50_RECOIL || moveEffect == EFFECT_MIND_BLOWN)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_MaxHp50Recoil;
|
||||
effect = TRUE;
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
case MOVEEND_RAPID_SPIN:
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_RAPID_SPIN
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget))
|
||||
{
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_RapidSpinAway;
|
||||
effect = TRUE;
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ITEM_EFFECTS_ATTACKER:
|
||||
if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker, FALSE))
|
||||
effect = TRUE;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_SYNCHRONIZE_TARGET: // target synchronize
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_SYNCHRONIZE, gBattlerTarget, 0, 0, 0))
|
||||
effect = TRUE;
|
||||
@ -6576,12 +6459,6 @@ static void Cmd_moveend(void)
|
||||
effect = TRUE;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_OPPORTUNIST:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
|
||||
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
|
||||
else
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_STATUS_IMMUNITY_ABILITIES: // status immunities
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0))
|
||||
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
|
||||
@ -6622,23 +6499,12 @@ static void Cmd_moveend(void)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
case MOVEEND_CHANGED_ITEMS: // changed held items
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattleStruct->changedItems[i] != ITEM_NONE)
|
||||
{
|
||||
gBattleMons[i].item = gBattleStruct->changedItems[i];
|
||||
gBattleStruct->changedItems[i] = ITEM_NONE;
|
||||
}
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ITEM_EFFECTS_TARGET:
|
||||
if (ItemBattleEffects(ITEMEFFECT_TARGET, gBattlerTarget, FALSE))
|
||||
effect = TRUE;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_MOVE_EFFECTS2: // For effects which should happen after target items, for example Knock Off after damage from Rocky Helmet.
|
||||
case MOVEEND_FIRST_MOVE_BLOCK: // For effects which should happen after target items, for example Knock Off after damage from Rocky Helmet.
|
||||
{
|
||||
switch (gBattleStruct->moveEffect2)
|
||||
{
|
||||
@ -6803,7 +6669,7 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_SUBSTITUTE: // update substitute
|
||||
case MOVEEND_SUBSTITUTE:
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gDisableStructs[i].substituteHP == 0)
|
||||
@ -7062,6 +6928,126 @@ static void Cmd_moveend(void)
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
case MOVEEND_DEFROST:
|
||||
if (gBattleMons[gBattlerTarget].status1 & STATUS1_FREEZE
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& gBattlerAttacker != gBattlerTarget
|
||||
&& (moveType == TYPE_FIRE || CanBurnHitThaw(gCurrentMove))
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FREEZE;
|
||||
BtlController_EmitSetMonData(gBattlerTarget, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
|
||||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_DefrostedViaFireMove;
|
||||
effect = TRUE;
|
||||
}
|
||||
if (gBattleMons[gBattlerTarget].status1 & STATUS1_FROSTBITE
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& gBattlerAttacker != gBattlerTarget
|
||||
&& MoveThawsUser(originallyUsedMove)
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
|
||||
{
|
||||
gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE;
|
||||
BtlController_EmitSetMonData(gBattlerTarget, BUFFER_A, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
|
||||
MarkBattlerForControllerExec(gBattlerTarget);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_FrostbiteHealedViaFireMove;
|
||||
effect = TRUE;
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_SECOND_MOVE_BLOCK:
|
||||
if (gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
{
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (moveEffect)
|
||||
{
|
||||
case EFFECT_RECOIL_IF_MISS:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& (!IsBattlerTurnDamaged(gBattlerTarget) || gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& !gBattleStruct->noTargetPresent)
|
||||
{
|
||||
if (B_RECOIL_IF_MISS_DMG >= GEN_5 || (B_CRASH_IF_TARGET_IMMUNE == GEN_4 && gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_DOESNT_AFFECT_FOE))
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 2;
|
||||
else if (B_RECOIL_IF_MISS_DMG == GEN_4 && (GetNonDynamaxMaxHP(gBattlerTarget) / 2) < gBattleStruct->moveDamage[gBattlerTarget])
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
|
||||
else // Fallback if B_RECOIL_IF_MISS_DMG is set to gen3 or lower.
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerTarget) / 2;
|
||||
|
||||
if (gBattleStruct->moveDamage[gBattlerAttacker] == 0)
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = 1;
|
||||
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_RecoilIfMiss;
|
||||
effect = TRUE;
|
||||
}
|
||||
break;
|
||||
case EFFECT_RECOIL:
|
||||
if (IsBattlerTurnDamaged(gBattlerTarget) && IsBattlerAlive(gBattlerAttacker))
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = max(1, gBattleStruct->moveDamage[gBattlerTarget] * max(1, GetMoveRecoil(gCurrentMove)) / 100);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEffectRecoil;
|
||||
effect = TRUE;
|
||||
}
|
||||
break;
|
||||
case EFFECT_EXPLOSION:
|
||||
if (!IsAbilityOnField(ABILITY_DAMP))
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = 0;
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_FaintAttackerForExplosion;
|
||||
effect = TRUE;
|
||||
}
|
||||
break;
|
||||
case EFFECT_MAX_HP_50_RECOIL:
|
||||
case EFFECT_MIND_BLOWN:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_FAILED)
|
||||
&& GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD)
|
||||
{
|
||||
gBattleStruct->moveDamage[gBattlerAttacker] = (GetNonDynamaxMaxHP(gBattlerAttacker) + 1) / 2; // Half of Max HP Rounded UP
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_MaxHp50Recoil;
|
||||
effect = TRUE;
|
||||
}
|
||||
break;
|
||||
case EFFECT_RAPID_SPIN:
|
||||
if (IsBattlerTurnDamaged(gBattlerTarget))
|
||||
{
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_RapidSpinAway;
|
||||
effect = TRUE;
|
||||
}
|
||||
break;
|
||||
case EFFECT_FELL_STINGER:
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& !IsBattlerAlive(gBattlerTarget)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& !NoAliveMonsForEitherParty()
|
||||
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
SET_STATCHANGER(STAT_ATK, GetGenConfig(GEN_CONFIG_FELL_STINGER_STAT_RAISE) >= GEN_7 ? 3 : 2, FALSE);
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
|
||||
BattleScriptPushCursor();
|
||||
gBattlescriptCurrInstr = BattleScript_FellStingerRaisesStat;
|
||||
effect = TRUE;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ITEM_EFFECTS_ATTACKER:
|
||||
if (ItemBattleEffects(ITEMEFFECT_MOVE_END, gBattlerAttacker, FALSE))
|
||||
effect = TRUE;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_ABILITY_BLOCK:
|
||||
effect = HandleMoveEndAbilityBlock(gBattlerAttacker, gBattlerTarget, gCurrentMove);
|
||||
gBattleScripting.moveendState++;
|
||||
@ -7316,9 +7302,6 @@ static void Cmd_moveend(void)
|
||||
if (!(emergencyExitBattlers & 1u << battler))
|
||||
continue;
|
||||
|
||||
if (moveEffect == EFFECT_HIT_ESCAPE)
|
||||
gBattlescriptCurrInstr = BattleScript_MoveEnd; // Prevent user switch-in selection
|
||||
|
||||
effect = TRUE;
|
||||
gBattleScripting.battler = battler;
|
||||
BattleScriptPushCursor();
|
||||
@ -7349,6 +7332,12 @@ static void Cmd_moveend(void)
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_OPPORTUNIST:
|
||||
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
|
||||
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
|
||||
else
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_SYMBIOSIS:
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
@ -7376,6 +7365,17 @@ static void Cmd_moveend(void)
|
||||
gBattleStruct->sameMoveTurns[gBattlerAttacker]++;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_CHANGED_ITEMS:
|
||||
for (i = 0; i < gBattlersCount; i++)
|
||||
{
|
||||
if (gBattleStruct->changedItems[i] != ITEM_NONE)
|
||||
{
|
||||
gBattleMons[i].item = gBattleStruct->changedItems[i];
|
||||
gBattleStruct->changedItems[i] = ITEM_NONE;
|
||||
}
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_CLEAR_BITS: // Clear/Set bits for things like using a move for all targets and all hits.
|
||||
if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget)
|
||||
gBattleStruct->moveTarget[gBattlerAttacker] = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3;
|
||||
@ -9587,20 +9587,6 @@ static void Cmd_useitemonopponent(void)
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static bool32 HasAttackerFaintedTarget(void)
|
||||
{
|
||||
if (!(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& !IsBattleMoveStatus(gCurrentMove)
|
||||
&& (gLastHitBy[gBattlerTarget] == 0xFF || gLastHitBy[gBattlerTarget] == gBattlerAttacker)
|
||||
&& gBattleStruct->moveTarget[gBattlerAttacker] == gBattlerTarget
|
||||
&& gBattlerTarget != gBattlerAttacker
|
||||
&& gCurrentTurnActionNumber == GetBattlerTurnOrderNum(gBattlerAttacker)
|
||||
&& (gChosenMove == gChosenMoveByBattler[gBattlerAttacker] || gChosenMove == gBattleMons[gBattlerAttacker].moves[gChosenMovePos] || gChosenMove == GetMaxMove(gBattlerAttacker, gChosenMoveByBattler[gBattlerAttacker])))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 CanUseLastResort(u8 battler)
|
||||
{
|
||||
u32 i;
|
||||
@ -10615,23 +10601,6 @@ static void Cmd_various(void)
|
||||
gBattleStruct->soulheartBattlerId = 0;
|
||||
break;
|
||||
}
|
||||
case VARIOUS_TRY_ACTIVATE_FELL_STINGER:
|
||||
{
|
||||
VARIOUS_ARGS();
|
||||
if (GetMoveEffect(gCurrentMove) == EFFECT_FELL_STINGER
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& HasAttackerFaintedTarget()
|
||||
&& !NoAliveMonsForEitherParty()
|
||||
&& CompareStat(gBattlerAttacker, STAT_ATK, MAX_STAT_STAGE, CMP_LESS_THAN))
|
||||
{
|
||||
SET_STATCHANGER(STAT_ATK, (B_FELL_STINGER_STAT_RAISE >= GEN_7 ? 3 : 2), FALSE);
|
||||
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
|
||||
BattleScriptPush(cmd->nextInstr);
|
||||
gBattlescriptCurrInstr = BattleScript_FellStingerRaisesStat;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VARIOUS_PLAY_MOVE_ANIMATION:
|
||||
{
|
||||
VARIOUS_ARGS(u16 move);
|
||||
|
||||
43
test/battle/move_effect/fell_stinger.c
Normal file
43
test/battle/move_effect/fell_stinger.c
Normal file
@ -0,0 +1,43 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Fell Stinger raises user's Attack by 3 stages if it faints target")
|
||||
{
|
||||
u32 config;
|
||||
|
||||
PARAMETRIZE { config = GEN_7; }
|
||||
PARAMETRIZE { config = GEN_6; }
|
||||
|
||||
GIVEN {
|
||||
WITH_CONFIG(GEN_CONFIG_FELL_STINGER_STAT_RAISE, config);
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FELL_STINGER); }
|
||||
OPPONENT(SPECIES_WOBBUFFET) { HP(1); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FELL_STINGER); SEND_OUT(opponent, 1); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, player);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
if (config == GEN_7)
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 3);
|
||||
else
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Fell Stinger doesn't raise user's Attack if it doesn't faint target")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Moves(MOVE_FELL_STINGER); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_FELL_STINGER); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, player);
|
||||
NOT ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, player);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_ATK], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user