Skip to content

Commit

Permalink
first turn events switch
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexOn1ine committed Jul 16, 2024
1 parent ba4e0b0 commit e3c18d0
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 119 deletions.
4 changes: 2 additions & 2 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ struct BattleStruct
u8 moneyMultiplierItem:1;
u8 moneyMultiplierMove:1;
u8 savedTurnActionNumber;
u8 switchInAbilitiesCounter;
enum FirstTurnEventStates eventsBeforeFirstTurnState;
u8 faintedActionsState;
u8 faintedActionsBattlerId;
u8 scriptPartyIdx; // for printing the nickname
Expand Down Expand Up @@ -672,7 +672,7 @@ struct BattleStruct
u16 chosenItem[MAX_BATTLERS_COUNT];
u16 choicedMove[MAX_BATTLERS_COUNT];
u16 changedItems[MAX_BATTLERS_COUNT];
u8 switchInItemsCounter;
u8 switchInBattlerCounter;
u8 arenaTurnCounter;
u8 turnSideTracker;
u16 lastTakenMoveFrom[MAX_BATTLERS_COUNT][MAX_BATTLERS_COUNT]; // a 2-D array [target][attacker]
Expand Down
20 changes: 20 additions & 0 deletions include/battle_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ struct MultiPartnerMenuPokemon
#define BOUNCE_MON 0x0
#define BOUNCE_HEALTHBOX 0x1

#if MODERN
#define U8_ENUM : u8
#else
#define U8_ENUM
#endif

enum FirstTurnEventStates U8_ENUM {
FIRST_TURN_EVENTS_START,
FIRST_TURN_EVENTS_OVERWORLD_WEATHER,
FIRST_TURN_EVENTS_TERRAIN,
FIRST_TURN_EVENTS_STARTING_STATUS,
FIRST_TURN_EVENTS_TOTEM_BOOST,
FIRST_TURN_EVENTS_NEUTRALIZING_GAS,
FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES,
FIRST_TURN_EVENTS_OPPORTUNIST_1,
FIRST_TURN_EVENTS_ITEM_EFFECTS,
FIRST_TURN_EVENTS_OPPORTUNIST_2,
FIRST_TURN_EVENTS_END,
};

void CB2_InitBattle(void);
void BattleMainCB2(void);
void CB2_QuitRecordedBattle(void);
Expand Down
254 changes: 139 additions & 115 deletions src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3995,8 +3995,8 @@ static void DoBattleIntro(void)
}
}

gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState = 0;
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers
Ai_InitPartyStruct(); // Save mons party counts, and first 2/4 mons on the battlefield.
Expand Down Expand Up @@ -4031,34 +4031,35 @@ static void TryDoEventsBeforeFirstTurn(void)
if (gBattleControllerExecFlags)
return;

// Set invalid mons as absent(for example when starting a double battle with only one pokemon).
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
switch (gBattleStruct->eventsBeforeFirstTurnState)
{
for (i = 0; i < gBattlersCount; i++)
case FIRST_TURN_EVENTS_START:
// Set invalid mons as absent(for example when starting a double battle with only one pokemon).
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
{
struct Pokemon *party = GetBattlerParty(i);
struct Pokemon *mon = &party[gBattlerPartyIndexes[i]];
if (gBattleMons[i].hp == 0 || gBattleMons[i].species == SPECIES_NONE || GetMonData(mon, MON_DATA_IS_EGG))
gAbsentBattlerFlags |= gBitTable[i];
for (i = 0; i < gBattlersCount; i++)
{
struct Pokemon *party = GetBattlerParty(i);
struct Pokemon *mon = &party[gBattlerPartyIndexes[i]];
if (gBattleMons[i].hp == 0 || gBattleMons[i].species == SPECIES_NONE || GetMonData(mon, MON_DATA_IS_EGG))
gAbsentBattlerFlags |= gBitTable[i];
}
}
}

