Fix Magic Coat targets

This commit is contained in:
DizzyEggg 2022-08-26 15:01:51 +02:00
parent 3facc4875a
commit 6331931ba3
3 changed files with 104 additions and 79 deletions

View file

@ -7421,6 +7421,7 @@ BattleScript_MagicCoatBounce::
printfromtable gMagicCoatBounceStringIds printfromtable gMagicCoatBounceStringIds
waitmessage B_WAIT_TIME_LONG waitmessage B_WAIT_TIME_LONG
orword gHitMarker, HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_ALLOW_NO_PP orword gHitMarker, HITMARKER_ATTACKSTRING_PRINTED | HITMARKER_NO_PPDEDUCT | HITMARKER_ALLOW_NO_PP
bicword gHitMarker, HITMARKER_NO_ATTACKSTRING
setmagiccoattarget BS_ATTACKER setmagiccoattarget BS_ATTACKER
return return

View file

@ -619,6 +619,9 @@ struct BattleStruct
u8 stickyWebUser; u8 stickyWebUser;
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle. u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
u8 attackerBeforeBounce:2;
u8 targetsDone[MAX_BATTLERS_COUNT]; // Each battler as a bit.
}; };
#define F_DYNAMIC_TYPE_1 (1 << 6) #define F_DYNAMIC_TYPE_1 (1 << 6)
@ -669,7 +672,7 @@ struct BattleStruct
#define SET_STATCHANGER(statId, stage, goesDown)(gBattleScripting.statChanger = (statId) + ((stage) << 3) + (goesDown << 7)) #define SET_STATCHANGER(statId, stage, goesDown)(gBattleScripting.statChanger = (statId) + ((stage) << 3) + (goesDown << 7))
#define SET_STATCHANGER2(dst, statId, stage, goesDown)(dst = (statId) + ((stage) << 3) + (goesDown << 7)) #define SET_STATCHANGER2(dst, statId, stage, goesDown)(dst = (statId) + ((stage) << 3) + (goesDown << 7))
// NOTE: The members of this struct have hard-coded offsets // NOTE: The members of this struct have hard-coded offsets
// in include/constants/battle_script_commands.h // in include/constants/battle_script_commands.h
struct BattleScripting struct BattleScripting
{ {

View file

@ -1422,7 +1422,7 @@ static void Cmd_attackcanceler(void)
return; return;
if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBattlerTarget, 0, 0, 0)) if (AbilityBattleEffects(ABILITYEFFECT_MOVES_BLOCK, gBattlerTarget, 0, 0, 0))
return; return;
if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE if (!gBattleMons[gBattlerAttacker].pp[gCurrMovePos] && gCurrentMove != MOVE_STRUGGLE
&& !(gHitMarker & (HITMARKER_ALLOW_NO_PP | HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT)) && !(gHitMarker & (HITMARKER_ALLOW_NO_PP | HITMARKER_NO_ATTACKSTRING | HITMARKER_NO_PPDEDUCT))
&& !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))
{ {
@ -1622,7 +1622,7 @@ static bool32 AccuracyCalcHelper(u16 move)
RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD); RecordAbilityBattle(gBattlerTarget, ABILITY_NO_GUARD);
return TRUE; return TRUE;
} }
if (gBattleStruct->zmove.active && !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE)) if (gBattleStruct->zmove.active && !(gStatuses3[gBattlerTarget] & STATUS3_SEMI_INVULNERABLE))
{ {
JumpIfMoveFailed(7, move); JumpIfMoveFailed(7, move);
@ -1765,7 +1765,7 @@ static void Cmd_accuracycheck(void)
gMoveResultFlags |= MOVE_RESULT_MISSED; gMoveResultFlags |= MOVE_RESULT_MISSED;
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY) if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE &&
(moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY)) (moveTarget == MOVE_TARGET_BOTH || moveTarget == MOVE_TARGET_FOES_AND_ALLY))
gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK; gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_ATK;
@ -2596,14 +2596,14 @@ static void CheckSetUnburden(u8 battlerId)
// battlerStealer steals the item of battlerItem // battlerStealer steals the item of battlerItem
void StealTargetItem(u8 battlerStealer, u8 battlerItem) void StealTargetItem(u8 battlerStealer, u8 battlerItem)
{ {
gLastUsedItem = gBattleMons[battlerItem].item; gLastUsedItem = gBattleMons[battlerItem].item;
gBattleMons[battlerItem].item = 0; gBattleMons[battlerItem].item = 0;
RecordItemEffectBattle(battlerItem, 0); RecordItemEffectBattle(battlerItem, 0);
RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem)); RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem));
gBattleMons[battlerStealer].item = gLastUsedItem; gBattleMons[battlerStealer].item = gLastUsedItem;
CheckSetUnburden(battlerItem); CheckSetUnburden(battlerItem);
gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN; gBattleResources->flags->flags[battlerStealer] &= ~RESOURCE_FLAG_UNBURDEN;
@ -2614,9 +2614,9 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem)
gActiveBattler = battlerItem; gActiveBattler = battlerItem;
BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gBattlerTarget].item), &gBattleMons[battlerItem].item); // remove target item
MarkBattlerForControllerExec(battlerItem); MarkBattlerForControllerExec(battlerItem);
gBattleStruct->choicedMove[battlerItem] = 0; gBattleStruct->choicedMove[battlerItem] = 0;
TrySaveExchangedItem(battlerItem, gLastUsedItem); TrySaveExchangedItem(battlerItem, gLastUsedItem);
} }
@ -2640,7 +2640,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR); bool32 mirrorArmorReflected = (GetBattlerAbility(gBattlerTarget) == ABILITY_MIRROR_ARMOR);
u32 flags = 0; u32 flags = 0;
u16 battlerAbility; u16 battlerAbility;
switch (gBattleScripting.moveEffect) // Set move effects which happen later on switch (gBattleScripting.moveEffect) // Set move effects which happen later on
{ {
case MOVE_EFFECT_KNOCK_OFF: case MOVE_EFFECT_KNOCK_OFF:
@ -2749,7 +2749,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
case STATUS1_BURN: case STATUS1_BURN:
if (gCurrentMove == MOVE_BURNING_JEALOUSY && !gProtectStructs[gEffectBattler].statRaised) if (gCurrentMove == MOVE_BURNING_JEALOUSY && !gProtectStructs[gEffectBattler].statRaised)
break; break;
if ((battlerAbility == ABILITY_WATER_VEIL || battlerAbility == ABILITY_WATER_BUBBLE) if ((battlerAbility == ABILITY_WATER_VEIL || battlerAbility == ABILITY_WATER_BUBBLE)
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
{ {
@ -2944,7 +2944,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
else else
{ {
gBattleMons[gEffectBattler].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); // 2-5 turns gBattleMons[gEffectBattler].status2 |= STATUS2_CONFUSION_TURN(((Random()) % 4) + 2); // 2-5 turns
// If the confusion is activating due to being released from Sky Drop, go to "confused due to fatigue" script. // If the confusion is activating due to being released from Sky Drop, go to "confused due to fatigue" script.
// Otherwise, do normal confusion script. // Otherwise, do normal confusion script.
if(gCurrentMove == MOVE_SKY_DROP) if(gCurrentMove == MOVE_SKY_DROP)
@ -2956,7 +2956,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
else else
{ {
BattleScriptPush(gBattlescriptCurrInstr + 1); BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleScripting.moveEffect]; gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleScripting.moveEffect];
} }
} }
break; break;
@ -3091,7 +3091,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
flags = affectsUser; flags = affectsUser;
if (mirrorArmorReflected && !affectsUser) if (mirrorArmorReflected && !affectsUser)
flags |= STAT_CHANGE_ALLOW_PTR; flags |= STAT_CHANGE_ALLOW_PTR;
if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE, if (ChangeStatBuffs(SET_STAT_BUFF_VALUE(1) | STAT_BUFF_NEGATIVE,
gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1, gBattleScripting.moveEffect - MOVE_EFFECT_ATK_MINUS_1 + 1,
flags | STAT_CHANGE_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1)) flags | STAT_CHANGE_UPDATE_MOVE_EFFECT, gBattlescriptCurrInstr + 1))
@ -3482,14 +3482,14 @@ void SetMoveEffect(bool32 primary, u32 certain)
gBattleMons[gEffectBattler].item = 0; gBattleMons[gEffectBattler].item = 0;
CheckSetUnburden(gEffectBattler); CheckSetUnburden(gEffectBattler);
gActiveBattler = gEffectBattler; gActiveBattler = gEffectBattler;
BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gEffectBattler].item), &gBattleMons[gEffectBattler].item); BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gEffectBattler].item), &gBattleMons[gEffectBattler].item);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
// attacker temporarily gains their item // attacker temporarily gains their item
gBattleStruct->changedItems[gBattlerAttacker] = gBattleMons[gBattlerAttacker].item; gBattleStruct->changedItems[gBattlerAttacker] = gBattleMons[gBattlerAttacker].item;
gBattleMons[gBattlerAttacker].item = gLastUsedItem; gBattleMons[gBattlerAttacker].item = gLastUsedItem;
BattleScriptPush(gBattlescriptCurrInstr + 1); BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_MoveEffectBugBite; gBattlescriptCurrInstr = BattleScript_MoveEffectBugBite;
} }
@ -4989,6 +4989,20 @@ static bool32 TryKnockOffBattleScript(u32 battlerDef)
return FALSE; return FALSE;
} }
static u32 GetNextTarget(u32 moveTarget)
{
u32 i;
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
if (i != gBattlerAttacker
&& IsBattlerAlive(i)
&& !(gBattleStruct->targetsDone[gBattlerAttacker] & gBitTable[i])
&& (GetBattlerSide(i) != GetBattlerSide(gBattlerAttacker) || moveTarget == MOVE_TARGET_FOES_AND_ALLY))
break;
}
return i;
}
static void Cmd_moveend(void) static void Cmd_moveend(void)
{ {
s32 i; s32 i;
@ -5257,13 +5271,13 @@ static void Cmd_moveend(void)
if (gBattleStruct->skyDropTargets[targetId] == i) if (gBattleStruct->skyDropTargets[targetId] == i)
break; break;
} }
// Set gBattlerAttacker to the battler id of the target // Set gBattlerAttacker to the battler id of the target
gBattlerAttacker = targetId; gBattlerAttacker = targetId;
// Jump to "confused due to fatigue" script // Jump to "confused due to fatigue" script
gBattlescriptCurrInstr = BattleScript_ThrashConfuses; gBattlescriptCurrInstr = BattleScript_ThrashConfuses;
// Clear skyDropTargets data // Clear skyDropTargets data
gBattleStruct->skyDropTargets[i] = 0xFF; gBattleStruct->skyDropTargets[i] = 0xFF;
gBattleStruct->skyDropTargets[targetId] = 0xFF; gBattleStruct->skyDropTargets[targetId] = 0xFF;
@ -5380,7 +5394,8 @@ static void Cmd_moveend(void)
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)) && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
gProtectStructs[gBattlerAttacker].targetAffected = TRUE; gProtectStructs[gBattlerAttacker].targetAffected = TRUE;
gBattleStruct->targetsDone[gBattlerAttacker] |= gBitTable[gBattlerTarget];
if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE) if (!(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& gBattleTypeFlags & BATTLE_TYPE_DOUBLE && gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& !gProtectStructs[gBattlerAttacker].chargingTurn && !gProtectStructs[gBattlerAttacker].chargingTurn
@ -5388,28 +5403,12 @@ static void Cmd_moveend(void)
|| moveTarget == MOVE_TARGET_FOES_AND_ALLY) || moveTarget == MOVE_TARGET_FOES_AND_ALLY)
&& !(gHitMarker & HITMARKER_NO_ATTACKSTRING)) && !(gHitMarker & HITMARKER_NO_ATTACKSTRING))
{ {
u8 battlerId; u32 nextTarget = GetNextTarget(moveTarget);
gHitMarker |= HITMARKER_NO_PPDEDUCT;
if (moveTarget == MOVE_TARGET_FOES_AND_ALLY) if (IsBattlerAlive(nextTarget))
{ {
gHitMarker |= HITMARKER_NO_PPDEDUCT; gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = nextTarget; // Fix for moxie spread moves
for (battlerId = gBattlerTarget + 1; battlerId < gBattlersCount; battlerId++)
{
if (battlerId == gBattlerAttacker)
continue;
if (IsBattlerAlive(battlerId))
break;
}
}
else
{
battlerId = GetBattlerAtPosition(BATTLE_PARTNER(GetBattlerPosition(gBattlerTarget)));
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
}
if (IsBattlerAlive(battlerId))
{
gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = battlerId; // Fix for moxie spread moves
gBattleScripting.moveendState = 0; gBattleScripting.moveendState = 0;
MoveValuesCleanUp(); MoveValuesCleanUp();
gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect; gBattleScripting.moveEffect = gBattleScripting.savedMoveEffect;
@ -5417,11 +5416,31 @@ static void Cmd_moveend(void)
gBattlescriptCurrInstr = BattleScript_FlushMessageBox; gBattlescriptCurrInstr = BattleScript_FlushMessageBox;
return; return;
} }
else // Check if the move used was actually a bounced move. If so, we need to go back to the original attacker and make sure, its move hits all 2 or 3 pokemon.
else if (gProtectStructs[gBattlerAttacker].usesBouncedMove)
{ {
gHitMarker |= HITMARKER_NO_ATTACKSTRING; u8 originalBounceTarget = gBattlerAttacker;
gHitMarker &= ~HITMARKER_NO_PPDEDUCT; gBattlerAttacker = gBattleStruct->attackerBeforeBounce;
gBattleStruct->targetsDone[gBattlerAttacker] |= gBitTable[originalBounceTarget];
gBattleStruct->targetsDone[originalBounceTarget] = 0;
nextTarget = GetNextTarget(moveTarget);
if (nextTarget != MAX_BATTLERS_COUNT)
{
// We found another target for the original move user.
gBattleStruct->moveTarget[gBattlerAttacker] = gBattlerTarget = nextTarget;
gBattleScripting.moveendState = 0;
gBattleScripting.animTurn = 0;
gBattleScripting.animTargetsHit = 0;
MoveValuesCleanUp();
BattleScriptPush(gBattleScriptsForMoveEffects[gBattleMoves[gCurrentMove].effect]);
gBattlescriptCurrInstr = BattleScript_FlushMessageBox;
return;
}
} }
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
gHitMarker &= ~HITMARKER_NO_PPDEDUCT;
} }
RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove); RecordLastUsedMoveBy(gBattlerAttacker, gCurrentMove);
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
@ -5482,7 +5501,7 @@ static void Cmd_moveend(void)
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RED_CARD && GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RED_CARD
&& (gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0) && (gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0)
&& CanBattlerSwitch(gBattlerAttacker)) && CanBattlerSwitch(gBattlerAttacker))
{ {
gLastUsedItem = gBattleMons[battler].item; gLastUsedItem = gBattleMons[battler].item;
gActiveBattler = gBattleStruct->savedBattlerTarget = gBattleScripting.battler = battler; // Battler with red card gActiveBattler = gBattleStruct->savedBattlerTarget = gBattleScripting.battler = battler; // Battler with red card
gEffectBattler = gBattlerAttacker; gEffectBattler = gBattlerAttacker;
@ -5554,7 +5573,7 @@ static void Cmd_moveend(void)
// Battle scripting is super brittle so we shall do the item exchange now (if possible) // Battle scripting is super brittle so we shall do the item exchange now (if possible)
if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD) if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STICKY_HOLD)
StealTargetItem(gBattlerTarget, gBattlerAttacker); // Target takes attacker's item StealTargetItem(gBattlerTarget, gBattlerAttacker); // Target takes attacker's item
gEffectBattler = gBattlerAttacker; gEffectBattler = gBattlerAttacker;
BattleScriptPushCursor(); BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_Pickpocket; // Includes sticky hold check to print separate string gBattlescriptCurrInstr = BattleScript_Pickpocket; // Includes sticky hold check to print separate string
@ -5635,6 +5654,7 @@ static void Cmd_moveend(void)
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it CancelMultiTurnMoves(gBattlerAttacker); // Cancel it
#endif #endif
gBattleStruct->targetsDone[gBattlerAttacker] = 0;
gProtectStructs[gBattlerAttacker].usesBouncedMove = FALSE; gProtectStructs[gBattlerAttacker].usesBouncedMove = FALSE;
gProtectStructs[gBattlerAttacker].targetAffected = FALSE; gProtectStructs[gBattlerAttacker].targetAffected = FALSE;
gBattleStruct->ateBoost[gBattlerAttacker] = 0; gBattleStruct->ateBoost[gBattlerAttacker] = 0;
@ -7109,7 +7129,7 @@ static void Cmd_removeitem(void)
// Popped Air Balloon cannot be restored by any means. // Popped Air Balloon cannot be restored by any means.
if (GetBattlerHoldEffect(gActiveBattler, TRUE) != HOLD_EFFECT_AIR_BALLOON) if (GetBattlerHoldEffect(gActiveBattler, TRUE) != HOLD_EFFECT_AIR_BALLOON)
gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gActiveBattler]][GetBattlerSide(gActiveBattler)] = itemId; // Remember if switched out gBattleStruct->usedHeldItems[gBattlerPartyIndexes[gActiveBattler]][GetBattlerSide(gActiveBattler)] = itemId; // Remember if switched out
gBattleMons[gActiveBattler].item = ITEM_NONE; gBattleMons[gActiveBattler].item = ITEM_NONE;
CheckSetUnburden(gActiveBattler); CheckSetUnburden(gActiveBattler);
@ -8037,6 +8057,7 @@ static void Cmd_various(void)
CancelMultiTurnMoves(gActiveBattler); CancelMultiTurnMoves(gActiveBattler);
break; break;
case VARIOUS_SET_MAGIC_COAT_TARGET: case VARIOUS_SET_MAGIC_COAT_TARGET:
gBattleStruct->attackerBeforeBounce = gActiveBattler;
gBattlerAttacker = gBattlerTarget; gBattlerAttacker = gBattlerTarget;
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove)) if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove))
@ -8103,7 +8124,7 @@ static void Cmd_various(void)
break; break;
case VARIOUS_ARENA_JUDGMENT_WINDOW: case VARIOUS_ARENA_JUDGMENT_WINDOW:
i = BattleArena_ShowJudgmentWindow(&gBattleCommunication[0]); i = BattleArena_ShowJudgmentWindow(&gBattleCommunication[0]);
// BattleArena_ShowJudgmentWindow's last state was an intermediate step. // BattleArena_ShowJudgmentWindow's last state was an intermediate step.
// Return without advancing the current instruction so that it will be called again. // Return without advancing the current instruction so that it will be called again.
if (i == ARENA_RESULT_RUNNING) if (i == ARENA_RESULT_RUNNING)
@ -8568,7 +8589,7 @@ static void Cmd_various(void)
} }
return; return;
case VARIOUS_TRY_SOAK: case VARIOUS_TRY_SOAK:
if (gBattleMons[gBattlerTarget].type1 == gBattleMoves[gCurrentMove].type if (gBattleMons[gBattlerTarget].type1 == gBattleMoves[gCurrentMove].type
&& gBattleMons[gBattlerTarget].type2 == gBattleMoves[gCurrentMove].type) && gBattleMons[gBattlerTarget].type2 == gBattleMoves[gCurrentMove].type)
{ {
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
@ -9096,7 +9117,7 @@ static void Cmd_various(void)
case VARIOUS_MAKE_INVISIBLE: case VARIOUS_MAKE_INVISIBLE:
if (gBattleControllerExecFlags) if (gBattleControllerExecFlags)
break; break;
BtlController_EmitSpriteInvisibility(BUFFER_A, TRUE); BtlController_EmitSpriteInvisibility(BUFFER_A, TRUE);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
break; break;
@ -9137,10 +9158,10 @@ static void Cmd_various(void)
BtlController_EmitSetMonData(BUFFER_A, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[gActiveBattler].pp[i]), &gBattleMons[gActiveBattler].pp[i]); BtlController_EmitSetMonData(BUFFER_A, REQUEST_PPMOVE1_BATTLE + i, 0, sizeof(gBattleMons[gActiveBattler].pp[i]), &gBattleMons[gActiveBattler].pp[i]);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
} }
if (gBattleMons[gActiveBattler].pp[i] == 0 && gBattleStruct->skyDropTargets[gActiveBattler] == 0xFF) if (gBattleMons[gActiveBattler].pp[i] == 0 && gBattleStruct->skyDropTargets[gActiveBattler] == 0xFF)
CancelMultiTurnMoves(gActiveBattler); CancelMultiTurnMoves(gActiveBattler);
gBattlescriptCurrInstr += 7; // continue gBattlescriptCurrInstr += 7; // continue
} }
else else
@ -9214,19 +9235,19 @@ static void Cmd_various(void)
return; return;
case VARIOUS_SET_SKY_DROP: case VARIOUS_SET_SKY_DROP:
gStatuses3[gBattlerTarget] |= (STATUS3_SKY_DROPPED | STATUS3_ON_AIR); gStatuses3[gBattlerTarget] |= (STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
/* skyDropTargets holds the information of who is in a particular instance of Sky Drop. /* skyDropTargets holds the information of who is in a particular instance of Sky Drop.
This is needed in the case that multiple Pokemon use Sky Drop in the same turn or if This is needed in the case that multiple Pokemon use Sky Drop in the same turn or if
the target of a Sky Drop faints while in the air.*/ the target of a Sky Drop faints while in the air.*/
gBattleStruct->skyDropTargets[gBattlerAttacker] = gBattlerTarget; gBattleStruct->skyDropTargets[gBattlerAttacker] = gBattlerTarget;
gBattleStruct->skyDropTargets[gBattlerTarget] = gBattlerAttacker; gBattleStruct->skyDropTargets[gBattlerTarget] = gBattlerAttacker;
// End any multiturn effects caused by the target except STATUS2_LOCK_CONFUSE // End any multiturn effects caused by the target except STATUS2_LOCK_CONFUSE
gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_MULTIPLETURNS); gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_MULTIPLETURNS);
gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_UPROAR); gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_UPROAR);
gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_BIDE); gBattleMons[gBattlerTarget].status2 &= ~(STATUS2_BIDE);
gDisableStructs[gBattlerTarget].rolloutTimer = 0; gDisableStructs[gBattlerTarget].rolloutTimer = 0;
gDisableStructs[gBattlerTarget].furyCutterCounter = 0; gDisableStructs[gBattlerTarget].furyCutterCounter = 0;
// End any Follow Me/Rage Powder effects caused by the target // End any Follow Me/Rage Powder effects caused by the target
if (gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer != 0 && gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTarget == gBattlerTarget) if (gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer != 0 && gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTarget == gBattlerTarget)
gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer = 0; gSideTimers[GetBattlerSide(gBattlerTarget)].followmeTimer = 0;
@ -9239,12 +9260,12 @@ static void Cmd_various(void)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else else
{ {
gBattleStruct->skyDropTargets[gBattlerAttacker] = 0xFF; gBattleStruct->skyDropTargets[gBattlerAttacker] = 0xFF;
gBattleStruct->skyDropTargets[gBattlerTarget] = 0xFF; gBattleStruct->skyDropTargets[gBattlerTarget] = 0xFF;
gStatuses3[gBattlerTarget] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR); gStatuses3[gBattlerTarget] &= ~(STATUS3_SKY_DROPPED | STATUS3_ON_AIR);
gBattlescriptCurrInstr += 7; gBattlescriptCurrInstr += 7;
} }
// Confuse target if they were in the middle of Petal Dance/Outrage/Thrash when targeted. // Confuse target if they were in the middle of Petal Dance/Outrage/Thrash when targeted.
if (gBattleMons[gBattlerTarget].status2 & STATUS2_LOCK_CONFUSE) if (gBattleMons[gBattlerTarget].status2 & STATUS2_LOCK_CONFUSE)
gBattleScripting.moveEffect = (MOVE_EFFECT_CONFUSION | MOVE_EFFECT_CERTAIN); gBattleScripting.moveEffect = (MOVE_EFFECT_CONFUSION | MOVE_EFFECT_CERTAIN);
@ -9258,7 +9279,7 @@ static void Cmd_various(void)
// Clear skyDropTargets data // Clear skyDropTargets data
gBattleStruct->skyDropTargets[gBattleStruct->skyDropTargets[gEffectBattler]] = 0xFF; gBattleStruct->skyDropTargets[gBattleStruct->skyDropTargets[gEffectBattler]] = 0xFF;
gBattleStruct->skyDropTargets[gEffectBattler] = 0xFF; gBattleStruct->skyDropTargets[gEffectBattler] = 0xFF;
// 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 the target was in the middle of Outrage/Thrash/etc. when targeted by Sky Drop, confuse them on release and do proper animation
if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE && CanBeConfused(gEffectBattler)) if (gBattleMons[gEffectBattler].status2 & STATUS2_LOCK_CONFUSE && CanBeConfused(gEffectBattler))
{ {
@ -9331,7 +9352,7 @@ static void Cmd_various(void)
count++; count++;
} }
} }
if (count == 0) if (count == 0)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // Rototiller fails gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // Rototiller fails
else else
@ -9368,19 +9389,19 @@ static void Cmd_various(void)
gBattlescriptCurrInstr += 4; gBattlescriptCurrInstr += 4;
return; return;
} }
gBattleScripting.battler = gEffectBattler = gBattlerTarget = gActiveBattler; // Cover all berry effect battlerId cases. e.g. ChangeStatBuffs uses target ID gBattleScripting.battler = gEffectBattler = gBattlerTarget = gActiveBattler; // Cover all berry effect battlerId cases. e.g. ChangeStatBuffs uses target ID
// Do move end berry effects for just a single battler, instead of looping through all battlers // Do move end berry effects for just a single battler, instead of looping through all battlers
if (ItemBattleEffects(ITEMEFFECT_BATTLER_MOVE_END, gActiveBattler, FALSE)) if (ItemBattleEffects(ITEMEFFECT_BATTLER_MOVE_END, gActiveBattler, FALSE))
return; return;
if (gBattlescriptCurrInstr[3]) if (gBattlescriptCurrInstr[3])
{ {
gBattleMons[gActiveBattler].item = gBattleStruct->changedItems[gActiveBattler]; gBattleMons[gActiveBattler].item = gBattleStruct->changedItems[gActiveBattler];
gBattleStruct->changedItems[gActiveBattler] = ITEM_NONE; gBattleStruct->changedItems[gActiveBattler] = ITEM_NONE;
gBattleResources->flags->flags[gActiveBattler] &= ~RESOURCE_FLAG_UNBURDEN; gBattleResources->flags->flags[gActiveBattler] &= ~RESOURCE_FLAG_UNBURDEN;
} }
gBattlescriptCurrInstr += 4; gBattlescriptCurrInstr += 4;
return; return;
case VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL: case VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL:
@ -9552,7 +9573,7 @@ static void Cmd_various(void)
return; return;
case VARIOUS_CAN_TAR_SHOT_WORK: case VARIOUS_CAN_TAR_SHOT_WORK:
// Tar Shot will fail if it's already been used on the target and its speed can't be lowered further // Tar Shot will fail if it's already been used on the target and its speed can't be lowered further
if (!gDisableStructs[gActiveBattler].tarShot if (!gDisableStructs[gActiveBattler].tarShot
&& CompareStat(gActiveBattler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN)) && CompareStat(gActiveBattler, STAT_SPEED, MAX_STAT_STAGE, CMP_LESS_THAN))
gBattlescriptCurrInstr += 7; gBattlescriptCurrInstr += 7;
else else
@ -9650,7 +9671,7 @@ static void Cmd_various(void)
case VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM: case VARIOUS_BATTLER_ITEM_TO_LAST_USED_ITEM:
gBattleMons[gActiveBattler].item = gLastUsedItem; gBattleMons[gActiveBattler].item = gLastUsedItem;
break; break;
case VARIOUS_SET_BEAK_BLAST: case VARIOUS_SET_BEAK_BLAST:
gProtectStructs[gBattlerAttacker].beakBlastCharge = TRUE; gProtectStructs[gBattlerAttacker].beakBlastCharge = TRUE;
break; break;
case VARIOUS_SWAP_SIDE_STATUSES: case VARIOUS_SWAP_SIDE_STATUSES:
@ -10268,7 +10289,7 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
gActiveBattler = gBattlerAttacker; gActiveBattler = gBattlerAttacker;
else else
gActiveBattler = gBattlerTarget; gActiveBattler = gBattlerTarget;
activeBattlerAbility = GetBattlerAbility(gActiveBattler); activeBattlerAbility = GetBattlerAbility(gActiveBattler);
gSpecialStatuses[gActiveBattler].changedStatsBattlerId = gBattlerAttacker; gSpecialStatuses[gActiveBattler].changedStatsBattlerId = gBattlerAttacker;
@ -10432,7 +10453,7 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
gBattleTextBuff2[index++] = STRINGID_STATFELL; gBattleTextBuff2[index++] = STRINGID_STATFELL;
gBattleTextBuff2[index++] = STRINGID_STATFELL >> 8; gBattleTextBuff2[index++] = STRINGID_STATFELL >> 8;
gBattleTextBuff2[index] = B_BUFF_EOS; gBattleTextBuff2[index] = B_BUFF_EOS;
if (gBattleMons[gActiveBattler].statStages[statId] == MIN_STAT_STAGE) if (gBattleMons[gActiveBattler].statStages[statId] == MIN_STAT_STAGE)
{ {
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_DECREASE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_DECREASE;
@ -10620,9 +10641,9 @@ static void Cmd_forcerandomswitch(void)
struct Pokemon *party = NULL; struct Pokemon *party = NULL;
s32 validMons = 0; s32 validMons = 0;
s32 minNeeded; s32 minNeeded;
bool32 redCardForcedSwitch = FALSE; bool32 redCardForcedSwitch = FALSE;
// Red card checks against wild pokemon. If we have reached here, the player has a mon to switch into // Red card checks against wild pokemon. If we have reached here, the player has a mon to switch into
// Red card swaps attacker with target to get the animation correct, so here we check attacker which is really the target. Thanks GF... // Red card swaps attacker with target to get the animation correct, so here we check attacker which is really the target. Thanks GF...
if (gBattleScripting.switchCase == B_SWITCH_RED_CARD if (gBattleScripting.switchCase == B_SWITCH_RED_CARD
@ -10665,7 +10686,7 @@ static void Cmd_forcerandomswitch(void)
&& GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) && GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
|| redCardForcedSwitch || redCardForcedSwitch
) )
{ {
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER) if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
party = gPlayerParty; party = gPlayerParty;
else else
@ -12190,7 +12211,7 @@ static void Cmd_maxattackhalvehp(void)
if (!(gBattleMons[gBattlerAttacker].maxHP / 2)) if (!(gBattleMons[gBattlerAttacker].maxHP / 2))
halfHp = 1; halfHp = 1;
// Belly Drum fails if the user's current HP is less than half its maximum, or if the user's Attack is already at +6 (even if the user has Contrary). // Belly Drum fails if the user's current HP is less than half its maximum, or if the user's Attack is already at +6 (even if the user has Contrary).
if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE if (gBattleMons[gBattlerAttacker].statStages[STAT_ATK] < MAX_STAT_STAGE
&& gBattleMons[gBattlerAttacker].hp > halfHp) && gBattleMons[gBattlerAttacker].hp > halfHp)
@ -12686,7 +12707,7 @@ static void Cmd_tryswapitems(void)
gBattleMons[gBattlerAttacker].item = ITEM_NONE; gBattleMons[gBattlerAttacker].item = ITEM_NONE;
gBattleMons[gBattlerTarget].item = oldItemAtk; gBattleMons[gBattlerTarget].item = oldItemAtk;
RecordItemEffectBattle(gBattlerAttacker, 0); RecordItemEffectBattle(gBattlerAttacker, 0);
RecordItemEffectBattle(gBattlerTarget, ItemId_GetHoldEffect(oldItemAtk)); RecordItemEffectBattle(gBattlerTarget, ItemId_GetHoldEffect(oldItemAtk));
@ -12705,7 +12726,7 @@ static void Cmd_tryswapitems(void)
PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk) PREPARE_ITEM_BUFFER(gBattleTextBuff1, *newItemAtk)
PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk) PREPARE_ITEM_BUFFER(gBattleTextBuff2, oldItemAtk)
if (!(sideAttacker == sideTarget && IsPartnerMonFromSameTrainer(gBattlerAttacker))) if (!(sideAttacker == sideTarget && IsPartnerMonFromSameTrainer(gBattlerAttacker)))
{ {
// if targeting your own side and you aren't in a multi battle, don't save items as stolen // if targeting your own side and you aren't in a multi battle, don't save items as stolen
@ -12782,7 +12803,7 @@ static void Cmd_trywish(void)
#else #else
gBattleMoveDamage = max(1, gBattleMons[gBattlerTarget].maxHP / 2); gBattleMoveDamage = max(1, gBattleMons[gBattlerTarget].maxHP / 2);
#endif #endif
gBattleMoveDamage *= -1; gBattleMoveDamage *= -1;
if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP) if (gBattleMons[gBattlerTarget].hp == gBattleMons[gBattlerTarget].maxHP)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2);
@ -13178,7 +13199,7 @@ u16 GetSecretPowerMoveEffect(void)
} }
} }
else else
{ {
switch (gBattleTerrain) switch (gBattleTerrain)
{ {
case BATTLE_TERRAIN_GRASS: case BATTLE_TERRAIN_GRASS:
@ -13401,7 +13422,7 @@ static void Cmd_settypebasedhalvers(void)
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_ELECTRIC; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_WEAKEN_ELECTRIC;
worked = TRUE; worked = TRUE;
} }
#else #else
if (!(gStatuses4[gBattlerAttacker] & STATUS4_MUD_SPORT)) if (!(gStatuses4[gBattlerAttacker] & STATUS4_MUD_SPORT))
{ {
gStatuses4[gBattlerAttacker] |= STATUS4_MUD_SPORT; gStatuses4[gBattlerAttacker] |= STATUS4_MUD_SPORT;
@ -13576,20 +13597,20 @@ static void Cmd_removelightscreenreflect(void)
{ {
u8 side; u8 side;
bool32 failed; bool32 failed;
#if B_BRICK_BREAK >= GEN_4 #if B_BRICK_BREAK >= GEN_4
// From Gen 4 onwards, Brick Break can remove screens on the user's side if used on an ally // From Gen 4 onwards, Brick Break can remove screens on the user's side if used on an ally
side = GetBattlerSide(gBattlerTarget); side = GetBattlerSide(gBattlerTarget);
#else #else
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
#endif #endif
#if B_BRICK_BREAK >= GEN_5 #if B_BRICK_BREAK >= GEN_5
failed = (gMoveResultFlags & MOVE_RESULT_NO_EFFECT); failed = (gMoveResultFlags & MOVE_RESULT_NO_EFFECT);
#else #else
failed = FALSE; failed = FALSE;
#endif #endif
if (!failed if (!failed
&& (gSideTimers[side].reflectTimer && (gSideTimers[side].reflectTimer
|| gSideTimers[side].lightscreenTimer || gSideTimers[side].lightscreenTimer
@ -13648,7 +13669,7 @@ static void Cmd_handleballthrow(void)
{ {
u32 odds, i; u32 odds, i;
u8 catchRate; u8 catchRate;
gLastThrownBall = gLastUsedItem; gLastThrownBall = gLastUsedItem;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI) if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
catchRate = gBattleStruct->safariCatchFactor * 1275 / 100; catchRate = gBattleStruct->safariCatchFactor * 1275 / 100;