summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/agb_sram.c90
-rwxr-xr-xsrc/titlescreen.c238
-rwxr-xr-xsrc/util.c2
3 files changed, 292 insertions, 38 deletions
diff --git a/src/agb_sram.c b/src/agb_sram.c
new file mode 100644
index 0000000..b33003c
--- /dev/null
+++ b/src/agb_sram.c
@@ -0,0 +1,90 @@
+#include "global.h"
+#include "agb_sram.h"
+
+// this should be in .bss
+extern /*static*/ u16 verifySramFast_Work[80]; // buffer to hold code of VerifySramFast_Core
+extern /*static*/ u16 readSramFast_Work[64]; // buffer to hold code of ReadSramFast_Core
+
+u32 (*VerifySramFast)(const u8 *src, u8 *dest, u32 size); // pointer to verifySramFast_Work
+void (*ReadSramFast)(const u8 *src, u8 *dest, u32 size); // pointer to readSramFast_Work
+
+void ReadSramFast_Core(const u8 *src, u8 *dest, u32 size)
+{
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+ while (--size != -1)
+ *dest++ = *src++;
+}
+
+void WriteSramFast(const u8 *src, u8 *dest, u32 size)
+{
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+ while (--size != -1)
+ *dest++ = *src++;
+}
+
+u32 VerifySramFast_Core(const u8 *src, u8 *dest, u32 size)
+{
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+ while (--size != -1)
+ {
+ if (*dest++ != *src++)
+ return (u32)(dest - 1);
+ }
+ return 0;
+}
+
+void SetSramFastFunc(void)
+{
+ u16 *src;
+ u16 *dest;
+ u16 size;
+
+ src = (u16 *)ReadSramFast_Core;
+ // clear the least significant bit so that we get the actual start address of the function
+ src = (u16 *)((uintptr_t)src ^ 1); // NOTE: In Fire Emblem 8, this is '& ~1' instead of '^ 1'.
+ dest = readSramFast_Work;
+ // get the size of the function by subtracting the address of the next function
+ size = ((uintptr_t)WriteSramFast - (uintptr_t)ReadSramFast_Core) / 2;
+ // copy the function into the WRAM buffer
+ while (size != 0)
+ {
+ *dest++ = *src++;
+ size--;
+ }
+ // add 1 to the address of the buffer so that we stay in THUMB mode when bx-ing to the address
+ ReadSramFast = (void *)((uintptr_t)readSramFast_Work + 1);
+
+ src = (u16 *)VerifySramFast_Core;
+ // clear the least significant bit so that we get the actual start address of the function
+ src = (u16 *)((uintptr_t)src ^ 1); // NOTE: In Fire Emblem 8, this is '& ~1' instead of '^ 1'.
+ dest = verifySramFast_Work;
+ // get the size of the function by subtracting the address of the next function
+ size = ((uintptr_t)SetSramFastFunc - (uintptr_t)VerifySramFast_Core) / 2;
+ // copy the function into the WRAM buffer
+ while (size != 0)
+ {
+ *dest++ = *src++;
+ size--;
+ }
+ // add 1 to the address of the buffer so that we stay in THUMB mode when bx-ing to the address
+ VerifySramFast = (void *)((uintptr_t)verifySramFast_Work + 1);
+
+ REG_WAITCNT = (REG_WAITCNT & ~3) | 3;
+}
+
+u32 WriteAndVerifySramFast(const u8 *src, u8 *dest, u32 size)
+{
+ u8 i;
+ u32 errorAddr;
+
+ // try writing and verifying the data 3 times
+ for (i = 0; i < 3; i++)
+ {
+ WriteSramFast(src, dest, size);
+ errorAddr = VerifySramFast(src, dest, size);
+ if (errorAddr == 0)
+ break;
+ }
+
+ return errorAddr;
+}
diff --git a/src/titlescreen.c b/src/titlescreen.c
index b013c2f..6a2bcac 100755
--- a/src/titlescreen.c
+++ b/src/titlescreen.c
@@ -1,11 +1,12 @@
#include "global.h"
-#include "titlescreen.h"
+#include "agb_sram.h"
#include "m4a.h"
+#include "titlescreen.h"
#include "main.h"
static void sub_114FC(void);
static void sub_1157C(void);
-/*static*/ extern void sub_11640(void);
+static void sub_11640(void);
// If the user doesn't press any buttons at the title screen,
// it will transition to a demo gameplay experience.
@@ -656,38 +657,201 @@ static void sub_1157C(void)
}
}
-// static void sub_11640(void)
-// {
-// int i;
-// const struct SpriteSet *spriteSet;
-// struct SpriteGroup *group1 = &gTitlescreen.unk8[gUnknown_0200B3B8];
-// struct SpriteGroup *group2 = &gTitlescreen.unk10[gUnknown_0200B3B8];
-// group1->available = gTitlescreen.unk9;
-// group2->available = gTitlescreen.unk11;
-// LoadSpriteSets(gUnknown_086A96E4, 5, gUnknown_0200B3B8);
-// if (group1->available == 1)
-// {
-// group1->baseX = 120;
-// group1->baseY = 102;
-// spriteSet = gUnknown_086A96E4[gTitlescreen.unk8];
-// for (i = 0; i < spriteSet->count; i++)
-// {
-// gOamBuffer[group1->oam[i].oamId].x = group1->oam[i].xOffset + group1->baseX;
-// gOamBuffer[group1->oam[i].oamId].y = group1->oam[i].yOffset + group1->baseY;
-// }
-// }
-
-// if (group2->available == 1)
-// {
-// group2->baseX = 120;
-// group2->baseY = 80;
-// for (i = 0; i < 2; i++)
-// {
-// gOamBuffer[group2->oam[i].oamId].x = group2->oam[i].xOffset + group2->baseX;
-// gOamBuffer[group2->oam[i].oamId].y = group2->oam[i].yOffset + group2->baseY;
-// }
-// }
-
-// group1->available = 0;
-// group2->available = 0;
-// }
+static void sub_11640(void)
+{
+ int i;
+ const struct SpriteSet *spriteSet;
+ struct SpriteGroup *group1 = &gTitlescreen.unk8[gUnknown_0200B3B8];
+ struct SpriteGroup *group2 = &gTitlescreen.unk10[gUnknown_0200B3B8];
+
+ group1->available = gTitlescreen.unk9;
+ group2->available = gTitlescreen.unk11;
+
+ LoadSpriteSets(gUnknown_086A96E4, 5, gUnknown_0200B3B8);
+
+ if (group1->available == 1)
+ {
+ group1->baseX = 120;
+ group1->baseY = 102;
+ spriteSet = gUnknown_086A96E4[gTitlescreen.unk8];
+ for (i = 0; i < spriteSet->count; i++)
+ {
+ gOamBuffer[group1->oam[i].oamId].x = group1->oam[i].xOffset + group1->baseX;
+ gOamBuffer[group1->oam[i].oamId].y = group1->oam[i].yOffset + group1->baseY;
+
+ asm(""); // needed to match
+ }
+ }
+
+ if (group2->available == 1)
+ {
+ group2->baseX = 120;
+ group2->baseY = 80;
+ for (i = 0; i < 2; i++)
+ {
+ gOamBuffer[group2->oam[i].oamId].x = group2->oam[i].xOffset + group2->baseX;
+ gOamBuffer[group2->oam[i].oamId].y = group2->oam[i].yOffset + group2->baseY;
+
+ asm(""); // needed to match
+ }
+ }
+
+ group1->available = 0;
+ group2->available = 0;
+}
+
+struct UnknownStruct1
+{
+ u16 count;
+ u8 filler2[6];
+};
+
+void sub_1175C(void)
+{
+ struct SpriteGroup *r10;
+ struct SpriteGroup *r9;
+ struct SpriteGroup *r8;
+ const struct UnknownStruct1 *r12;
+ int sp0;
+
+ gMain.blendControl = 0x210;
+ gMain.blendAlpha = 0x808;
+ REG_BLDCNT = gMain.blendControl;
+ REG_BLDALPHA = gMain.blendAlpha;
+
+ r10 = &gMain.spriteGroups[gTitlescreen.unkA];
+ r9 = &gMain.spriteGroups[gTitlescreen.unkC];
+ r8 = &gMain.spriteGroups[gTitlescreen.unkE];
+
+ r10->available = gTitlescreen.unkB;
+ r9->available = gTitlescreen.unkD;
+ r8->available = gTitlescreen.unkF;
+
+ LoadSpriteSets((const struct SpriteSet *const *)gUnknown_0201C190, 7, gMain.spriteGroups);
+
+ if (r10->available == 1)
+ {
+ r10->baseX = 0x78;
+ r10->baseY = 0x66;
+ r12 = (const struct UnknownStruct1 *)gUnknown_0201C190[6];
+ for (sp0 = 0; sp0 < r12->count; sp0++)
+ {
+ struct OamDataSimple *r4 = &r10->oam[sp0];
+ if (r12[sp0 + 1].count == 1) // dunno. wtf?
+ gOamBuffer[r4->oamId].objMode = 1;
+ else
+ gOamBuffer[r4->oamId].objMode = 0;
+ gOamBuffer[r4->oamId].x = r4->xOffset + r10->baseX;
+ gOamBuffer[r4->oamId].y = r4->yOffset + r10->baseY;
+ }
+ }
+
+ if (r9->available == 1)
+ {
+ struct OamDataSimple *r5;
+
+ r9->baseX = gUnknown_086A9684[gTitlescreen.menuCursorIndex].x;
+ r9->baseY = gUnknown_086A9684[gTitlescreen.menuCursorIndex].y;
+
+ r5 = &r9->oam[0];
+
+ gOamBuffer[r5->oamId].x = r5->xOffset + r9->baseX;
+ gOamBuffer[r5->oamId].y = r5->yOffset + r9->baseY;
+ }
+
+ if (r8->available == 1)
+ {
+ struct OamDataSimple *r5;
+
+ r8->baseX = gUnknown_086A9694[gTitlescreen.menuCursorIndex].x;
+ r8->baseY = gUnknown_086A9694[gTitlescreen.menuCursorIndex].y;
+
+ r5 = &r8->oam[0];
+
+ gOamBuffer[r5->oamId].x = r5->xOffset + r8->baseX;
+ gOamBuffer[r5->oamId].y = r5->yOffset + r8->baseY;
+ }
+
+ r10->available = 0;
+ r9->available = 0;
+ r8->available = 0;
+}
+
+void sub_11968(void)
+{
+ struct SpriteGroup *r10;
+ struct SpriteGroup *r9;
+ struct SpriteGroup *r8;
+ const struct UnknownStruct1 *r12;
+ int sp0;
+
+ gMain.blendControl = 0x210;
+ gMain.blendAlpha = 0x808;
+ REG_BLDCNT = gMain.blendControl;
+ REG_BLDALPHA = gMain.blendAlpha;
+
+ r10 = &gMain.spriteGroups[gTitlescreen.unkA];
+ r9 = &gMain.spriteGroups[gTitlescreen.unkC];
+ r8 = &gMain.spriteGroups[gTitlescreen.unkE];
+
+ r10->available = gTitlescreen.unkB;
+ r9->available = gTitlescreen.unkD;
+ r8->available = gTitlescreen.unkF;
+
+ LoadSpriteSets((const struct SpriteSet *const *)gUnknown_0202BE00, 7, gMain.spriteGroups);
+
+ if (r10->available == 1)
+ {
+ r10->baseX = 0x78;
+ r10->baseY = 0x66;
+ r12 = (const struct UnknownStruct1 *)gUnknown_0202BE00[6];
+ for (sp0 = 0; sp0 < r12->count; sp0++)
+ {
+ struct OamDataSimple *r4 = &r10->oam[sp0];
+ if (r12[sp0 + 1].count == 1) // dunno. wtf?
+ gOamBuffer[r4->oamId].objMode = 1;
+ else
+ gOamBuffer[r4->oamId].objMode = 0;
+ gOamBuffer[r4->oamId].x = r4->xOffset + r10->baseX;
+ gOamBuffer[r4->oamId].y = r4->yOffset + r10->baseY;
+ }
+ }
+
+ if (r9->available == 1)
+ {
+ struct OamDataSimple *r5;
+
+ r9->baseX = gUnknown_086A96AC[gTitlescreen.menuCursorIndex].x;
+ r9->baseY = gUnknown_086A96AC[gTitlescreen.menuCursorIndex].y;
+
+ r5 = &r9->oam[0];
+
+ gOamBuffer[r5->oamId].x = r5->xOffset + r9->baseX;
+ gOamBuffer[r5->oamId].y = r5->yOffset + r9->baseY;
+ }
+
+ if (r8->available == 1)
+ {
+ struct OamDataSimple *r5;
+
+ r8->baseX = gUnknown_086A96C0[gTitlescreen.menuCursorIndex].x;
+ r8->baseY = gUnknown_086A96C0[gTitlescreen.menuCursorIndex].y;
+
+ r5 = &r8->oam[0];
+
+ gOamBuffer[r5->oamId].x = r5->xOffset + r8->baseX;
+ gOamBuffer[r5->oamId].y = r5->yOffset + r8->baseY;
+ }
+
+ r10->available = 0;
+ r9->available = 0;
+ r8->available = 0;
+}
+
+void sub_11B74(void)
+{
+ sub_52C64();
+ sub_52B30();
+ gMain.unk40 = 0;
+ WriteAndVerifySramFast((const u8 *)&gMain.unk40, (void *)0x0E000544, 4);
+}
diff --git a/src/util.c b/src/util.c
index f0d0b05..d0f3f42 100755
--- a/src/util.c
+++ b/src/util.c
@@ -186,7 +186,7 @@ void sub_578(void)
void sub_678(u8 *arg0, s16 arg1, s16 arg2)
{
// Rumble Pak related?
- s16 var0 = sub_55A24(arg0) - 1;
+ s16 var0 = strlen(arg0) - 1;
u16 *dest = &gUnknown_03005C00[arg1 * 32 + arg2];
do
{