summaryrefslogtreecommitdiff
path: root/src/interrupts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interrupts.c')
-rw-r--r--src/interrupts.c463
1 files changed, 463 insertions, 0 deletions
diff --git a/src/interrupts.c b/src/interrupts.c
new file mode 100644
index 00000000..da810ec6
--- /dev/null
+++ b/src/interrupts.c
@@ -0,0 +1,463 @@
+#include "global.h"
+#include "audio.h"
+#include "main.h"
+#include "player.h"
+#include "structures.h"
+#include "save.h"
+#include "textbox.h"
+#include "functions.h"
+#include "object.h"
+#include "manager.h"
+#include "utils.h"
+#include "npc.h"
+#include "effects.h"
+#include "screen.h"
+
+extern u8 gUnk_03003DE0;
+extern u8 gUnk_03000C30;
+
+extern u16* gUnk_02025EB0;
+extern u16* gUnk_0200B650;
+extern u8 gUpdateVisibleTiles;
+extern u8 gUnk_03003DF0[];
+extern u8 gUnk_03003BE0;
+extern Entity* gUnk_03004040[3];
+extern u8 gUnk_020342F8;
+
+extern void sub_080ADD70();
+extern void sub_0801C25C();
+extern void UpdateDisplayControls();
+extern void LoadResources();
+extern void FadeMain();
+extern u32 CheckDontUpdate();
+extern void HandlePlayerLife();
+extern void DoPlayerAction();
+extern void sub_080171F0();
+extern void sub_08078FB0();
+extern void DrawEntity();
+extern void sub_0807A050();
+extern u32 sub_08079B24();
+extern void sub_08079708();
+extern void CreateSparkle();
+extern void sub_080028E0(Entity*);
+extern void sub_08078180(void);
+extern void sub_0807B0C8(void);
+extern void sub_0807A8D8(Entity*);
+extern void sub_08077FEC(u32);
+extern void ItemInit(Entity*);
+extern void InitObject(Entity*);
+extern u32 ReadBit(void*, u32);
+extern void InitNPC(Entity*);
+extern void m4aSoundMain();
+extern void m4aSoundVSync();
+
+typedef struct {
+ u8 unk0;
+ u8 unk1;
+ u8 unk2;
+ u8 unk3;
+ u8 unk4;
+ u8 unk5;
+ u16 unk6;
+} ItemFrame;
+extern ItemFrame gUnk_08126DA8[];
+extern ItemFrame* gUnk_08126ED8[3];
+
+typedef struct {
+ u16 unk0;
+ u16 unk1;
+ u16 x;
+ u16 y;
+} NPCStruct;
+extern NPCStruct gUnk_02031EC0[100];
+
+// todo: merge with screen.h
+typedef struct {
+ u16 dest;
+ u16 _2;
+ u16 _4;
+ u16 _6;
+ u8* src;
+} DmaSettings;
+
+extern u16 gDmaPresets[];
+
+struct {
+ u8 update;
+ u8 _0[0x1c];
+ struct OamData oam[0x80];
+} extern gUnk_03000000;
+
+struct {
+ u8 ready;
+ u16* src;
+ u16* dest;
+ u32 size;
+} extern gUnk_02022730;
+
+void sub_08016CA8(DmaSettings* s);
+void sub_08016BF8(void);
+void DispCtrlSet(void);
+
+extern u16 gUnk_080B2CD8[];
+
+extern u32 gUnk_03000FBC;
+
+void gIntrMain(void);
+
+typedef void (*fp)(void);
+
+void DummyIntr(void) {
+ /* .. */
+}
+
+void EnableVBlankIntr(void) {
+ INTR_VECTOR = gIntrMain;
+ REG_DISPSTAT = 0x5028;
+ REG_IE = 0x2005;
+ REG_IME = 1;
+}
+
+void VBlankIntr(void) {
+ DmaStop(0);
+ m4aSoundVSync();
+ if (gMain.interruptFlag == 0) {
+ DispCtrlSet();
+ DmaCopy32(0, &gUnk_03000FBC, &gUnk_02022730, 16);
+ gMain.interruptFlag = 1;
+ }
+ sub_08016BF8();
+ INTR_CHECK |= 1;
+}
+
+void HBlankIntr(void) {
+ REG_DISPSTAT = 0x5028;
+ m4aSoundMain();
+}
+
+void sub_08016BF8(void) {
+ if (gUnk_02022730.ready) {
+ const u16* src = gUnk_02022730.src;
+ u16* dest = gUnk_02022730.dest;
+ s32 size, i = size = gUnk_02022730.size;
+ DmaSet(0, src, dest, size);
+
+ i = size & 0x3fff;
+ if (i == 0) {
+ i = 0x4000;
+ }
+ do {
+ *dest++ = *src++;
+ } while (--i > 0);
+ }
+}
+
+void UpdateDisplayControls(void) {
+ if (gUnk_03000000.update && ((gScreen.lcd.displayControl & 0x1000) != 0)) {
+ gUnk_03000000.update = 0;
+ DmaCopy32(3, &gUnk_03000000.oam, 0x07000000, 0x400);
+ }
+ sub_08016CA8((DmaSettings*)&gScreen.bg.bg0Control);
+ sub_08016CA8((DmaSettings*)&gScreen.bg.bg1Control);
+ sub_08016CA8((DmaSettings*)&gScreen.affine.bg2Control);
+ sub_08016CA8((DmaSettings*)&gScreen.affine.bg3Control);
+}
+
+void sub_08016CA8(DmaSettings* s) {
+ if (s->_6 && s->src != 0) {
+ u32 dest;
+ s->_6 = 0;
+ dest = s->dest;
+ DmaCopy32(3, s->src, ((dest << 3) & 0xF800) + 0x06000000, gUnk_080B2CD8[dest >> 14]);
+ }
+}
+
+ASM_FUNC("asm/dispCtrlSet.s", void DispCtrlSet(void));
+
+// Load any resources that were requested with LoadResourceAsync
+void LoadResources(void) {
+ if (gUnk_03003DE0 != 0) {
+ u8* buf = &gUnk_03000C30;
+ s32 i = gUnk_03003DE0;
+ gUnk_03003DE0 = 0;
+ do {
+ switch (*buf) {
+ case 0:
+ DmaCopy32(3, *(u32*)(buf + 4), *(u32*)(buf + 8), *(u16*)(buf + 2));
+ break;
+ case 1:
+ LZ77UnCompVram(*(void**)(buf + 4), *(u8**)(buf + 8));
+ break;
+ case 2:
+ DmaFill32(3, *(u32*)(buf + 4), *(u32*)(buf + 8), *(u16*)(buf + 2));
+ break;
+ }
+ buf += 12;
+ i--;
+ } while (0 < i);
+ }
+}
+
+void PrepNextFrame(void) {
+ gMain.interruptFlag = 0;
+ VBlankIntrWait();
+ do {
+ // Our VBlankIntr will set this flag
+ } while (gMain.interruptFlag == 0);
+
+ sub_080ADD70();
+ sub_0801C25C();
+ UpdateDisplayControls();
+ LoadResources();
+
+ if (gUpdateVisibleTiles) {
+ gUpdateVisibleTiles = 0;
+ if (gUnk_02025EB0 != NULL)
+ // sizeof(BGBuffer) = 0x800, what are we omitting?
+ DmaCopy32(3, &gBG1Buffer, VRAM + (*gUnk_02025EB0 & 0x1f00) * 8, 0x5C0);
+ if (gUnk_0200B650 != NULL)
+ DmaCopy32(3, &gBG2Buffer, VRAM + (*gUnk_0200B650 & 0x1f00) * 8, 0x5C0);
+ }
+ FadeMain();
+}
+
+void PlayerUpdate(Entity* this) {
+ if (gSave.stats.effect != 0)
+ gPlayerState.flags |= 0x4000;
+ else
+ gPlayerState.flags &= ~0x4000;
+
+ if (CheckDontUpdate(this) == 0) {
+ if ((gPlayerState.flags & 0x80000) != 0) {
+ sub_08077B20();
+ if ((gPlayerState.flags & 0x200000) != 0) {
+ gPlayerState.playerAction = 0x18;
+ gPlayerState.flags &= ~0x80000;
+ gPlayerState.hurtBlinkSpeed = 0xf0;
+ COLLISION_ON(this);
+ } else {
+ COLLISION_OFF(this);
+ gPlayerState.field_0xa8 = 0xf;
+ }
+ }
+ HandlePlayerLife(this);
+ DoPlayerAction(this);
+ if ((this->height.WORD == 0) && (this->action == 1 || this->action == 9))
+ sub_08008790(this, 8);
+ sub_080171F0();
+ }
+ sub_08078FB0(this);
+ DrawEntity(this);
+ sub_0807A050();
+}
+
+// Responsible for some life things like low health beep and initiating the death sequence
+#ifdef EU
+ASM_FUNC("asm/non_matching/eu/HandlePlayerLife.inc", void HandlePlayerLife(Entity* this));
+#else
+void HandlePlayerLife(Entity* this) {
+ u32 temp;
+
+ gUnk_0200AF00.filler25[10] = 0;
+ gUnk_0200AF00.filler25[8] = 0;
+ gUnk_0200AF00.filler25[9] = 0;
+
+ if ((gPlayerEntity.bitfield & 0x80) && (gPlayerEntity.iframes > 0))
+ SoundReq(SFX_86);
+
+ gPlayerState.flags &= ~(0x2000000 | 0x200);
+ if (gPlayerState.flags & 0x400)
+ ResetPlayer();
+ if ((gPlayerState.flags & 0x400000) && !gPlayerState.field_0xa0[0])
+ sub_0807A108();
+ if (sub_08079B24() == 0)
+ sub_08079708(this);
+
+ gUnk_03003DF0[0] = 0;
+ if (gPlayerState.field_0x27[0] != 0)
+ gPlayerState.field_0x27[0]--;
+
+ gPlayerState.field_0xa9 = gPlayerState.field_0xa8;
+ gPlayerState.field_0xa8 = 0;
+ if (gPlayerState.hurtType[0x4a] != 0) {
+ gPlayerState.hurtType[0x4a]--;
+ return;
+ }
+
+ if ((gPlayerState.field_0x8b != 0) || (gMessage.doTextBox & 0x7f))
+ return;
+
+ gRoomVars.unk2 = gMessage.doTextBox & 0x7f;
+ temp = gSave.stats.maxHealth / 4;
+ if (temp > 24)
+ temp = 24;
+ if (temp < 8)
+ temp = 8;
+
+ if (gSave.stats.health <= temp) {
+ gRoomVars.unk2 = 1;
+ if ((gUnk_0200AF00.filler0[1] == 0) && gScreenTransition.frameCount % 90 == 0) {
+ EnqueueSFX(SFX_LOW_HEALTH);
+ }
+ }
+
+ if (gSave.stats.charm == 0) {
+ gSave.stats.charmTimer = 0;
+ } else if ((gSave.stats.charmTimer == 0) || --gSave.stats.charmTimer == 0) {
+ gSave.stats.charm = 0;
+ SoundReq(SFX_ICE_BLOCK_MELT);
+ }
+
+ if (gSave.stats.unkB == 0) {
+ gSave.stats.unkTimer = 0;
+ } else if ((gSave.stats.unkTimer == 0) || (--gSave.stats.unkTimer == 0)) {
+ gSave.stats.unkB = 0;
+ SoundReq(SFX_140);
+ } else if ((gSave.stats.unkTimer & 0xf) == 0) {
+ CreateSparkle(this);
+ }
+
+ if (gSave.stats.effect == 0) {
+ gSave.stats.effectTimer = 0;
+ } else if ((gSave.stats.effectTimer == 0) || --gSave.stats.effectTimer == 0) {
+ gSave.stats.effect = 0;
+ } else if ((gSave.stats.effectTimer & 0x3f) == 0) {
+ CreateFx(this, FX_AURA_BASE + gSave.stats.effect, 0);
+ }
+}
+#endif
+
+void sub_080171F0(void) {
+ if (gPlayerState.field_0x1a[0] != 0)
+ ResetPlayer();
+ if (gPlayerState.field_0x14 != 0)
+ gPlayerState.field_0x14--;
+ if (gPlayerEntity.field_0x7a.HWORD != 0)
+ gPlayerEntity.field_0x7a.HWORD--;
+
+ gPlayerEntity.bitfield &= ~0x80;
+ if (gPlayerEntity.action != 0x14)
+ COPY_FLAG_FROM_TO(gPlayerState.flags, 0x2, 0x10000);
+
+ gPlayerState.flags &= ~2;
+ sub_080028E0(&gPlayerEntity);
+
+ if (gPlayerState.flags & 0x400000)
+ gUnk_0200AF00.filler25[10] = 1;
+
+ sub_08078180();
+ gPlayerState.field_0x7 &= ~0x80;
+ gPlayerState.field_0xa &= 0xf;
+ gPlayerState.keepFacing &= ~0x80;
+ gPlayerState.field_0x1a[0] = 0;
+ gPlayerState.field_0x80 = 0;
+ gPlayerState.field_0xaa = 0;
+ MemClear(&gUnk_03003BE0, 0x8c);
+ gPlayerEntity.spriteOffsetY = gPlayerState.field_0x3f;
+ gPlayerState.field_0x3f = 0;
+ sub_0807B0C8();
+
+ if (gPlayerState.flags & 0x400000)
+ gUnk_03004040[0]->spriteOffsetY = gUnk_03004040[1]->spriteOffsetY = gUnk_03004040[2]->spriteOffsetY = 0;
+
+ if (gPlayerEntity.action == 0x1d)
+ gPlayerState.flags |= 0x20000000;
+ else
+ gPlayerState.flags &= ~0x20000000;
+
+ sub_0807A8D8(&gPlayerEntity);
+ if (gPlayerState.jumpStatus & 0xc0)
+ gPlayerEntity.iframes = 0xfe;
+
+ if (gPlayerEntity.action != 0x17) {
+ sub_08077FEC(gPlayerEntity.action);
+ }
+}
+
+void ItemUpdate(Entity* this) {
+ if ((this->flags & ENT_DID_INIT) == 0 && this->action == 0 && this->subAction == 0)
+ ItemInit(this);
+
+ if (!CheckDontUpdate(this)) {
+ gPlayerItemFunctions[this->id](this);
+ this->bitfield &= ~0x80;
+ if (this->iframes != 0) {
+ if (this->iframes > 0)
+ this->iframes--;
+ else
+ this->iframes++;
+ }
+ }
+ DrawEntity(this);
+}
+
+// tiny regalloc
+NONMATCH("asm/non_matching/arm_proxy/ItemInit.inc", void ItemInit(Entity* this)) {
+ ItemFrame* entry;
+
+ entry = &gUnk_08126DA8[this->id];
+ if (entry->unk0 == 0xff) {
+ u32 temp = entry->unk2;
+ ItemFrame* temp2 = gUnk_08126ED8[entry->unk1];
+ entry = &temp2[this->field_0x68.HALF.LO - temp];
+ }
+
+ this->palette.raw = ((entry->unk0 & 0xf) << 4) | entry->unk0;
+ this->damage = entry->unk1;
+ this->hurtType = entry->unk3;
+ this->hitType = entry->unk4;
+ this->spriteIndex = entry->unk5;
+ if (entry->unk6 == 0)
+ this->spriteVramOffset = gPlayerEntity.spriteVramOffset;
+ else
+ this->spriteVramOffset = entry->unk6 & 0x3ff;
+
+ if (this->animationState == 0)
+ this->animationState = gPlayerEntity.animationState & 6;
+
+ this->collisionLayer = gPlayerEntity.collisionLayer;
+ this->spriteRendering.b3 = gPlayerEntity.spriteRendering.b3;
+ this->spritePriority.b0 = gPlayerEntity.spritePriority.b0;
+ this->spriteOrientation.flipY = gPlayerEntity.spriteOrientation.flipY;
+ this->currentHealth = 1;
+ this->flags |= ENT_DID_INIT;
+}
+END_NONMATCH
+
+void ObjectUpdate(Entity* this) {
+ if ((this->flags & ENT_DID_INIT) == 0 && this->action == 0)
+ InitObject(this);
+ if (this->iframes != 0)
+ this->iframes++;
+ if (!CheckDontUpdate(this)) {
+ gObjectFunctions[this->id](this);
+ this->bitfield &= ~0x80;
+ }
+ DrawEntity(this);
+}
+
+void ManagerUpdate(Entity* this) {
+ if (!CheckDontUpdate(this))
+ gManagerFunctions[this->id](this);
+}
+
+// regalloc
+NONMATCH("asm/non_matching/arm_proxy/NPCUpdate.inc", void NPCUpdate(Entity* this)) {
+ if ((this->currentHealth & 0x7f) && !ReadBit(&gUnk_020342F8, this->currentHealth - 1))
+ DeleteThisEntity();
+ if (this->action == 0 && (this->flags & ENT_DID_INIT) == 0)
+ InitNPC(this);
+ if (!CheckDontUpdate(this))
+ gNPCFunctions[this->id][0](this);
+ if (this->next != NULL) {
+ if (gNPCFunctions[this->id][1] != NULL)
+ gNPCFunctions[this->id][1](this);
+ if ((this->currentHealth & 0x7f) != 0) {
+ u32 temp = this->currentHealth & 0x7f;
+ gUnk_02031EC0[temp * 2 - 2].x = this->x.HALF.HI - gRoomControls.roomOriginX;
+ gUnk_02031EC0[temp * 2 - 2].y = this->y.HALF.HI - gRoomControls.roomOriginY;
+ }
+ DrawEntity(this);
+ }
+}
+END_NONMATCH