Refactor battle intro, allow to speed it up

This commit is contained in:
DizzyEggg 2018-12-23 18:47:00 +01:00
parent c23b1acc5e
commit bd817d70d6
5 changed files with 303 additions and 541 deletions

View File

@ -584,6 +584,7 @@ struct BattleStruct
struct MegaEvolutionData mega; struct MegaEvolutionData mega;
const u8 *trainerSlideMsg; const u8 *trainerSlideMsg;
bool8 trainerSlideLowHpMsgDone; bool8 trainerSlideLowHpMsgDone;
u8 introState;
}; };
#define GET_MOVE_TYPE(move, typeArg) \ #define GET_MOVE_TYPE(move, typeArg) \

View File

@ -43,6 +43,7 @@ void PressurePPLose(u8 bankDef, u8 bankAtk, u16 move);
void PressurePPLoseOnUsingPerishSong(u8 bankAtk); void PressurePPLoseOnUsingPerishSong(u8 bankAtk);
void PressurePPLoseOnUsingImprision(u8 bankAtk); void PressurePPLoseOnUsingImprision(u8 bankAtk);
void MarkAllBattlersForControllerExec(void); // unused void MarkAllBattlersForControllerExec(void); // unused
bool32 IsBattlerMarkedForControllerExec(u8 battlerId);
void MarkBattlerForControllerExec(u8 battlerId); void MarkBattlerForControllerExec(u8 battlerId);
void sub_803F850(u8 arg0); void sub_803F850(u8 arg0);
void CancelMultiTurnMoves(u8 battlerId); void CancelMultiTurnMoves(u8 battlerId);

View File

@ -15,4 +15,6 @@
#define B_EXP_CATCH GEN_6 // Starting from gen6, pokemon get experience from catching. #define B_EXP_CATCH GEN_6 // Starting from gen6, pokemon get experience from catching.
#define B_ABILITY_POP_UP GEN_6 // Starting from gen5, the pokemon abilities are displayed in a pop-up, when they activate in battle. #define B_ABILITY_POP_UP GEN_6 // Starting from gen5, the pokemon abilities are displayed in a pop-up, when they activate in battle.
#define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a pokemon, as opposing to waiting for the animation to end.
#endif // GUARD_CONSTANTS_BATTLE_CONFIG_H #endif // GUARD_CONSTANTS_BATTLE_CONFIG_H

View File

