summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 000000000..72cb976a1
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,454 @@
+#include "global.h"
+#include "main.h"
+#include "m4a.h"
+#include "random.h"
+#include "dma3.h"
+#include "gba/flash_internal.h"
+#include "battle.h"
+
+extern u16 GetGpuReg(u8);
+extern void SetGpuReg(u8, u16);
+extern void RFUVSync(void);
+extern void LinkVSync(void);
+extern void sub_80FCF34(void);
+extern void LinkVSync(void);
+extern void InitGpuRegManager(void);
+extern void InitRFU(void);
+extern void CheckForFlashMemory(void);
+extern void InitMapMusic(void);
+extern void ResetBgs(void);
+extern void SetDefaultFontsPointer(void);
+extern void InitHeap(void *heapStart, u32 heapSize); // malloc.h
+extern void rfu_REQ_stopMode(void);
+extern void rfu_waitREQComplete(void);
+extern bool32 sub_80582E0(void);
+extern bool32 sub_8058274(void);
+extern void ClearSpriteCopyRequests(void);
+extern void PlayTimeCounter_Update(void);
+extern void MapMusicMain(void);
+extern void EnableInterrupts(u16);
+extern void sub_800DD28(void);
+extern u16 SetFlashTimerIntr(u8 timerNum, void (**intrFunc)(void));
+extern void remove_some_task(void);
+extern void sub_80F50F4(void);
+extern bool32 sub_80F5118(void);
+extern bool8 sub_813B870(void);
+
+extern struct SoundInfo gSoundInfo;
+extern u32 gFlashMemoryPresent;
+extern u32 IntrMain[];
+extern u8 gHeap[];
+extern struct SaveBlock1 gSaveBlock1;
+extern struct SaveBlock2 gSaveBlock2;
+extern struct PokemonStorage gPokemonStorage;
+extern u32 gBattleTypeFlags;
+extern u8 gUnknown_03002748;
+extern u32 *gUnknown_0203CF5C;
+
+void Timer3Intr(void);
+bool8 HandleLinkConnection(void);
+void c2_copyright_1(void);
+
+static void VBlankIntr(void);
+static void HBlankIntr(void);
+static void VCountIntr(void);
+static void SerialIntr(void);
+static void IntrDummy(void);
+
+const u8 gGameVersion = VERSION_FIRE_RED;
+
+const u8 gGameLanguage = GAME_LANGUAGE;
+
+const char BuildDateTime[] = "2004 04 26 11:20";
+
+const IntrFunc gIntrTableTemplate[] =
+{
+ VCountIntr, // V-count interrupt
+ SerialIntr, // Serial interrupt
+ Timer3Intr, // Timer 3 interrupt
+ HBlankIntr, // H-blank interrupt
+ VBlankIntr, // V-blank interrupt
+ IntrDummy, // Timer 0 interrupt
+ IntrDummy, // Timer 1 interrupt
+ IntrDummy, // Timer 2 interrupt
+ IntrDummy, // DMA 0 interrupt
+ IntrDummy, // DMA 1 interrupt
+ IntrDummy, // DMA 2 interrupt
+ IntrDummy, // DMA 3 interrupt
+ IntrDummy, // Key interrupt
+ IntrDummy, // Game Pak interrupt
+};
+
+#define INTR_COUNT ((int)(sizeof(gIntrTableTemplate)/sizeof(IntrFunc)))
+
+extern u16 gKeyRepeatStartDelay;
+extern u8 gLinkTransferringData;
+extern struct Main gMain;
+extern u16 gKeyRepeatContinueDelay;
+extern u8 gSoftResetDisabled;
+extern IntrFunc gIntrTable[INTR_COUNT];
+extern bool8 gLinkVSyncDisabled;
+extern u32 IntrMain_Buffer[0x200];
+extern u8 gPcmDmaCounter;
+extern u8 gUnknown_3003578;
+extern u8 gUnknown_3003D80;
+extern u8 gUnknown_3003D84;
+
+static IntrFunc * const sTimerIntrFunc = gIntrTable + 0x7;
+
+extern u16 gTrainerId;
+extern bool8 gUnknown_3005ECC;
+extern bool8 gUnknown_3003F3C;
+extern bool8 gUnknown_3005E88;
+
+EWRAM_DATA void (**gFlashTimerIntrFunc)(void) = NULL;
+
+static void UpdateLinkAndCallCallbacks(void);
+static void InitMainCallbacks(void);
+static void CallCallbacks(void);
+static void ReadKeys(void);
+void InitIntrHandlers(void);
+static void WaitForVBlank(void);
+void EnableVCountIntrAtLine150(void);
+
+#define B_START_SELECT (B_BUTTON | START_BUTTON | SELECT_BUTTON)
+
+void AgbMain()
+{
+ RegisterRamReset(RESET_ALL);
+ *(vu16 *)BG_PLTT = 0x7FFF;
+ InitGpuRegManager();
+ REG_WAITCNT = WAITCNT_PREFETCH_ENABLE | WAITCNT_WS0_S_1 | WAITCNT_WS0_N_3;
+ InitKeys();
+ InitIntrHandlers();
+ m4aSoundInit();
+ EnableVCountIntrAtLine150();
+ InitRFU();
+ CheckForFlashMemory();
+ InitMainCallbacks();
+ InitMapMusic();
+ ClearDma3Requests();
+ ResetBgs();
+ InitHeap(gHeap, 0x1C000);
+ SetDefaultFontsPointer();
+
+ gSoftResetDisabled = FALSE;
+ gUnknown_3005ECC = FALSE;
+
+ sub_80F50F4();
+
+ AGBPrintInit();
+
+#if REVISION == 1
+ if (gFlashMemoryPresent != TRUE)
+ SetMainCallback2(NULL);
+#endif
+
+ gLinkTransferringData = FALSE;
+
+ for (;;)
+ {
+ ReadKeys();
+
+ if (gSoftResetDisabled == FALSE
+ && (gMain.heldKeysRaw & A_BUTTON)
+ && (gMain.heldKeysRaw & B_START_SELECT) == B_START_SELECT)
+ {
+ rfu_REQ_stopMode();
+ rfu_waitREQComplete();
+ DoSoftReset();
+ }
+
+ if (sub_80582E0() == 1)
+ {
+ gLinkTransferringData = TRUE;
+ UpdateLinkAndCallCallbacks();
+ gLinkTransferringData = FALSE;
+ }
+ else
+ {
+ gLinkTransferringData = FALSE;
+ UpdateLinkAndCallCallbacks();
+
+ if (sub_8058274() == 1)
+ {
+ gMain.newKeys = 0;
+ ClearSpriteCopyRequests();
+ gLinkTransferringData = TRUE;
+ UpdateLinkAndCallCallbacks();
+ gLinkTransferringData = FALSE;
+ }
+ }
+
+ PlayTimeCounter_Update();
+ MapMusicMain();
+ WaitForVBlank();
+ }
+}
+
+static void UpdateLinkAndCallCallbacks(void)
+{
+ if (!HandleLinkConnection())
+ CallCallbacks();
+}
+
+static void InitMainCallbacks(void)
+{
+ gMain.vblankCounter1 = 0;
+ gMain.vblankCounter2 = 0;
+ gMain.callback1 = NULL;
+ SetMainCallback2(c2_copyright_1);
+ gSaveBlock2Ptr = &gSaveBlock2;
+ gSaveBlock1Ptr = &gSaveBlock1;
+ gSaveBlock2.encryptionKey = 0;
+ gUnknown_3005E88 = FALSE;
+}
+
+static void CallCallbacks(void)
+{
+ if (!sub_80F5118() && !sub_813B870())
+ {
+ if (gMain.callback1)
+ gMain.callback1();
+
+ if (gMain.callback2)
+ gMain.callback2();
+ }
+}
+
+void SetMainCallback2(MainCallback callback)
+{
+ gMain.callback2 = callback;
+ gMain.state = 0;
+}
+
+void StartTimer1(void)
+{
+ REG_TM1CNT_H = 0x80;
+}
+
+void SeedRngAndSetTrainerId(void)
+{
+ u16 val = REG_TM1CNT_L;
+ SeedRng(val);
+ REG_TM1CNT_H = 0;
+ gTrainerId = val;
+}
+
+u16 GetGeneratedTrainerIdLower(void)
+{
+ return gTrainerId;
+}
+
+void EnableVCountIntrAtLine150(void)
+{
+ u16 gpuReg = (GetGpuReg(REG_OFFSET_DISPSTAT) & 0xFF) | (150 << 8);
+ SetGpuReg(REG_OFFSET_DISPSTAT, gpuReg | DISPSTAT_VCOUNT_INTR);
+ EnableInterrupts(INTR_FLAG_VCOUNT);
+}
+
+void InitKeys(void)
+{
+ gKeyRepeatContinueDelay = 5;
+ gKeyRepeatStartDelay = 40;
+
+ gMain.heldKeys = 0;
+ gMain.newKeys = 0;
+ gMain.newAndRepeatedKeys = 0;
+ gMain.heldKeysRaw = 0;
+ gMain.newKeysRaw = 0;
+}
+
+static void ReadKeys(void)
+{
+ u16 keyInput = REG_KEYINPUT ^ KEYS_MASK;
+ gMain.newKeysRaw = keyInput & ~gMain.heldKeysRaw;
+ gMain.newKeys = gMain.newKeysRaw;
+ gMain.newAndRepeatedKeys = gMain.newKeysRaw;
+
+ // BUG: Key repeat won't work when pressing L using L=A button mode
+ // because it compares the raw key input with the remapped held keys.
+ // Note that newAndRepeatedKeys is never remapped either.
+
+ if (keyInput != 0 && gMain.heldKeys == keyInput)
+ {
+ gMain.keyRepeatCounter--;
+
+ if (gMain.keyRepeatCounter == 0)
+ {
+ gMain.newAndRepeatedKeys = keyInput;
+ gMain.keyRepeatCounter = gKeyRepeatContinueDelay;
+ }
+ }
+ else
+ {
+ // If there is no input or the input has changed, reset the counter.
+ gMain.keyRepeatCounter = gKeyRepeatStartDelay;
+ }
+
+ gMain.heldKeysRaw = keyInput;
+ gMain.heldKeys = gMain.heldKeysRaw;
+
+ // Remap L to A if the L=A option is enabled.
+ if (gSaveBlock2Ptr->optionsButtonMode == 2)
+ {
+ if (gMain.newKeys & L_BUTTON)
+ gMain.newKeys |= A_BUTTON;
+
+ if (gMain.heldKeys & L_BUTTON)
+ gMain.heldKeys |= A_BUTTON;
+ }
+
+ if (gMain.newKeys & gMain.watchedKeysMask)
+ gMain.watchedKeysPressed = TRUE;
+}
+
+void InitIntrHandlers(void)
+{
+ int i;
+
+ for (i = 0; i < INTR_COUNT; i++)
+ gIntrTable[i] = gIntrTableTemplate[i];
+
+ DmaCopy32(3, IntrMain, IntrMain_Buffer, sizeof(IntrMain_Buffer));
+
+ INTR_VECTOR = IntrMain_Buffer;
+
+ SetVBlankCallback(NULL);
+ SetHBlankCallback(NULL);
+ SetSerialCallback(NULL);
+
+ REG_IME = 1;
+
+ EnableInterrupts(0x1);
+}
+
+void SetVBlankCallback(IntrCallback callback)
+{
+ gMain.vblankCallback = callback;
+}
+
+void SetHBlankCallback(IntrCallback callback)
+{
+ gMain.hblankCallback = callback;
+}
+
+void SetVCountCallback(IntrCallback callback)
+{
+ gMain.vcountCallback = callback;
+}
+
+void SetSerialCallback(IntrCallback callback)
+{
+ gMain.serialCallback = callback;
+}
+
+extern void CopyBufferedValuesToGpuRegs(void);
+extern void ProcessDma3Requests(void);
+
+static void VBlankIntr(void)
+{
+ if (gUnknown_3003F3C)
+ RFUVSync();
+ else if (!gLinkVSyncDisabled)
+ LinkVSync();
+
+ if (gMain.vblankCounter1)
+ (*gMain.vblankCounter1)++;
+
+ if (gMain.vblankCallback)
+ gMain.vblankCallback();
+
+ gMain.vblankCounter2++;
+
+ CopyBufferedValuesToGpuRegs();
+ ProcessDma3Requests();
+
+ gPcmDmaCounter = gSoundInfo.pcmDmaCounter;
+
+ gUnknown_3003D84 = REG_VCOUNT;
+ m4aSoundMain();
+ gUnknown_3003578 = REG_VCOUNT;
+
+ sub_800DD28();
+ Random();
+ sub_80FCF34();
+
+ INTR_CHECK |= INTR_FLAG_VBLANK;
+ gMain.intrCheck |= INTR_FLAG_VBLANK;
+}
+
+void InitFlashTimer(void)
+{
+ IntrFunc **func = (IntrFunc **)&sTimerIntrFunc;
+ SetFlashTimerIntr(2, *func);
+}
+
+static void HBlankIntr(void)
+{
+ if (gMain.hblankCallback)
+ gMain.hblankCallback();
+
+ INTR_CHECK |= INTR_FLAG_HBLANK;
+ gMain.intrCheck |= INTR_FLAG_HBLANK;
+}
+
+static void VCountIntr(void)
+{
+ gUnknown_3003D80 = REG_VCOUNT;
+ m4aSoundVSync();
+ INTR_CHECK |= INTR_FLAG_VCOUNT;
+ gMain.intrCheck |= INTR_FLAG_VCOUNT;
+}
+
+static void SerialIntr(void)
+{
+ if (gMain.serialCallback)
+ gMain.serialCallback();
+
+ INTR_CHECK |= INTR_FLAG_SERIAL;
+ gMain.intrCheck |= INTR_FLAG_SERIAL;
+}
+
+void RestoreSerialTimer3IntrHandlers(void)
+{
+ gIntrTable[1] = SerialIntr;
+ gIntrTable[2] = Timer3Intr;
+}
+
+static void IntrDummy(void)
+{}
+
+static void WaitForVBlank(void)
+{
+ gMain.intrCheck &= ~INTR_FLAG_VBLANK;
+
+ while (!(gMain.intrCheck & INTR_FLAG_VBLANK))
+ ;
+}
+
+void SetVBlankCounter1Ptr(u32 *ptr)
+{
+ gMain.vblankCounter1 = ptr;
+}
+
+void DisableVBlankCounter1(void)
+{
+ gMain.vblankCounter1 = NULL;
+}
+
+void DoSoftReset(void)
+{
+ REG_IME = 0;
+ m4aSoundVSyncOff();
+ remove_some_task();
+ DmaStop(1);
+ DmaStop(2);
+ DmaStop(3);
+ SoftReset(RESET_ALL & ~RESET_SIO_REGS);
+}
+
+void ClearPokemonCrySongs(void)
+{
+ CpuFill16(0, gPokemonCrySongs, MAX_POKEMON_CRIES * sizeof(struct PokemonCrySong));
+}