// Allow for illegal abilities within tests.
#if TESTING
if (gTestRunnerEnabled && gBattleStruct->switchInAbilitiesCounter == 0)
{
for (i = 0; i < gBattlersCount; ++i)
// Allow for illegal abilities within tests.
#if TESTING
if (gTestRunnerEnabled)
{
u32 side = GetBattlerSide(i);
u32 partyIndex = gBattlerPartyIndexes[i];
if (TestRunner_Battle_GetForcedAbility(side, partyIndex))
gBattleMons[i].ability = gBattleStruct->overwrittenAbilities[i] = TestRunner_Battle_GetForcedAbility(side, partyIndex);
for (i = 0; i < gBattlersCount; ++i)
{
u32 side = GetBattlerSide(i);
u32 partyIndex = gBattlerPartyIndexes[i];
if (TestRunner_Battle_GetForcedAbility(side, partyIndex))
gBattleMons[i].ability = gBattleStruct->overwrittenAbilities[i] = TestRunner_Battle_GetForcedAbility(side, partyIndex);
}
}
}
#endif // TESTING
#endif // TESTING

if (gBattleStruct->switchInAbilitiesCounter == 0)
{
for (i = 0; i < gBattlersCount; i++)
gBattlerByTurnOrder[i] = i;
for (i = 0; i < gBattlersCount - 1; i++)
Expand All @@ -4069,112 +4070,135 @@ static void TryDoEventsBeforeFirstTurn(void)
SwapTurnOrder(i, j);
}
}
}
if (!gBattleStruct->overworldWeatherDone
&& AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_WEATHER, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0)
{
gBattleStruct->overworldWeatherDone = TRUE;
return;
}

if (!gBattleStruct->terrainDone && AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_TERRAIN, 0, 0, ABILITYEFFECT_SWITCH_IN_TERRAIN, 0) != 0)
{
gBattleStruct->terrainDone = TRUE;
return;
}

if (!gBattleStruct->startingStatusDone
&& gBattleStruct->startingStatus
&& AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_STATUSES, 0, 0, ABILITYEFFECT_SWITCH_IN_STATUSES, 0) != 0)
{
gBattleStruct->startingStatusDone = TRUE;
return;
}

// Totem boosts
for (i = 0; i < gBattlersCount; i++)
{
if (gQueuedStatBoosts[i].stats != 0 && !gProtectStructs[i].eatMirrorHerb && gProtectStructs[i].activateOpportunist == 0)
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_OVERWORLD_WEATHER:
if (!gBattleStruct->overworldWeatherDone
&& AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_WEATHER, 0, 0, ABILITYEFFECT_SWITCH_IN_WEATHER, 0) != 0)
{
gBattlerAttacker = i;
BattleScriptExecute(BattleScript_TotemVar);
gBattleStruct->overworldWeatherDone = TRUE;
return;
}
}

// Check neutralizing gas
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0)
return;

// Check all switch in abilities happening from the fastest mon to slowest.
while (gBattleStruct->switchInAbilitiesCounter < gBattlersCount)
{
gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->switchInAbilitiesCounter++];

if (TryPrimalReversion(gBattlerAttacker))
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_TERRAIN:
if (!gBattleStruct->terrainDone
&& AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_TERRAIN, 0, 0, ABILITYEFFECT_SWITCH_IN_TERRAIN, 0) != 0)
{
gBattleStruct->terrainDone = TRUE;
return;
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerAttacker, 0, 0, 0) != 0)
}
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_STARTING_STATUS:
if (!gBattleStruct->startingStatusDone
&& gBattleStruct->startingStatus
&& AbilityBattleEffects(ABILITYEFFECT_SWITCH_IN_STATUSES, 0, 0, ABILITYEFFECT_SWITCH_IN_STATUSES, 0) != 0)
{
gBattleStruct->startingStatusDone = TRUE;
return;
}

if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;

// Check all switch in items having effect from the fastest mon to slowest.
while (gBattleStruct->switchInItemsCounter < gBattlersCount)
{
if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInItemsCounter++], FALSE))
}
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_TOTEM_BOOST:
for (i = 0; i < gBattlersCount; i++)
{
if (gQueuedStatBoosts[i].stats != 0 && !gProtectStructs[i].eatMirrorHerb && gProtectStructs[i].activateOpportunist == 0)
{
gBattlerAttacker = i;
BattleScriptExecute(BattleScript_TotemVar);
return;
}
}
memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); // erase all totem boosts for Mirror Herb and Opportunist
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_NEUTRALIZING_GAS:
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0)
return;
}
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_SWITCH_IN_ABILITIES:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++];