@ -117,18 +117,7 @@ static void SpecialStatusesClear(void);
static void TurnValuesCleanUp(bool8 var0); static void TurnValuesCleanUp(bool8 var0);
static void SpriteCB_BounceEffect(struct Sprite *sprite); static void SpriteCB_BounceEffect(struct Sprite *sprite);
static void BattleStartClearSetData(void); static void BattleStartClearSetData(void);
static void BattleIntroGetMonsData(void); static void DoBattleIntro(void);
static void BattleIntroPrepareBackgroundSlide(void);
static void BattleIntroDrawTrainersOrMonsSprites(void);
static void BattleIntroDrawPartySummaryScreens(void);
static void BattleIntroPrintTrainerWantsToBattle(void);
static void BattleIntroPrintWildMonAttacked(void);
static void BattleIntroPrintOpponentSendsOut(void);
static void BattleIntroPrintPlayerSendsOut(void);
static void BattleIntroOpponent1SendsOutMonAnimation(void);
static void BattleIntroOpponent2SendsOutMonAnimation(void);
static void BattleIntroRecordMonsToDex(void);
static void BattleIntroPlayer1SendsOutMonAnimation(void);
static void TryDoEventsBeforeFirstTurn(void); static void TryDoEventsBeforeFirstTurn(void);
static void HandleTurnActionSelectionState(void); static void HandleTurnActionSelectionState(void);
static void RunTurnActionsFunctions(void); static void RunTurnActionsFunctions(void);
@ -2013,12 +2002,6 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
return gTrainers[trainerNum].partySize; return gTrainers[trainerNum].partySize;
} }
void sub_8038A04(void) // unused
{
if (REG_VCOUNT < 0xA0 && REG_VCOUNT >= 0x6F)
SetGpuReg(REG_OFFSET_BG0CNT, 0x9800);
}
void VBlankCB_Battle(void) void VBlankCB_Battle(void)
{ {
// Change gRngSeed every vblank unless the battle could be recorded. // Change gRngSeed every vblank unless the battle could be recorded.
@ -2661,13 +2644,6 @@ void SpriteCallbackDummy_2(struct Sprite *sprite)
} }
static void sub_80398BC(struct Sprite *sprite) // unused?
{
sprite->data[3] = 6;
sprite->data[4] = 1;
sprite->callback = sub_80398D0;
}
static void sub_80398D0(struct Sprite *sprite) static void sub_80398D0(struct Sprite *sprite)
{ {
sprite->data[4]--; sprite->data[4]--;
@ -2958,7 +2934,8 @@ void BeginBattleIntro(void)
{ {
BattleStartClearSetData(); BattleStartClearSetData();
gBattleCommunication[1] = 0; gBattleCommunication[1] = 0;
gBattleMainFunc = BattleIntroGetMonsData; gBattleStruct->introState = 0;
gBattleMainFunc = DoBattleIntro;
} }
static void BattleMainCB1(void) static void BattleMainCB1(void)
@ -3311,550 +3288,323 @@ void FaintClearSetData(void)
UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]); UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]);
} }
static void BattleIntroGetMonsData(void) static void DoBattleIntro(void)
{ {
switch (gBattleCommunication[MULTIUSE_STATE]) s32 i;
u8 *state = &gBattleStruct->introState;
switch (*state)
{ {
case 0: case 0: // Get Data of all battlers.
gActiveBattler = gBattleCommunication[1]; gActiveBattler = gBattleCommunication[1];
BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, 0); BtlController_EmitGetMonData(0, REQUEST_ALL_BATTLE, 0);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
gBattleCommunication[MULTIUSE_STATE]++; (*state)++;
break; break;
case 1: case 1: // Loop through all battlers.
if (gBattleControllerExecFlags == 0) if (!gBattleControllerExecFlags)
{ {
gBattleCommunication[1]++; if (++gBattleCommunication[1] == gBattlersCount)
if (gBattleCommunication[1] == gBattlersCount) (*state)++;
gBattleMainFunc = BattleIntroPrepareBackgroundSlide;
else else
gBattleCommunication[MULTIUSE_STATE] = 0; *state = 0;
} }
break; break;
} case 2: // Start graphical intro slide.
} if (!gBattleControllerExecFlags)
static void BattleIntroPrepareBackgroundSlide(void)
{
if (gBattleControllerExecFlags == 0)
{
gActiveBattler = GetBattlerAtPosition(0);
BtlController_EmitIntroSlide(0, gBattleTerrain);
MarkBattlerForControllerExec(gActiveBattler);
gBattleMainFunc = BattleIntroDrawTrainersOrMonsSprites;
gBattleCommunication[0] = 0;
gBattleCommunication[1] = 0;
}
}
static void BattleIntroDrawTrainersOrMonsSprites(void)
{
u8 *ptr;
s32 i;
if (gBattleControllerExecFlags)
return;
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI)
&& GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
{ {
ptr = (u8 *)&gBattleMons[gActiveBattler]; gActiveBattler = GetBattlerAtPosition(0);
for (i = 0; i < sizeof(struct BattlePokemon); i++) BtlController_EmitIntroSlide(0, gBattleTerrain);
ptr[i] = 0;
}
else
{
u16* hpOnSwitchout;
ptr = (u8 *)&gBattleMons[gActiveBattler];
for (i = 0; i < sizeof(struct BattlePokemon); i++)
ptr[i] = gBattleBufferB[gActiveBattler][4 + i];
gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1;
gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2;
gBattleMons[gActiveBattler].type3 = TYPE_MYSTERY;
gBattleMons[gActiveBattler].ability = GetAbilityBySpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].altAbility);
hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(gActiveBattler)];
*hpOnSwitchout = gBattleMons[gActiveBattler].hp;
for (i = 0; i < NUM_BATTLE_STATS; i++)
gBattleMons[gActiveBattler].statStages[i] = 6;
gBattleMons[gActiveBattler].status2 = 0;
}
if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_LEFT)
{
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler); MarkBattlerForControllerExec(gActiveBattler);
gBattleCommunication[0] = 0;
gBattleCommunication[1] = 0;
(*state)++;
}
break;
case 3: // Wait for intro slide.
if (!gBattleControllerExecFlags)
(*state)++;
break;
case 4: // Copy battler data gotten in cases 0 and 1. Draw trainer/mon sprite.
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if ((gBattleTypeFlags & BATTLE_TYPE_SAFARI) && GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
{
memset(&gBattleMons[gActiveBattler], 0, sizeof(struct BattlePokemon));
}
else
{
memcpy(&gBattleMons[gActiveBattler], &gBattleBufferB[gActiveBattler][4], sizeof(struct BattlePokemon));
gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1;
gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2;
gBattleMons[gActiveBattler].type3 = TYPE_MYSTERY;
gBattleMons[gActiveBattler].ability = GetAbilityBySpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].altAbility);
gBattleStruct->hpOnSwitchout[GetBattlerSide(gActiveBattler)] = gBattleMons[gActiveBattler].hp;
gBattleMons[gActiveBattler].status2 = 0;
for (i = 0; i < NUM_BATTLE_STATS; i++)
gBattleMons[gActiveBattler].statStages[i] = 6;
}
// Draw sprite.
switch (GetBattlerPosition(gActiveBattler))
{
case B_POSITION_PLAYER_LEFT: // player sprite
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler);
break;
case B_POSITION_OPPONENT_LEFT:
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) // opponent 1 sprite
{
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler);
}
else // wild mon 1
{
BtlController_EmitLoadMonSprite(0);
MarkBattlerForControllerExec(gActiveBattler);
gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
}
break;
case B_POSITION_PLAYER_RIGHT:
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER)) // partner sprite
{
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler);
}
break;
case B_POSITION_OPPONENT_RIGHT:
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS)) // opponent 2 if exists
{
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler);
}
}
else // wild mon 2
{
BtlController_EmitLoadMonSprite(0);
MarkBattlerForControllerExec(gActiveBattler);
gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
}
break;
}
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
BattleArena_InitPoints();
} }
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER) if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{ {
if (GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_LEFT) (*state)++;
}
else // Skip party summary since it is a wild battle.
{
if (B_FAST_INTRO)
*state = 7; // Don't wait for sprite, print message at the same time.
else
*state = 6; // Wait for sprite to load.
}
break;
case 5: // draw party summary in trainer battles
if (!gBattleControllerExecFlags)
{
struct HpAndStatus hpStatus[PARTY_SIZE];
for (i = 0; i < PARTY_SIZE; i++)
{ {
BtlController_EmitDrawTrainerPic(0); if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
MarkBattlerForControllerExec(gActiveBattler); || GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS);
}
} }
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
| BATTLE_TYPE_FRONTIER BtlController_EmitDrawPartyStatusSummary(0, hpStatus, 0x80);
| BATTLE_TYPE_LINK MarkBattlerForControllerExec(gActiveBattler);
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_TRAINER_HILL))) for (i = 0; i < PARTY_SIZE; i++)
{ {
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality); if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
}
}
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
BtlController_EmitDrawPartyStatusSummary(0, hpStatus, 0x80);
MarkBattlerForControllerExec(gActiveBattler);
(*state)++;
}
break;
case 6: // wait for previous action to complete
if (!gBattleControllerExecFlags)
(*state)++;
break;
case 7: // print battle intro message
if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)))
{
PrepareStringBattle(STRINGID_INTROMSG, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT));
(*state)++;
}
break;
case 8: // wait for intro message to be printed
if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)))
{
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
(*state)++;
}
else
{
if (B_FAST_INTRO)
*state = 15; // Wait for text to be printed.
else
*state = 14; // Wait for text and sprite.
} }
} }
break;
case 9: // print opponent sends out
if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_PLAYER_LEFT));
else else
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT));
(*state)++;
break;
case 10: // wait for opponent sends out text
if (!gBattleControllerExecFlags)
(*state)++;
break;
case 11: // first opponent's mon send out animation
if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
else
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
(*state)++;
break;
case 12: // nothing
(*state)++;
case 13: // second opponent's mon send out
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS))
{ {
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
else
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
}
if (B_FAST_INTRO && !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_x2000000 | BATTLE_TYPE_x80000000 | BATTLE_TYPE_LINK)))
*state = 15; // Print at the same time as trainer sends out second mon.
else
(*state)++;
break;
case 14: // wait for opponent 2 send out
if (!gBattleControllerExecFlags)
(*state)++;
break;
case 15: // wait for wild battle message
if (!IsBattlerMarkedForControllerExec(GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)))
(*state)++;
break;
case 16: // print player sends out
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
{
if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
else
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
// A hack that makes fast intro work in trainer battles too.
if (B_FAST_INTRO
&& gBattleTypeFlags & BATTLE_TYPE_TRAINER
&& !(gBattleTypeFlags & (BATTLE_TYPE_RECORDED | BATTLE_TYPE_x2000000 | BATTLE_TYPE_x80000000 | BATTLE_TYPE_LINK))
&& gSprites[gHealthboxSpriteIds[gActiveBattler ^ BIT_SIDE]].callback == SpriteCallbackDummy)
{ {
if (!(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER return;
| BATTLE_TYPE_FRONTIER }
| BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000 PrepareStringBattle(STRINGID_INTROSENDOUT, gActiveBattler);
| BATTLE_TYPE_TRAINER_HILL))) }
(*state)++;
break;
case 17: // wait for player send out message
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK && gBattleControllerExecFlags))
{
if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
else
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
if (!IsBattlerMarkedForControllerExec(gActiveBattler))
(*state)++;
}
break;
case 18: // player 1 send out
if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
else
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
(*state)++;
break;
case 19: // player 2 send out
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_INGAME_PARTNER))
{
if (gBattleTypeFlags & BATTLE_TYPE_x2000000 && !(gBattleTypeFlags & BATTLE_TYPE_x80000000))
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
else
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
}
(*state)++;
break;
case 20: // set dex and battle vars
if (!gBattleControllerExecFlags)
{
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_TRAINER_HILL)))
{ {
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality); HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality);
} }
BtlController_EmitLoadMonSprite(0);
MarkBattlerForControllerExec(gActiveBattler);
gBattleResults.lastOpponentSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gActiveBattler]], MON_DATA_SPECIES, NULL);
} }
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
} }
break;
if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT
|| (GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT && gBattleTypeFlags & BATTLE_TYPE_TRAINER))
{
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler);
}
}
if (gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS && GetBattlerPosition(gActiveBattler) == B_POSITION_OPPONENT_RIGHT)
{
BtlController_EmitDrawTrainerPic(0);
MarkBattlerForControllerExec(gActiveBattler);
}
if (gBattleTypeFlags & BATTLE_TYPE_ARENA)
BattleArena_InitPoints();
}
gBattleMainFunc = BattleIntroDrawPartySummaryScreens;
}
static void BattleIntroDrawPartySummaryScreens(void)
{
s32 i;
struct HpAndStatus hpStatus[PARTY_SIZE];
if (gBattleControllerExecFlags)
return;
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gEnemyParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gEnemyParty[i], MON_DATA_STATUS);
}
}
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
BtlController_EmitDrawPartyStatusSummary(0, hpStatus, 0x80);
MarkBattlerForControllerExec(gActiveBattler);
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
}
}
gActiveBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
BtlController_EmitDrawPartyStatusSummary(0, hpStatus, 0x80);
MarkBattlerForControllerExec(gActiveBattler);
gBattleMainFunc = BattleIntroPrintTrainerWantsToBattle;
}
else
{
// The struct gets set here, but nothing is ever done with it since
// wild battles don't show the party summary.
// Still, there's no point in having dead code.
for (i = 0; i < PARTY_SIZE; i++)
{
if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_NONE
|| GetMonData(&gPlayerParty[i], MON_DATA_SPECIES2) == SPECIES_EGG)
{
hpStatus[i].hp = 0xFFFF;
hpStatus[i].status = 0;
}
else
{
hpStatus[i].hp = GetMonData(&gPlayerParty[i], MON_DATA_HP);
hpStatus[i].status = GetMonData(&gPlayerParty[i], MON_DATA_STATUS);
}
}
gBattleMainFunc = BattleIntroPrintWildMonAttacked;
}
}
static void BattleIntroPrintTrainerWantsToBattle(void)
{
if (gBattleControllerExecFlags == 0)
{
gActiveBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
PrepareStringBattle(STRINGID_INTROMSG, gActiveBattler);
gBattleMainFunc = BattleIntroPrintOpponentSendsOut;
}
}
static void BattleIntroPrintWildMonAttacked(void)
{
if (gBattleControllerExecFlags == 0)
{
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
PrepareStringBattle(STRINGID_INTROMSG, 0);
}
}
static void BattleIntroPrintOpponentSendsOut(void)
{
u32 position;
if (gBattleControllerExecFlags)
return;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
position = B_POSITION_OPPONENT_LEFT;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
position = B_POSITION_OPPONENT_LEFT;
else
position = B_POSITION_PLAYER_LEFT;
}
else
position = B_POSITION_OPPONENT_LEFT;
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(position));
gBattleMainFunc = BattleIntroOpponent1SendsOutMonAnimation;
}
static void BattleIntroOpponent2SendsOutMonAnimation(void)
{
u32 position;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
position = B_POSITION_OPPONENT_RIGHT;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
position = B_POSITION_OPPONENT_RIGHT;
else
position = B_POSITION_PLAYER_RIGHT;
}
else
position = B_POSITION_OPPONENT_RIGHT;
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerPosition(gActiveBattler) == position)
{
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
}
}
gBattleMainFunc = BattleIntroRecordMonsToDex;
}
#ifdef NONMATCHING
static void BattleIntroOpponent1SendsOutMonAnimation(void)
{
u32 position;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
position = B_POSITION_OPPONENT_LEFT;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
position = B_POSITION_OPPONENT_LEFT;
else
position = B_POSITION_PLAYER_LEFT;
}
else
position = B_POSITION_OPPONENT_LEFT;
if (gBattleControllerExecFlags)
return;
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerPosition(gActiveBattler) == position)
{
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI | BATTLE_TYPE_TWO_OPPONENTS))
{
gBattleMainFunc = BattleIntroOpponent2SendsOutMonAnimation;
return;
}
}
}
gBattleMainFunc = BattleIntroRecordMonsToDex;
}
#else
NAKED
static void BattleIntroOpponent1SendsOutMonAnimation(void)
{
asm(".syntax unified\n\
push {r4-r6,lr}\n\
ldr r0, =gBattleTypeFlags\n\
ldr r2, [r0]\n\
movs r0, 0x80\n\
lsls r0, 17\n\
ands r0, r2\n\
cmp r0, 0\n\
beq _0803B298\n\
movs r0, 0x80\n\
lsls r0, 18\n\
ands r0, r2\n\
cmp r0, 0\n\
beq _0803B298\n\
movs r1, 0x80\n\
lsls r1, 24\n\
ands r1, r2\n\
negs r0, r1\n\
orrs r0, r1\n\
lsrs r5, r0, 31\n\
b _0803B29A\n\
.pool\n\
_0803B288:\n\
ldr r1, =gBattleMainFunc\n\
ldr r0, =BattleIntroOpponent2SendsOutMonAnimation\n\
b _0803B2F0\n\
.pool\n\
_0803B298:\n\
movs r5, 0x1\n\
_0803B29A:\n\
ldr r0, =gBattleControllerExecFlags\n\
ldr r2, [r0]\n\
cmp r2, 0\n\
bne _0803B2F2\n\
ldr r0, =gActiveBattler\n\
strb r2, [r0]\n\
ldr r1, =gBattlersCount\n\
adds r4, r0, 0\n\
ldrb r1, [r1]\n\
cmp r2, r1\n\
bcs _0803B2EC\n\
adds r6, r4, 0\n\
_0803B2B2:\n\
ldrb r0, [r4]\n\
bl GetBattlerPosition\n\
lsls r0, 24\n\
lsrs r0, 24\n\
cmp r0, r5\n\
bne _0803B2D8\n\
movs r0, 0\n\
bl BtlController_EmitIntroTrainerBallThrow\n\
ldrb r0, [r4]\n\
bl MarkBattlerForControllerExec\n\
ldr r0, =gBattleTypeFlags\n\
ldr r0, [r0]\n\
ldr r1, =0x00008040\n\
ands r0, r1\n\
cmp r0, 0\n\
bne _0803B288\n\
_0803B2D8:\n\
ldrb r0, [r6]\n\
adds r0, 0x1\n\
strb r0, [r6]\n\
ldr r1, =gBattlersCount\n\
lsls r0, 24\n\
lsrs r0, 24\n\
ldr r4, =gActiveBattler\n\
ldrb r1, [r1]\n\
cmp r0, r1\n\
bcc _0803B2B2\n\
_0803B2EC:\n\
ldr r1, =gBattleMainFunc\n\
ldr r0, =BattleIntroRecordMonsToDex\n\
_0803B2F0:\n\
str r0, [r1]\n\
_0803B2F2:\n\
pop {r4-r6}\n\
pop {r0}\n\
bx r0\n\
.pool\n\
.syntax divided");
}
#endif // NONMATCHING
static void BattleIntroRecordMonsToDex(void)
{
if (gBattleControllerExecFlags == 0)
{
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT
&& !(gBattleTypeFlags & (BATTLE_TYPE_EREADER_TRAINER
| BATTLE_TYPE_FRONTIER
| BATTLE_TYPE_LINK
| BATTLE_TYPE_x2000000
| BATTLE_TYPE_TRAINER_HILL)))
{
HandleSetPokedexFlag(SpeciesToNationalPokedexNum(gBattleMons[gActiveBattler].species), FLAG_SET_SEEN, gBattleMons[gActiveBattler].personality);
}
}
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
}
void sub_803B3AC(void) // unused
{
if (gBattleControllerExecFlags == 0)
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
static void BattleIntroPrintPlayerSendsOut(void)
{
if (gBattleControllerExecFlags == 0)
{
u8 position;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
position = B_POSITION_PLAYER_LEFT;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
position = B_POSITION_PLAYER_LEFT;
else
position = B_POSITION_OPPONENT_LEFT;
}
else
position = B_POSITION_PLAYER_LEFT;
if (!(gBattleTypeFlags & BATTLE_TYPE_SAFARI))
PrepareStringBattle(STRINGID_INTROSENDOUT, GetBattlerAtPosition(position));
gBattleMainFunc = BattleIntroPlayer1SendsOutMonAnimation;
}
}
static void BattleIntroPlayer2SendsOutMonAnimation(void)
{
u32 position;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
position = B_POSITION_PLAYER_RIGHT;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
position = B_POSITION_PLAYER_RIGHT;
else
position = B_POSITION_OPPONENT_RIGHT;
}
else
position = B_POSITION_PLAYER_RIGHT;
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerPosition(gActiveBattler) == position)
{
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
static void BattleIntroPlayer1SendsOutMonAnimation(void)
{
u32 position;
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
position = B_POSITION_PLAYER_LEFT;
else if (gBattleTypeFlags & BATTLE_TYPE_x2000000)
{
if (gBattleTypeFlags & BATTLE_TYPE_x80000000)
position = B_POSITION_PLAYER_LEFT;
else
position = B_POSITION_OPPONENT_LEFT;
}
else
position = B_POSITION_PLAYER_LEFT;
if (gBattleControllerExecFlags)
return;
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerPosition(gActiveBattler) == position)
{
BtlController_EmitIntroTrainerBallThrow(0);
MarkBattlerForControllerExec(gActiveBattler);
if (gBattleTypeFlags & (BATTLE_TYPE_MULTI))
{
gBattleMainFunc = BattleIntroPlayer2SendsOutMonAnimation;
return;
}
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
void sub_803B598(void) // unused
{
if (gBattleControllerExecFlags == 0)
{
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
{
BtlController_EmitSwitchInAnim(0, gBattlerPartyIndexes[gActiveBattler], FALSE);
MarkBattlerForControllerExec(gActiveBattler);
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
} }
} }

View File

@ -440,6 +440,14 @@ void MarkAllBattlersForControllerExec(void) // unused
} }
} }
bool32 IsBattlerMarkedForControllerExec(u8 battlerId)
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
return (gBattleControllerExecFlags & (gBitTable[battlerId] << 0x1C)) != 0;
else
return (gBattleControllerExecFlags & (gBitTable[battlerId])) != 0;
}
void MarkBattlerForControllerExec(u8 battlerId) void MarkBattlerForControllerExec(u8 battlerId)
{ {
if (gBattleTypeFlags & BATTLE_TYPE_LINK) if (gBattleTypeFlags & BATTLE_TYPE_LINK)