#include "global.h" #include "battle.h" #include "recorded_battle.h" #include "main.h" #include "pokemon.h" #include "random.h" #include "event_data.h" #include "link.h" #include "string_util.h" #include "palette.h" #include "save.h" #include "alloc.h" #include "util.h" #include "task.h" #include "text.h" #include "battle_setup.h" #include "frontier_util.h" #include "constants/trainers.h" #define BATTLER_RECORD_SIZE 664 #define ILLEGAL_BATTLE_TYPES ((BATTLE_TYPE_LINK | BATTLE_TYPE_SAFARI | BATTLE_TYPE_FIRST_BATTLE \ | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_ROAMER | BATTLE_TYPE_EREADER_TRAINER \ | BATTLE_TYPE_KYOGRE_GROUDON | BATTLE_TYPE_LEGENDARY | BATTLE_TYPE_REGI \ | BATTLE_TYPE_RECORDED | BATTLE_TYPE_TRAINER_HILL | BATTLE_TYPE_SECRET_BASE \ | BATTLE_TYPE_GROUDON | BATTLE_TYPE_KYOGRE | BATTLE_TYPE_RAYQUAZA)) struct PlayerInfo { u32 trainerId; u8 name[PLAYER_NAME_LENGTH + 1]; u8 gender; u16 battlerId; u16 language; }; struct MovePp { u16 moves[4]; u8 pp[4]; }; struct RecordedBattleSave { struct Pokemon playerParty[PARTY_SIZE]; struct Pokemon opponentParty[PARTY_SIZE]; u8 playersName[MAX_BATTLERS_COUNT][PLAYER_NAME_LENGTH + 1]; u8 playersGender[MAX_BATTLERS_COUNT]; u32 playersTrainerId[MAX_BATTLERS_COUNT]; u8 playersLanguage[MAX_BATTLERS_COUNT]; u32 rngSeed; u32 battleFlags; u8 playersBattlers[MAX_BATTLERS_COUNT]; u16 opponentA; u16 opponentB; u16 partnerId; u16 field_4FA; u8 lvlMode; u8 frontierFacility; u8 frontierBrainSymbol; u8 battleScene:1; u8 textSpeed:3; u32 AI_scripts; u8 recordMixFriendName[PLAYER_NAME_LENGTH + 1]; u8 recordMixFriendClass; u8 apprenticeId; u16 easyChatSpeech[6]; u8 recordMixFriendLanguage; u8 apprenticeLanguage; u8 battleRecord[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE]; u32 checksum; }; EWRAM_DATA u32 gRecordedBattleRngSeed = 0; EWRAM_DATA u32 gBattlePalaceMoveSelectionRngValue = 0; EWRAM_DATA static u8 sBattleRecords[MAX_BATTLERS_COUNT][BATTLER_RECORD_SIZE] = {0}; EWRAM_DATA static u16 sRecordedBytesNo[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA static u16 sUnknown_0203C79C[4] = {0}; EWRAM_DATA static u16 sUnknown_0203C7A4[4] = {0}; EWRAM_DATA static u8 sUnknown_0203C7AC = 0; EWRAM_DATA static u8 sLvlMode = 0; EWRAM_DATA static u8 sFrontierFacility = 0; EWRAM_DATA static u8 sFrontierBrainSymbol = 0; EWRAM_DATA static MainCallback sCallback2_AfterRecordedBattle = NULL; EWRAM_DATA u8 gUnknown_0203C7B4 = 0; EWRAM_DATA static u8 sUnknown_0203C7B5 = 0; EWRAM_DATA static u8 sBattleScene = 0; EWRAM_DATA static u8 sTextSpeed = 0; EWRAM_DATA static u32 sBattleFlags = 0; EWRAM_DATA static u32 sAI_Scripts = 0; EWRAM_DATA static struct Pokemon sSavedPlayerParty[PARTY_SIZE] = {0}; EWRAM_DATA static struct Pokemon sSavedOpponentParty[PARTY_SIZE] = {0}; EWRAM_DATA static u16 sPlayerMonMoves[2][4] = {0}; EWRAM_DATA static struct PlayerInfo sPlayers[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA static u8 sUnknown_0203CCD0 = 0; EWRAM_DATA static u8 sRecordMixFriendName[PLAYER_NAME_LENGTH + 1] = {0}; EWRAM_DATA static u8 sRecordMixFriendClass = 0; EWRAM_DATA static u8 sApprenticeId = 0; EWRAM_DATA static u16 sEasyChatSpeech[6] = {0}; EWRAM_DATA static u8 sBattleOutcome = 0; IWRAM_DATA static u8 sRecordMixFriendLanguage; IWRAM_DATA static u8 sApprenticeLanguage; // this file's functions static u8 sub_8185278(u8 *arg0, u8 *arg1, u8 *arg2); static bool32 CopyRecordedBattleFromSave(struct RecordedBattleSave *dst); static void RecordedBattle_RestoreSavedParties(void); static void CB2_RecordedBattle(void); void sub_8184DA4(u8 arg0) { s32 i, j; sUnknown_0203C7AC = arg0; sUnknown_0203CCD0 = 0; for (i = 0; i < MAX_BATTLERS_COUNT; i++) { sRecordedBytesNo[i] = 0; sUnknown_0203C79C[i] = 0; sUnknown_0203C7A4[i] = 0; if (arg0 == 1) { for (j = 0; j < BATTLER_RECORD_SIZE; j++) { sBattleRecords[i][j] = 0xFF; } sBattleFlags = gBattleTypeFlags; sAI_Scripts = gBattleResources->ai->aiFlags; } } } void sub_8184E58(void) { s32 i, j; if (sUnknown_0203C7AC == 1) { gRecordedBattleRngSeed = gRngValue; sFrontierFacility = VarGet(VAR_FRONTIER_FACILITY); sFrontierBrainSymbol = GetFronterBrainSymbol(); } else if (sUnknown_0203C7AC == 2) { gRngValue = gRecordedBattleRngSeed; } if (gBattleTypeFlags & BATTLE_TYPE_LINK) { u8 linkPlayersCount; u8 text[30]; gUnknown_0203C7B4 = GetMultiplayerId(); linkPlayersCount = GetLinkPlayerCount(); for (i = 0; i < MAX_BATTLERS_COUNT; i++) { sPlayers[i].trainerId = gLinkPlayers[i].trainerId; sPlayers[i].gender = gLinkPlayers[i].gender; sPlayers[i].battlerId = gLinkPlayers[i].id; sPlayers[i].language = gLinkPlayers[i].language; if (i < linkPlayersCount) { StringCopy(text, gLinkPlayers[i].name); StripExtCtrlCodes(text); StringCopy(sPlayers[i].name, text); } else { for (j = 0; j < PLAYER_NAME_LENGTH + 1; j++) sPlayers[i].name[j] = gLinkPlayers[i].name[j]; } } } else { sPlayers[0].trainerId = (gSaveBlock2Ptr->playerTrainerId[0]) | (gSaveBlock2Ptr->playerTrainerId[1] << 8) | (gSaveBlock2Ptr->playerTrainerId[2] << 16) | (gSaveBlock2Ptr->playerTrainerId[3] << 24); sPlayers[0].gender = gSaveBlock2Ptr->playerGender; sPlayers[0].battlerId = 0; sPlayers[0].language = gGameLanguage; for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) sPlayers[0].name[i] = gSaveBlock2Ptr->playerName[i]; } } void RecordedBattle_SetBattlerAction(u8 battlerId, u8 action) { if (sRecordedBytesNo[battlerId] < BATTLER_RECORD_SIZE && sUnknown_0203C7AC != 2) { sBattleRecords[battlerId][sRecordedBytesNo[battlerId]++] = action; } } void RecordedBattle_ClearBattlerAction(u8 battlerId, u8 bytesToClear) { s32 i; for (i = 0; i < bytesToClear; i++) { sRecordedBytesNo[battlerId]--; sBattleRecords[battlerId][sRecordedBytesNo[battlerId]] = 0xFF; if (sRecordedBytesNo[battlerId] == 0) break; } } u8 RecordedBattle_GetBattlerAction(u8 battlerId) { // Trying to read past array or invalid action byte, battle is over. if (sRecordedBytesNo[battlerId] >= BATTLER_RECORD_SIZE || sBattleRecords[battlerId][sRecordedBytesNo[battlerId]] == 0xFF) { gSpecialVar_Result = gBattleOutcome = B_OUTCOME_PLAYER_TELEPORTED; // hah ResetPaletteFadeControl(); BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 0x10, 0); SetMainCallback2(CB2_QuitRecordedBattle); return 0xFF; } else { return sBattleRecords[battlerId][sRecordedBytesNo[battlerId]++]; } } u8 sub_81850D0(void) { return sUnknown_0203C7AC; } u8 sub_81850DC(u8 *arg0) { u8 i, j; u8 ret = 0; for (i = 0; i < MAX_BATTLERS_COUNT; i++) { if (sRecordedBytesNo[i] != sUnknown_0203C79C[i]) { arg0[ret++] = i; arg0[ret++] = sRecordedBytesNo[i] - sUnknown_0203C79C[i]; for (j = 0; j < sRecordedBytesNo[i] - sUnknown_0203C79C[i]; j++) { arg0[ret++] = sBattleRecords[i][sUnknown_0203C79C[i] + j]; } sUnknown_0203C79C[i] = sRecordedBytesNo[i]; } } return ret; } void sub_81851A8(u8 *arg0) { s32 i; u8 var1 = 2; u8 var2; if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)) return; for (i = 0; i < GetLinkPlayerCount(); i++) { if ((gLinkPlayers[i].version & 0xFF) != VERSION_EMERALD) return; } if (!(gBattleTypeFlags & BATTLE_TYPE_IS_MASTER)) { for (var2 = *arg0; var2 != 0;) { u8 unkVar = sub_8185278(arg0, &var1, &var2); u8 unkVar2 = sub_8185278(arg0, &var1, &var2); for (i = 0; i < unkVar2; i++) { sBattleRecords[unkVar][sUnknown_0203C7A4[unkVar]++] = sub_8185278(arg0, &var1, &var2); } } } } static u8 sub_8185278(u8 *arg0, u8 *arg1, u8 *arg2) { (*arg2)--; return arg0[(*arg1)++]; } bool32 CanCopyRecordedBattleSaveData(void) { struct RecordedBattleSave *dst = AllocZeroed(sizeof(struct RecordedBattleSave)); bool32 ret = CopyRecordedBattleFromSave(dst); Free(dst); return ret; } static bool32 IsRecordedBattleSaveValid(struct RecordedBattleSave *save) { if (save->battleFlags == 0) return FALSE; if (save->battleFlags & ILLEGAL_BATTLE_TYPES) return FALSE; if (CalcByteArraySum((void*)(save), sizeof(*save) - 4) != save->checksum) return FALSE; return TRUE; } static bool32 RecordedBattleToSave(struct RecordedBattleSave *battleSave, struct RecordedBattleSave *saveSection) { memset(saveSection, 0, 0x1000); memcpy(saveSection, battleSave, sizeof(*battleSave)); saveSection->checksum = CalcByteArraySum((void*)(saveSection), sizeof(*saveSection) - 4); if (sub_8153634(31, (void*)(saveSection)) != 1) return FALSE; else return TRUE; } bool32 MoveRecordedBattleToSaveData(void) { s32 i, j; bool32 ret; struct RecordedBattleSave *battleSave, *savSection; u8 var; var = 0; battleSave = AllocZeroed(sizeof(struct RecordedBattleSave)); savSection = AllocZeroed(0x1000); for (i = 0; i < PARTY_SIZE; i++) { battleSave->playerParty[i] = sSavedPlayerParty[i]; battleSave->opponentParty[i] = sSavedOpponentParty[i]; } for (i = 0; i < MAX_BATTLERS_COUNT; i++) { for (j = 0; j < PLAYER_NAME_LENGTH + 1; j++) { battleSave->playersName[i][j] = sPlayers[i].name[j]; } battleSave->playersGender[i] = sPlayers[i].gender; battleSave->playersLanguage[i] = sPlayers[i].language; battleSave->playersBattlers[i] = sPlayers[i].battlerId; battleSave->playersTrainerId[i] = sPlayers[i].trainerId; } battleSave->rngSeed = gRecordedBattleRngSeed; if (sBattleFlags & BATTLE_TYPE_LINK) { battleSave->battleFlags = (sBattleFlags & ~(BATTLE_TYPE_LINK | BATTLE_TYPE_20)) | BATTLE_TYPE_x2000000; if (sBattleFlags & BATTLE_TYPE_IS_MASTER) { battleSave->battleFlags |= BATTLE_TYPE_x80000000; } else if (sBattleFlags & BATTLE_TYPE_MULTI) { switch (sPlayers[0].battlerId) { case 0: case 2: if (!(sPlayers[gUnknown_0203C7B4].battlerId & 1)) battleSave->battleFlags |= BATTLE_TYPE_x80000000; break; case 1: case 3: if ((sPlayers[gUnknown_0203C7B4].battlerId & 1)) battleSave->battleFlags |= BATTLE_TYPE_x80000000; break; } } } else { battleSave->battleFlags = sBattleFlags; } battleSave->opponentA = gTrainerBattleOpponent_A; battleSave->opponentB = gTrainerBattleOpponent_B; battleSave->partnerId = gPartnerTrainerId; battleSave->field_4FA = gUnknown_0203C7B4; battleSave->lvlMode = gSaveBlock2Ptr->frontier.lvlMode; battleSave->frontierFacility = sFrontierFacility; battleSave->frontierBrainSymbol = sFrontierBrainSymbol; battleSave->battleScene = gSaveBlock2Ptr->optionsBattleSceneOff; battleSave->textSpeed = gSaveBlock2Ptr->optionsTextSpeed; battleSave->AI_scripts = sAI_Scripts; if (gTrainerBattleOpponent_A >= TRAINER_RECORD_MIXING_FRIEND && gTrainerBattleOpponent_A < TRAINER_RECORD_MIXING_APPRENTICE) { for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) battleSave->recordMixFriendName[i] = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_FRIEND].name[i]; battleSave->recordMixFriendClass = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_FRIEND].facilityClass; if (sBattleOutcome == B_OUTCOME_WON) { for (i = 0; i < 6; i++) battleSave->easyChatSpeech[i] = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_FRIEND].speechLost[i]; } else { for (i = 0; i < 6; i++) battleSave->easyChatSpeech[i] = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_FRIEND].speechWon[i]; } battleSave->recordMixFriendLanguage = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_FRIEND].language; } else if (gTrainerBattleOpponent_B >= TRAINER_RECORD_MIXING_FRIEND && gTrainerBattleOpponent_B < TRAINER_RECORD_MIXING_APPRENTICE) { for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) battleSave->recordMixFriendName[i] = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_FRIEND].name[i]; battleSave->recordMixFriendClass = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_FRIEND].facilityClass; if (sBattleOutcome == B_OUTCOME_WON) { for (i = 0; i < 6; i++) battleSave->easyChatSpeech[i] = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_FRIEND].speechLost[i]; } else { for (i = 0; i < 6; i++) battleSave->easyChatSpeech[i] = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_FRIEND].speechWon[i]; } battleSave->recordMixFriendLanguage = gSaveBlock2Ptr->frontier.towerRecords[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_FRIEND].language; } else if (gPartnerTrainerId >= TRAINER_RECORD_MIXING_FRIEND && gPartnerTrainerId < TRAINER_RECORD_MIXING_APPRENTICE) { for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) battleSave->recordMixFriendName[i] = gSaveBlock2Ptr->frontier.towerRecords[gPartnerTrainerId - TRAINER_RECORD_MIXING_FRIEND].name[i]; battleSave->recordMixFriendClass = gSaveBlock2Ptr->frontier.towerRecords[gPartnerTrainerId - TRAINER_RECORD_MIXING_FRIEND].facilityClass; battleSave->recordMixFriendLanguage = gSaveBlock2Ptr->frontier.towerRecords[gPartnerTrainerId - TRAINER_RECORD_MIXING_FRIEND].language; } if (gTrainerBattleOpponent_A >= TRAINER_RECORD_MIXING_APPRENTICE) { battleSave->apprenticeId = gSaveBlock2Ptr->apprentices[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_APPRENTICE].id; for (i = 0; i < 6; i++) battleSave->easyChatSpeech[i] = gSaveBlock2Ptr->apprentices[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_APPRENTICE].easyChatWords[i]; battleSave->apprenticeLanguage = gSaveBlock2Ptr->apprentices[gTrainerBattleOpponent_A - TRAINER_RECORD_MIXING_APPRENTICE].language; } else if (gTrainerBattleOpponent_B >= TRAINER_RECORD_MIXING_APPRENTICE) { battleSave->apprenticeId = gSaveBlock2Ptr->apprentices[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_APPRENTICE].id; for (i = 0; i < 6; i++) battleSave->easyChatSpeech[i] = gSaveBlock2Ptr->apprentices[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_APPRENTICE].easyChatWords[i]; battleSave->apprenticeLanguage = gSaveBlock2Ptr->apprentices[gTrainerBattleOpponent_B - TRAINER_RECORD_MIXING_APPRENTICE].language; } else if (gPartnerTrainerId >= TRAINER_RECORD_MIXING_APPRENTICE) { battleSave->apprenticeId = gSaveBlock2Ptr->apprentices[gPartnerTrainerId - TRAINER_RECORD_MIXING_APPRENTICE].id; battleSave->apprenticeLanguage = gSaveBlock2Ptr->apprentices[gPartnerTrainerId - TRAINER_RECORD_MIXING_APPRENTICE].language; } for (i = 0; i < MAX_BATTLERS_COUNT; i++) { for (j = 0; j < BATTLER_RECORD_SIZE; j++) { battleSave->battleRecord[i][j] = sBattleRecords[i][j]; } } while (1) { ret = RecordedBattleToSave(battleSave, savSection); if (ret == TRUE) break; var++; if (var >= 3) break; } free(battleSave); free(savSection); return ret; } static bool32 TryCopyRecordedBattleSaveData(struct RecordedBattleSave *dst, struct SaveSection *saveBuffer) { if (TryCopySpecialSaveSection(SECTOR_ID_RECORDED_BATTLE, (void*)(saveBuffer)) != 1) return FALSE; memcpy(dst, saveBuffer, sizeof(struct RecordedBattleSave)); if (!IsRecordedBattleSaveValid(dst)) return FALSE; return TRUE; } static bool32 CopyRecordedBattleFromSave(struct RecordedBattleSave *dst) { struct SaveSection *savBuffer = AllocZeroed(sizeof(struct SaveSection)); bool32 ret = TryCopyRecordedBattleSaveData(dst, savBuffer); Free(savBuffer); return ret; } static void CB2_RecordedBattleEnd(void) { gSaveBlock2Ptr->frontier.lvlMode = sLvlMode; gBattleOutcome = 0; gBattleTypeFlags = 0; gTrainerBattleOpponent_A = 0; gTrainerBattleOpponent_B = 0; gPartnerTrainerId = 0; RecordedBattle_RestoreSavedParties(); SetMainCallback2(sCallback2_AfterRecordedBattle); } #define tFramesToWait data[0] static void Task_StartAfterCountdown(u8 taskId) { if (--gTasks[taskId].tFramesToWait == 0) { gMain.savedCallback = CB2_RecordedBattleEnd; SetMainCallback2(CB2_InitBattle); DestroyTask(taskId); } } static void SetVariablesForRecordedBattle(struct RecordedBattleSave *src) { bool8 var; s32 i, j; ZeroPlayerPartyMons(); ZeroEnemyPartyMons(); for (i = 0; i < PARTY_SIZE; i++) { gPlayerParty[i] = src->playerParty[i]; gEnemyParty[i] = src->opponentParty[i]; } for (i = 0; i < MAX_BATTLERS_COUNT; i++) { for (var = FALSE, j = 0; j < PLAYER_NAME_LENGTH + 1; j++) { gLinkPlayers[i].name[j] = src->playersName[i][j]; if (src->playersName[i][j] == EOS) var = TRUE; } gLinkPlayers[i].gender = src->playersGender[i]; gLinkPlayers[i].language = src->playersLanguage[i]; gLinkPlayers[i].id = src->playersBattlers[i]; gLinkPlayers[i].trainerId = src->playersTrainerId[i]; if (var) ConvertInternationalString(gLinkPlayers[i].name, gLinkPlayers[i].language); } gRecordedBattleRngSeed = src->rngSeed; gBattleTypeFlags = src->battleFlags | BATTLE_TYPE_RECORDED; gTrainerBattleOpponent_A = src->opponentA; gTrainerBattleOpponent_B = src->opponentB; gPartnerTrainerId = src->partnerId; gUnknown_0203C7B4 = src->field_4FA; sLvlMode = gSaveBlock2Ptr->frontier.lvlMode; sFrontierFacility = src->frontierFacility; sFrontierBrainSymbol = src->frontierBrainSymbol; sBattleScene = src->battleScene; sTextSpeed = src->textSpeed; sAI_Scripts = src->AI_scripts; for (i = 0; i < PLAYER_NAME_LENGTH + 1; i++) { sRecordMixFriendName[i] = src->recordMixFriendName[i]; } sRecordMixFriendClass = src->recordMixFriendClass; sApprenticeId = src->apprenticeId; sRecordMixFriendLanguage = src->recordMixFriendLanguage; sApprenticeLanguage = src->apprenticeLanguage; for (i = 0; i < 6; i++) { sEasyChatSpeech[i] = src->easyChatSpeech[i]; } gSaveBlock2Ptr->frontier.lvlMode = src->lvlMode; for (i = 0; i < MAX_BATTLERS_COUNT; i++) { for (j = 0; j < BATTLER_RECORD_SIZE; j++) { sBattleRecords[i][j] = src->battleRecord[i][j]; } } } void PlayRecordedBattle(void (*CB2_After)(void)) { struct RecordedBattleSave *battleSave = AllocZeroed(sizeof(struct RecordedBattleSave)); if (CopyRecordedBattleFromSave(battleSave) == TRUE) { u8 taskId; RecordedBattle_SaveParties(); SetVariablesForRecordedBattle(battleSave); taskId = CreateTask(Task_StartAfterCountdown, 1); gTasks[taskId].tFramesToWait = 128; sCallback2_AfterRecordedBattle = CB2_After; PlayMapChosenOrBattleBGM(FALSE); SetMainCallback2(CB2_RecordedBattle); } Free(battleSave); } #undef tFramesToWait static void CB2_RecordedBattle(void) { AnimateSprites(); BuildOamBuffer(); RunTasks(); } u8 GetRecordedBattleFrontierFacility(void) { return sFrontierFacility; } u8 GetRecordedBattleFronterBrainSymbol(void) { return sFrontierBrainSymbol; } void RecordedBattle_SaveParties(void) { s32 i; for (i = 0; i < PARTY_SIZE; i++) { sSavedPlayerParty[i] = gPlayerParty[i]; sSavedOpponentParty[i] = gEnemyParty[i]; } } static void RecordedBattle_RestoreSavedParties(void) { s32 i; for (i = 0; i < PARTY_SIZE; i++) { gPlayerParty[i] = sSavedPlayerParty[i]; gEnemyParty[i] = sSavedOpponentParty[i]; } } u8 GetActiveBattlerLinkPlayerGender(void) { s32 i; for (i = 0; i < MAX_LINK_PLAYERS; i++) { if (gLinkPlayers[i].id == gActiveBattler) break; } if (i != MAX_LINK_PLAYERS) return gLinkPlayers[i].gender; return 0; } void sub_8185F84(void) { sUnknown_0203C7B5 = 0; } void sub_8185F90(u16 arg0) { sUnknown_0203C7B5 |= (arg0 & 0x8000) >> 0xF; } u8 sub_8185FAC(void) { return sUnknown_0203C7B5; } u8 GetBattleSceneInRecordedBattle(void) { return sBattleScene; } u8 GetTextSpeedInRecordedBattle(void) { return sTextSpeed; } void RecordedBattle_CopyBattlerMoves(void) { s32 i; if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) return; if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) return; if (sUnknown_0203C7AC == 2) return; for (i = 0; i < MAX_MON_MOVES; i++) { sPlayerMonMoves[gActiveBattler / 2][i] = gBattleMons[gActiveBattler].moves[i]; } } #define ACTION_MOVE_CHANGE 6 void sub_818603C(u8 arg0) { s32 battlerId, j, k; if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000)) return; for (battlerId = 0; battlerId < gBattlersCount; battlerId++) { if (GetBattlerSide(battlerId) != B_SIDE_OPPONENT) // player's side only { if (arg0 == 1) { for (j = 0; j < MAX_MON_MOVES; j++) { if (gBattleMons[battlerId].moves[j] != sPlayerMonMoves[battlerId / 2][j]) break; } if (j != MAX_MON_MOVES) // player's mon's move has been changed { RecordedBattle_SetBattlerAction(battlerId, ACTION_MOVE_CHANGE); for (j = 0; j < MAX_MON_MOVES; j++) { for (k = 0; k < MAX_MON_MOVES; k++) { if (gBattleMons[battlerId].moves[j] == sPlayerMonMoves[battlerId / 2][k]) { RecordedBattle_SetBattlerAction(battlerId, k); break; } } } } } else { if (sBattleRecords[battlerId][sRecordedBytesNo[battlerId]] == ACTION_MOVE_CHANGE) { u8 ppBonuses[4]; u8 array1[4]; u8 array2[4]; struct MovePp movePp; u8 array3[8]; u8 var; RecordedBattle_GetBattlerAction(battlerId); for (j = 0; j < MAX_MON_MOVES; j++) { ppBonuses[j] = ((gBattleMons[battlerId].ppBonuses & ((3 << (j << 1)))) >> (j << 1)); } for (j = 0; j < MAX_MON_MOVES; j++) { array1[j] = RecordedBattle_GetBattlerAction(battlerId); movePp.moves[j] = gBattleMons[battlerId].moves[array1[j]]; movePp.pp[j] = gBattleMons[battlerId].pp[array1[j]]; array3[j] = ppBonuses[array1[j]]; array2[j] = (gDisableStructs[battlerId].mimickedMoves & gBitTable[j]) >> j; } for (j = 0; j < MAX_MON_MOVES; j++) { gBattleMons[battlerId].moves[j] = movePp.moves[j]; gBattleMons[battlerId].pp[j] = movePp.pp[j]; } gBattleMons[battlerId].ppBonuses = 0; gDisableStructs[battlerId].mimickedMoves = 0; for (j = 0; j < MAX_MON_MOVES; j++) { gBattleMons[battlerId].ppBonuses |= (array3[j]) << (j << 1); gDisableStructs[battlerId].mimickedMoves |= (array2[j]) << (j); } if (!(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED)) { for (j = 0; j < MAX_MON_MOVES; j++) { ppBonuses[j] = ((GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP_BONUSES, NULL) & ((3 << (j << 1)))) >> (j << 1)); } for (j = 0; j < MAX_MON_MOVES; j++) { movePp.moves[j] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_MOVE1 + array1[j], NULL); movePp.pp[j] = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP1 + array1[j], NULL); array3[j] = ppBonuses[array1[j]]; } for (j = 0; j < MAX_MON_MOVES; j++) { SetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_MOVE1 + j, &movePp.moves[j]); SetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP1 + j, &movePp.pp[j]); } var = 0; for (j = 0; j < MAX_MON_MOVES; j++) { var |= (array3[j]) << (j << 1); } SetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PP_BONUSES, &var); } gChosenMoveByBattler[battlerId] = gBattleMons[battlerId].moves[*(gBattleStruct->chosenMovePositions + battlerId)]; } } } } } u32 GetAiScriptsInRecordedBattle(void) { return sAI_Scripts; } void sub_8186444(void) { sUnknown_0203CCD0 = 1; } bool8 sub_8186450(void) { return (sUnknown_0203CCD0 == 0); } void sub_8186468(u8 *dst) { s32 i; for (i = 0; i < 8; i++) dst[i] = sRecordMixFriendName[i]; dst[7] = EOS; ConvertInternationalString(dst, sRecordMixFriendLanguage); } u8 GetRecordedBattleRecordMixFriendClass(void) { return sRecordMixFriendClass; } u8 GetRecordedBattleApprenticeId(void) { return sApprenticeId; } u8 GetRecordedBattleRecordMixFriendLanguage(void) { return sRecordMixFriendLanguage; } u8 GetRecordedBattleApprenticeLanguage(void) { return sApprenticeLanguage; } void RecordedBattle_SaveBattleOutcome(void) { sBattleOutcome = gBattleOutcome; } u16 *GetRecordedBattleEasyChatSpeech(void) { return sEasyChatSpeech; }