if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;
if (TryPrimalReversion(gBattlerAttacker))
return;
if (AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gBattlerAttacker, 0, 0, 0) != 0)
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_OPPORTUNIST_1:
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_ITEM_EFFECTS:
while (gBattleStruct->switchInBattlerCounter < gBattlersCount) // From fastest to slowest
{
if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInBattlerCounter++], FALSE))
return;
}
gBattleStruct->switchInBattlerCounter = 0;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_OPPORTUNIST_2:
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;
gBattleStruct->eventsBeforeFirstTurnState++;
break;
case FIRST_TURN_EVENTS_END:
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
*(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE;
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
}
TurnValuesCleanUp(FALSE);
SpecialStatusesClear();
*(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags;
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
gBattleMainFunc = HandleTurnActionSelectionState;
ResetSentPokesToOpponentValue();

for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
*(gBattleStruct->monToSwitchIntoId + i) = PARTY_SIZE;
gChosenActionByBattler[i] = B_ACTION_NONE;
gChosenMoveByBattler[i] = MOVE_NONE;
}
TurnValuesCleanUp(FALSE);
SpecialStatusesClear();
*(&gBattleStruct->absentBattlerFlags) = gAbsentBattlerFlags;
BattlePutTextOnWindow(gText_EmptyString3, B_WIN_MSG);
gBattleMainFunc = HandleTurnActionSelectionState;
ResetSentPokesToOpponentValue();
for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;

for (i = 0; i < BATTLE_COMMUNICATION_ENTRIES_COUNT; i++)
gBattleCommunication[i] = 0;
for (i = 0; i < gBattlersCount; i++)
{
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
// Record party slots of player's mons that appeared in battle
if (!BattlerHasAi(i))
gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[i]];
}

for (i = 0; i < gBattlersCount; i++)
{
gBattleMons[i].status2 &= ~STATUS2_FLINCHED;
// Record party slots of player's mons that appeared in battle
if (!BattlerHasAi(i))
gBattleStruct->appearedInBattle |= gBitTable[gBattlerPartyIndexes[i]];
}
*(&gBattleStruct->turnEffectsTracker) = 0;
*(&gBattleStruct->turnEffectsBattlerId) = 0;
*(&gBattleStruct->wishPerishSongState) = 0;
*(&gBattleStruct->wishPerishSongBattlerId) = 0;
gBattleScripting.moveendState = 0;
gBattleStruct->faintedActionsState = 0;
gBattleStruct->turnCountersTracker = 0;
gMoveResultFlags = 0;

*(&gBattleStruct->turnEffectsTracker) = 0;
*(&gBattleStruct->turnEffectsBattlerId) = 0;
*(&gBattleStruct->wishPerishSongState) = 0;
*(&gBattleStruct->wishPerishSongBattlerId) = 0;
gBattleScripting.moveendState = 0;
gBattleStruct->faintedActionsState = 0;
gBattleStruct->turnCountersTracker = 0;
gMoveResultFlags = 0;
memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts));
SetShellSideArmCategory();
SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers

memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); // erase all totem boosts just to be safe
SetShellSideArmCategory();
SetAiLogicDataForTurn(AI_DATA); // get assumed abilities, hold effects, etc of all battlers
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
{
StopCryAndClearCrySongs();
BattleScriptExecute(BattleScript_ArenaTurnBeginning);
}

if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
{
StopCryAndClearCrySongs();
BattleScriptExecute(BattleScript_ArenaTurnBeginning);
if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_BEFORE_FIRST_TURN)))
BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2);
gBattleStruct->eventsBeforeFirstTurnState = 0;
break;
}

if ((i = ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), TRAINER_SLIDE_BEFORE_FIRST_TURN)))
BattleScriptExecute(i == 1 ? BattleScript_TrainerASlideMsgEnd2 : BattleScript_TrainerBSlideMsgEnd2);
}

static void HandleEndTurn_ContinueBattle(void)
Expand Down
6 changes: 5 additions & 1 deletion src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -17023,7 +17023,11 @@ void BS_CopyFoesStatIncrease(void)

if (gQueuedStatBoosts[battler].stats == 0)
{
gQueuedStatBoosts[battler].stats = 0xFF;
for (stat = 0; stat < (NUM_BATTLE_STATS - 1); stat++)
{
if (gQueuedStatBoosts[battler].statChanges[stat] != 0)
gQueuedStatBoosts[battler].stats |= (1 << stat);
}
gBattlescriptCurrInstr = cmd->jumpInstr;
return;
}
Expand Down
Loading

0 comments on commit e3c18d0

Please sign in to comment.