Clean up for Moveend

This commit is contained in:
AlexOn1ine 2025-07-02 17:25:03 +02:00
parent bdb0989030
commit 734a15478c
3 changed files with 194 additions and 194 deletions

View File

@ -6568,6 +6568,24 @@ static void Cmd_moveend(void)
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_SYMBIOSIS:
for (i = 0; i < gBattlersCount; i++)
{
if ((gSpecialStatuses[i].berryReduced
|| (B_SYMBIOSIS_GEMS >= GEN_7 && gSpecialStatuses[i].gemBoost))
&& TryTriggerSymbiosis(i, BATTLE_PARTNER(i)))
{
BestowItem(BATTLE_PARTNER(i), i);
gLastUsedAbility = gBattleMons[BATTLE_PARTNER(i)].ability;
gBattleScripting.battler = gBattlerAbility = BATTLE_PARTNER(i);
gBattlerAttacker = i;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_SymbiosisActivates;
effect = TRUE;
}
}
gBattleScripting.moveendState++;
break;
case MOVEEND_FIRST_MOVE_BLOCK:
if ((gSpecialStatuses[gBattlerAttacker].parentalBondState == PARENTAL_BOND_1ST_HIT && IsBattlerAlive(gBattlerTarget))
|| gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT
@ -6640,12 +6658,6 @@ static void Cmd_moveend(void)
else
gBattleScripting.moveendState++;
break;
case MOVEEND_KINGSROCK: // King's rock
// These effects will occur at each hit in a multi-strike move
if (ItemBattleEffects(ITEMEFFECT_KINGSROCK, 0, FALSE))
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_ATTACKER_INVISIBLE: // make attacker sprite invisible
if (gStatuses3[gBattlerAttacker] & (STATUS3_SEMI_INVULNERABLE)
&& gHitMarker & (HITMARKER_NO_ANIMATIONS | HITMARKER_DISABLE_ANIMATION))
@ -6683,6 +6695,12 @@ static void Cmd_moveend(void)
}
gBattleScripting.moveendState++;
break;
case MOVEEND_KINGSROCK: // King's rock
// These effects will occur at each hit in a multi-strike move
if (ItemBattleEffects(ITEMEFFECT_KINGSROCK, 0, FALSE))
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_SUBSTITUTE:
for (i = 0; i < gBattlersCount; i++)
{
@ -6819,6 +6837,37 @@ 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, B_COMM_TO_CONTROLLER, 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
&& IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerTarget)
&& gBattlerAttacker != gBattlerTarget
&& MoveThawsUser(originallyUsedMove)
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
{
gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE;
BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, REQUEST_STATUS_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].status1), &gBattleMons[gBattlerTarget].status1);
MarkBattlerForControllerExec(gBattlerTarget);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_FrostbiteHealedViaFireMove;
effect = TRUE;
}
gBattleScripting.moveendState++;
break;
case MOVEEND_NEXT_TARGET: // For moves hitting two opposing Pokemon.
{
u16 moveTarget = GetBattlerMoveTargetType(gBattlerAttacker, gCurrentMove);
@ -6942,37 +6991,6 @@ 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, B_COMM_TO_CONTROLLER, 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
&& IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerTarget)
&& gBattlerAttacker != gBattlerTarget
&& MoveThawsUser(originallyUsedMove)
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT))
{
gBattleMons[gBattlerTarget].status1 &= ~STATUS1_FROSTBITE;
BtlController_EmitSetMonData(gBattlerTarget, B_COMM_TO_CONTROLLER, 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)
{
@ -7083,6 +7101,57 @@ static void Cmd_moveend(void)
else
gBattleScripting.moveendState++;
break;
case MOVEEND_RED_CARD:
{
u32 redCardBattlers = 0, i;
for (i = 0; i < gBattlersCount; i++)
{
if (i == gBattlerAttacker)
continue;
if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_RED_CARD)
redCardBattlers |= (1u << i);
}
if (redCardBattlers && IsBattlerAlive(gBattlerAttacker))
{
// Since we check if battler was damaged, we don't need to check move result.
// In fact, doing so actually prevents multi-target moves from activating red card properly
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u32 battler = battlers[i];
// Search for fastest hit pokemon with a red card
// Attacker is the one to be switched out, battler is one with red card
if (redCardBattlers & (1u << battler)
&& IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& IsBattlerTurnDamaged(battler)
&& CanBattlerSwitch(gBattlerAttacker)
&& !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battler)))
{
effect = TRUE;
gLastUsedItem = gBattleMons[battler].item;
SaveBattlerTarget(battler); // save battler with red card
SaveBattlerAttacker(gBattlerAttacker);
gBattleScripting.battler = battler;
gEffectBattler = gBattlerAttacker;
BattleScriptPushCursor();
if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE
|| GetBattlerAbility(gBattlerAttacker) == ABILITY_GUARD_DOG
|| GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX)
gBattlescriptCurrInstr = BattleScript_RedCardActivationNoSwitch;
else
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
break; // Only fastest red card activates
}
}
}
}
if (effect)
gBattleScripting.moveendState = MOVEEND_OPPORTUNIST;
else
gBattleScripting.moveendState++;
break;
case MOVEEND_EJECT_BUTTON:
{
// Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items.
@ -7130,6 +7199,61 @@ static void Cmd_moveend(void)
else
gBattleScripting.moveendState++;
break;
case MOVEEND_LIFEORB_SHELLBELL:
if (ItemBattleEffects(ITEMEFFECT_LIFEORB_SHELLBELL, 0, FALSE))
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out
{
// Because sorting the battlers by speed takes lots of cycles,
// we check if EE can be activated and cound how many.
u32 numEmergencyExitBattlers = 0;
u32 emergencyExitBattlers = 0;
for (i = 0; i < gBattlersCount; i++)
{
if (EmergencyExitCanBeTriggered(i))
{
emergencyExitBattlers |= 1u << i;
numEmergencyExitBattlers++;
}
}
if (numEmergencyExitBattlers == 0)
{
gBattleScripting.moveendState++;
break;
}
u8 battlers[4] = {0, 1, 2, 3};
if (numEmergencyExitBattlers > 1)
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u32 battler = battlers[i];
if (!(emergencyExitBattlers & 1u << battler))
continue;
effect = TRUE;
gBattleScripting.battler = battler;
BattleScriptPushCursor();
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER || IsOnPlayerSide(battler))
gBattlescriptCurrInstr = BattleScript_EmergencyExit;
else
gBattlescriptCurrInstr = BattleScript_EmergencyExitWild;
break; // Only the fastest Emergency Exit / Wimp Out activates
}
}
if (effect)
gBattleScripting.moveendState = MOVEEND_OPPORTUNIST;
else
gBattleScripting.moveendState++;
break;
case MOVEEND_EJECT_PACK:
{
// Because sorting the battlers by speed takes lots of cycles, it's better to just check if any of the battlers has the Eject items.
@ -7184,80 +7308,25 @@ static void Cmd_moveend(void)
else
gBattleScripting.moveendState++;
break;
case MOVEEND_WHITE_HERB:
for (i = 0; i < gBattlersCount; i++)
case MOVEEND_HIT_ESCAPE:
if (moveEffect == EFFECT_HIT_ESCAPE
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerAttacker)
&& !NoAliveMonsForBattlerSide(gBattlerTarget))
{
if (!IsBattlerAlive(i))
continue;
if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_WHITE_HERB
&& RestoreWhiteHerbStats(i))
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
effect = TRUE;
break;
}
effect = TRUE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_EffectHitEscape;
}
if (!effect)
gBattleScripting.moveendState++;
gBattleScripting.moveendState++;
break;
case MOVEEND_RED_CARD:
{
u32 redCardBattlers = 0, i;
for (i = 0; i < gBattlersCount; i++)
{
if (i == gBattlerAttacker)
continue;
if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_RED_CARD)
redCardBattlers |= (1u << i);
}
if (redCardBattlers && IsBattlerAlive(gBattlerAttacker))
{
// Since we check if battler was damaged, we don't need to check move result.
// In fact, doing so actually prevents multi-target moves from activating red card properly
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u32 battler = battlers[i];
// Search for fastest hit pokemon with a red card
// Attacker is the one to be switched out, battler is one with red card
if (redCardBattlers & (1u << battler)
&& IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& IsBattlerTurnDamaged(battler)
&& CanBattlerSwitch(gBattlerAttacker)
&& !(moveEffect == EFFECT_HIT_SWITCH_TARGET && CanBattlerSwitch(battler)))
{
effect = TRUE;
gLastUsedItem = gBattleMons[battler].item;
SaveBattlerTarget(battler); // save battler with red card
SaveBattlerAttacker(gBattlerAttacker);
gBattleScripting.battler = battler;
gEffectBattler = gBattlerAttacker;
BattleScriptPushCursor();
if (gBattleStruct->commanderActive[gBattlerAttacker] != SPECIES_NONE
|| GetBattlerAbility(gBattlerAttacker) == ABILITY_GUARD_DOG
|| GetActiveGimmick(gBattlerAttacker) == GIMMICK_DYNAMAX)
gBattlescriptCurrInstr = BattleScript_RedCardActivationNoSwitch;
else
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
break; // Only fastest red card activates
}
}
}
}
if (effect)
gBattleScripting.moveendState = MOVEEND_OPPORTUNIST;
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_LIFEORB_SHELLBELL:
if (ItemBattleEffects(ITEMEFFECT_LIFEORB_SHELLBELL, 0, FALSE))
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_PICKPOCKET:
if (IsBattlerAlive(gBattlerAttacker)
&& gBattleMons[gBattlerAttacker].item != ITEM_NONE // Attacker must be holding an item
@ -7294,75 +7363,6 @@ static void Cmd_moveend(void)
}
gBattleScripting.moveendState++;
break;
case MOVEEND_EMERGENCY_EXIT: // Special case, because moves hitting multiple opponents stop after switching out
{
// Because sorting the battlers by speed takes lots of cycles,
// we check if EE can be activated and cound how many.
u32 numEmergencyExitBattlers = 0;
u32 emergencyExitBattlers = 0;
for (i = 0; i < gBattlersCount; i++)
{
if (EmergencyExitCanBeTriggered(i))
{
emergencyExitBattlers |= 1u << i;
numEmergencyExitBattlers++;
}
}
if (numEmergencyExitBattlers == 0)
{
gBattleScripting.moveendState++;
break;
}
u8 battlers[4] = {0, 1, 2, 3};
if (numEmergencyExitBattlers > 1)
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u32 battler = battlers[i];
if (!(emergencyExitBattlers & 1u << battler))
continue;
effect = TRUE;
gBattleScripting.battler = battler;
BattleScriptPushCursor();
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER || IsOnPlayerSide(battler))
gBattlescriptCurrInstr = BattleScript_EmergencyExit;
else
gBattlescriptCurrInstr = BattleScript_EmergencyExitWild;
break; // Only the fastest Emergency Exit / Wimp Out activates
}
}
if (effect)
gBattleScripting.moveendState = MOVEEND_OPPORTUNIST;
else
gBattleScripting.moveendState++;
break;
case MOVEEND_HIT_ESCAPE:
if (moveEffect == EFFECT_HIT_ESCAPE
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& IsBattlerTurnDamaged(gBattlerTarget)
&& IsBattlerAlive(gBattlerAttacker)
&& !NoAliveMonsForBattlerSide(gBattlerTarget))
{
effect = TRUE;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_EffectHitEscape;
}
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_REMOVE_TERRAIN:
if (GetMoveEffect(gChosenMove) == EFFECT_STEEL_ROLLER // Steel Roller has to check the chosen move, Otherwise it would fail in certain cases
&& IsBattlerTurnDamaged(gBattlerTarget))
@ -7381,20 +7381,31 @@ static void Cmd_moveend(void)
}
gBattleScripting.moveendState++;
break;
case MOVEEND_SYMBIOSIS:
case MOVEEND_WHITE_HERB:
for (i = 0; i < gBattlersCount; i++)
{
if ((gSpecialStatuses[i].berryReduced
|| (B_SYMBIOSIS_GEMS >= GEN_7 && gSpecialStatuses[i].gemBoost))
&& TryTriggerSymbiosis(i, BATTLE_PARTNER(i)))
if (!IsBattlerAlive(i))
continue;
if (GetBattlerHoldEffect(i, TRUE) == HOLD_EFFECT_WHITE_HERB
&& RestoreWhiteHerbStats(i))
{
BestowItem(BATTLE_PARTNER(i), i);
gLastUsedAbility = gBattleMons[BATTLE_PARTNER(i)].ability;
gBattleScripting.battler = gBattlerAbility = BATTLE_PARTNER(i);
gBattlerAttacker = i;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_SymbiosisActivates;
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
effect = TRUE;
break;
}
}
if (!effect)
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++;
@ -7408,17 +7419,6 @@ 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;

BIN
tools/compresSmol/compresSmol Executable file

Binary file not shown.

Binary file not shown.