Decompile wall clock routines (#49)

This commit is contained in:
camthesaxman 2016-10-02 15:41:16 -05:00 committed by YamaArashi
parent 179c2e5041
commit 6ce4ed25d6
5 changed files with 130111 additions and 131035 deletions

View File

@ -4,7 +4,7 @@ AS := $(DEVKITARM)/bin/arm-none-eabi-as
ASFLAGS := -mcpu=arm7tdmi
CC1 := tools/agbcc/bin/agbcc
CFLAGS := -mthumb-interwork -O2 -g
CFLAGS := -mthumb-interwork -Wimplicit -O2 -g -fhex-asm
CPP := $(DEVKITARM)/bin/arm-none-eabi-cpp
CPPFLAGS := -I tools/agbcc/include -iquote include -nostdinc -undef
@ -46,7 +46,7 @@ compare_sapphire compare_sapphire_rev1 compare_sapphire_rev2
C_SRCS := $(wildcard src/*.c)
C_OBJS := $(C_SRCS:%.c=%.o)
ASM_OBJS := asm/crt0.o asm/rom3.o asm/rom_8040EB4.o asm/rom4.o asm/rom_8074BAC.o asm/rom5.o \
ASM_OBJS := asm/crt0.o asm/rom3.o asm/rom_8040EB4.o asm/rom4.o asm/rom_8074BAC.o asm/rom5.o asm/rom6.o\
asm/libgcnmultiboot.o asm/m4a_1.o asm/m4a_3.o asm/libagbsyscall.o \
asm/rom_8072DF8.o asm/rom_8065394.o asm/rom_803D1FC.o asm/rom_803BA2C.o

131034
asm/rom5.s

File diff suppressed because it is too large Load Diff

129510
asm/rom6.s Normal file

File diff suppressed because it is too large Load Diff

View File

@ -72,6 +72,8 @@ SECTIONS {
asm/rom_8074BAC.o(.text);
src/task.o(.text);
asm/rom5.o(.text);
src/wallclock.o(.text);
asm/rom6.o(.text);
} =0
script_data :

596
src/wallclock.c Normal file
View File

@ -0,0 +1,596 @@
#include "gba/io_reg.h"
#include "gba/macro.h"
#include "global.h"
#include "main.h"
#include "menu.h"
#include "palette.h"
#include "rtc.h"
#include "songs.h"
#include "sprite.h"
#include "task.h"
#include "text.h"
#include "trig.h"
//Functions that need to be put in headers
void LZ77UnCompVram(const void *src, void *dest);
void SetMainCallback2(MainCallback callback);
void SetVBlankCallback(IntrCallback callback);
void remove_some_task(void);
void LoadCompressedObjectPic(void *);
void PlaySE(u16);
extern u16 gUnknown_0202E8CC;
extern u16 gMiscClockMale_Pal[];
extern u16 gMiscClockFemale_Pal[];
extern u8 gMiscClock_Gfx[];
extern u8 gUnknown_083F7A90[];
extern struct SpritePalette gUnknown_083F7AA0;
extern u8 gUnknown_08E95774[];
extern u8 gUnknown_08E954B0[];
extern u8 gOtherText_CorrectTimePrompt[];
extern u8 * const gUnknown_08376D74[][2];
extern s8 gClockHandCoords[][2];
extern struct WindowConfig gWindowConfig_81E6C3C;
extern struct WindowConfig gWindowConfig_81E6CE4;
extern struct SpriteTemplate gSpriteTemplate_83F7AD8;
extern struct SpriteTemplate gSpriteTemplate_83F7AF0;
extern struct SpriteTemplate gSpriteTemplate_83F7B28;
extern struct SpriteTemplate gSpriteTemplate_83F7B40;
static void WallClockVblankCallback(void);
static void LoadWallClockGraphics(void);
static void WallClockMainCallback(void);
static void WallClockInit(void);
static void Task_SetClock1(u8 taskId);
static void Task_SetClock2(u8 taskId);
static void Task_SetClock3(u8 taskId);
static void Task_SetClock4(u8 taskId);
static void Task_SetClock5(u8 taskId);
static void Task_SetClock6(u8 taskId);
static void Task_ViewClock1(u8 taskId);
static void Task_ViewClock2(u8 taskId);
static void Task_ViewClock3(u8 taskId);
static void Task_ViewClock4(u8 taskId);
static u8 CalcMinHandDelta(u16 speed);
static u16 CalcNewMinHandAngle(u16 angle, u8 direction, u8 speed);
static u8 AdvanceClock(u8 taskId, u8 direction);
static void UpdateClockPeriod(u8 taskId, u8 direction);
static void InitClockWithRtc(u8 taskId);
//Task data
enum {
TD_MHAND_ANGLE,
TD_HHAND_ANGLE,
TD_HOURS,
TD_MINUTES,
TD_SETDIRECTION, //Movement direction when setting the clock
TD_PERIOD, //Whether the time is AM or PM
TD_SETSPEED, //Movement speed when setting the clock
};
enum {
AM,
PM
};
enum {
BACKWARD = 1,
FORWARD
};
static void WallClockVblankCallback(void)
{
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
}
static void LoadWallClockGraphics(void)
{
u8 *addr;
u32 size;
SetVBlankCallback(0);
REG_DISPCNT = 0;
REG_BG3CNT = 0;
REG_BG2CNT = 0;
REG_BG1CNT = 0;
REG_BG0CNT = 0;
REG_BG3HOFS = 0;
REG_BG3VOFS = 0;
REG_BG2HOFS = 0;
REG_BG2VOFS = 0;
REG_BG1HOFS = 0;
REG_BG1VOFS = 0;
REG_BG0HOFS = 0;
REG_BG0VOFS = 0;
addr = (void *)VRAM;
size = 0x18000;
while(1)
{
DmaFill16(3, 0, addr, 0x1000);
addr += 0x1000;
size -= 0x1000;
if(size <= 0x1000)
{
DmaFill16(3, 0, addr, size);
break;
}
}
{
void *oam = (void *)OAM;
u32 oamSize = OAM_SIZE;
DmaFill32(3, 0, oam, oamSize);
}
{
void *pltt = (void *)PLTT;
u32 plttSize = PLTT_SIZE;
DmaFill16(3, 0, pltt, plttSize);
}
LZ77UnCompVram(gMiscClock_Gfx, (void *)VRAM);
if(gUnknown_0202E8CC == MALE)
LoadPalette(gMiscClockMale_Pal, 0, 32);
else
LoadPalette(gMiscClockFemale_Pal, 0, 32);
remove_some_task();
ResetTasks();
ResetSpriteData();
ResetPaletteFade();
FreeAllSpritePalettes();
LoadCompressedObjectPic(gUnknown_083F7A90);
LoadSpritePalettes(&gUnknown_083F7AA0);
SetUpWindowConfig(&gWindowConfig_81E6C3C);
InitMenuWindow(&gWindowConfig_81E6CE4);
}
static void WallClockInit(void)
{
u16 ime;
BeginNormalPaletteFade(-1, 0, 0x10, 0, 0);
ime = REG_IME;
REG_IME = 0;
REG_IE |= 0x1;
REG_IME = ime;
REG_DISPSTAT |= 0x8;
SetVBlankCallback(WallClockVblankCallback);
SetMainCallback2(WallClockMainCallback);
REG_BLDCNT = 0;
REG_BLDALPHA = 0;
REG_BLDY = 0;
REG_BG3CNT = 0x701;
REG_BG0CNT = 0x1F08;
REG_DISPCNT = 0x1940;
}
//Allow player to set the clock
void Cb2_StartWallClock(void)
{
u8 taskId;
u8 spriteId;
LoadWallClockGraphics();
LZ77UnCompVram(&gUnknown_08E954B0, (void *)(VRAM + 0x3800));
taskId = CreateTask(Task_SetClock1, 0);
gTasks[taskId].data[TD_HOURS] = 10;
gTasks[taskId].data[TD_MINUTES] = 0;
gTasks[taskId].data[TD_SETDIRECTION] = 0;
gTasks[taskId].data[TD_PERIOD] = AM;
gTasks[taskId].data[TD_SETSPEED] = 0;
gTasks[taskId].data[TD_MHAND_ANGLE] = 0;
gTasks[taskId].data[TD_HHAND_ANGLE] = 300;
spriteId = CreateSprite(&gSpriteTemplate_83F7AD8, 0x78, 0x50, 1);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].oam.affineMode = 1;
gSprites[spriteId].oam.matrixNum = 0;
spriteId = CreateSprite(&gSpriteTemplate_83F7AF0, 0x78, 0x50, 0);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].oam.affineMode = 1;
gSprites[spriteId].oam.matrixNum = 1;
spriteId = CreateSprite(&gSpriteTemplate_83F7B28, 0x78, 0x50, 2);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].data1 = 45;
spriteId = CreateSprite(&gSpriteTemplate_83F7B40, 0x78, 0x50, 2);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].data1 = 90;
WallClockInit();
}
//View, but don't set, the clock
void Cb2_ViewWallClock(void)
{
u8 taskId;
s16 angle1;
s16 angle2;
u8 spriteId;
LoadWallClockGraphics();
LZ77UnCompVram(gUnknown_08E95774, (void *)(VRAM + 0x3800));
taskId = CreateTask(Task_ViewClock1, 0);
InitClockWithRtc(taskId);
if(gTasks[taskId].data[TD_PERIOD] == 0)
{
angle1 = 45;
angle2 = 90;
}
else
{
angle1 = 90;
angle2 = 135;
}
spriteId = CreateSprite(&gSpriteTemplate_83F7AD8, 120, 80, 1);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].oam.affineMode = 1;
gSprites[spriteId].oam.matrixNum = 0;
spriteId = CreateSprite(&gSpriteTemplate_83F7AF0, 120, 80, 0);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].oam.affineMode = 1;
gSprites[spriteId].oam.matrixNum = 1;
spriteId = CreateSprite(&gSpriteTemplate_83F7B28, 120, 80, 2);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].data1 = angle1;
spriteId = CreateSprite(&gSpriteTemplate_83F7B40, 120, 80, 2);
gSprites[spriteId].data0 = taskId;
gSprites[spriteId].data1 = angle2;
WallClockInit();
}
static void WallClockMainCallback(void)
{
RunTasks();
AnimateSprites();
BuildOamBuffer();
UpdatePaletteFade();
}
static void Task_SetClock1(u8 taskId)
{
if(!gPaletteFade.active)
gTasks[taskId].func = Task_SetClock2;
}
//Handle keypresses when setting clock
static void Task_SetClock2(u8 taskId)
{
if(gTasks[taskId].data[TD_MHAND_ANGLE] % 6)
{
gTasks[taskId].data[TD_MHAND_ANGLE] = CalcNewMinHandAngle(
gTasks[taskId].data[TD_MHAND_ANGLE],
gTasks[taskId].data[TD_SETDIRECTION],
gTasks[taskId].data[TD_SETSPEED]);
}
else
{
gTasks[taskId].data[TD_MHAND_ANGLE] = gTasks[taskId].data[TD_MINUTES] * 6;
gTasks[taskId].data[TD_HHAND_ANGLE] = (gTasks[taskId].data[TD_HOURS] % 12) * 30 + (gTasks[taskId].data[TD_MINUTES] / 10) * 5;
if(gMain.newKeys & A_BUTTON)
{
gTasks[taskId].func = Task_SetClock3;
return;
}
else
{
gTasks[taskId].data[TD_SETDIRECTION] = gMain.newKeys & A_BUTTON;
if(gMain.heldKeys & DPAD_LEFT)
gTasks[taskId].data[TD_SETDIRECTION] = BACKWARD;
if(gMain.heldKeys & DPAD_RIGHT)
gTasks[taskId].data[TD_SETDIRECTION] = FORWARD;
if(gTasks[taskId].data[TD_SETDIRECTION])
{
if(gTasks[taskId].data[TD_SETSPEED] <= 0xFE)
gTasks[taskId].data[TD_SETSPEED]++;
gTasks[taskId].data[TD_MHAND_ANGLE] = CalcNewMinHandAngle(
gTasks[taskId].data[TD_MHAND_ANGLE],
gTasks[taskId].data[TD_SETDIRECTION],
gTasks[taskId].data[TD_SETSPEED]);
AdvanceClock(taskId, gTasks[taskId].data[TD_SETDIRECTION]);
}
else
{
gTasks[taskId].data[TD_SETSPEED] = 0;
}
}
}
}
//Ask player "Is this the correct time?"
static void Task_SetClock3(u8 taskId)
{
MenuDrawTextWindow(2, 16, 27, 19);
MenuPrint(gOtherText_CorrectTimePrompt, 3, 17);
MenuDrawTextWindow(23, 8, 29, 13);
PrintMenuItems(24, 9, 2, gUnknown_08376D74);
InitMenu(0, 24, 9, 2, 1, 5);
gTasks[taskId].func = Task_SetClock4;
}
//Get menu selection
static void Task_SetClock4(u8 taskId)
{
switch(ProcessMenuInputNoWrap_())
{
case 0: //YES
PlaySE(SE_SELECT);
gTasks[taskId].func = Task_SetClock5; //Move on
return;
case -1: //B button
case 1: //NO
sub_8072DEC();
PlaySE(SE_SELECT);
MenuZeroFillWindowRect(23, 8, 29, 13);
MenuZeroFillWindowRect(2, 16, 27, 19);
gTasks[taskId].func = Task_SetClock2; //Go back and let player adjust clock
}
}
//Set the time offset based on the wall clock's time
static void Task_SetClock5(u8 taskId)
{
RtcInitLocalTimeOffset(gTasks[taskId].data[TD_HOURS], gTasks[taskId].data[TD_MINUTES]);
BeginNormalPaletteFade(-1, 0, 0, 16, 0);
gTasks[taskId].func = Task_SetClock6;
}
static void Task_SetClock6(u8 taskId)
{
if(!gPaletteFade.active)
SetMainCallback2((MainCallback)gMain.field_8);
}
static void Task_ViewClock1(u8 taskId)
{
if(!gPaletteFade.active)
gTasks[taskId].func = Task_ViewClock2;
}
//Wait for A or B press
static void Task_ViewClock2(u8 taskId)
{
InitClockWithRtc(taskId);
if(gMain.newKeys & (A_BUTTON | B_BUTTON))
gTasks[taskId].func = Task_ViewClock3;
}
static void Task_ViewClock3(u8 taskId)
{
BeginNormalPaletteFade(-1, 0, 0, 16, 0);
gTasks[taskId].func = Task_ViewClock4;
}
static void Task_ViewClock4(u8 taskId)
{
if(!gPaletteFade.active)
SetMainCallback2((MainCallback)gMain.field_8);
}
static u8 CalcMinHandDelta(u16 speed)
{
if(speed > 60)
return 6;
else if(speed > 30)
return 3;
else if(speed > 10)
return 2;
else
return 1;
}
//Calculates the new position of the minute hand when setting the clock
static u16 CalcNewMinHandAngle(u16 angle, u8 direction, u8 speed)
{
u8 delta = CalcMinHandDelta(speed);
switch(direction)
{
case BACKWARD:
if(angle)
angle = angle - delta;
else
angle = 360 - delta;
break;
case FORWARD:
if(angle < 360 - delta)
angle = angle + delta;
else
angle = 0;
break;
}
return angle;
}
//Advances clock forward or backward by 1 minute
static u8 AdvanceClock(u8 taskId, u8 direction)
{
switch(direction)
{
case BACKWARD:
if(gTasks[taskId].data[TD_MINUTES] > 0)
gTasks[taskId].data[TD_MINUTES]--;
else
{
gTasks[taskId].data[TD_MINUTES] = 59;
if(gTasks[taskId].data[TD_HOURS] > 0)
gTasks[taskId].data[TD_HOURS]--;
else
gTasks[taskId].data[TD_HOURS] = 23;
UpdateClockPeriod(taskId, direction);
}
break;
case FORWARD:
if(gTasks[taskId].data[TD_MINUTES] <= 58)
gTasks[taskId].data[TD_MINUTES]++;
else
{
gTasks[taskId].data[TD_MINUTES] = 0;
if(gTasks[taskId].data[TD_HOURS] <= 22)
gTasks[taskId].data[TD_HOURS]++;
else
gTasks[taskId].data[TD_HOURS] = 0;
UpdateClockPeriod(taskId, direction);
}
break;
}
return 0;
}
//Determines the clock period (AM/PM) based on the hour
static void UpdateClockPeriod(u8 taskId, u8 direction)
{
u8 hours = gTasks[taskId].data[TD_HOURS];
switch(direction)
{
case 1:
switch(hours)
{
case 11:
gTasks[taskId].data[TD_PERIOD] = AM;
break;
case 23:
gTasks[taskId].data[TD_PERIOD] = PM;
break;
}
break;
case 2:
switch(hours)
{
case 0:
gTasks[taskId].data[TD_PERIOD] = AM;
break;
case 12:
gTasks[taskId].data[TD_PERIOD] = PM;
break;
}
break;
}
}
static void InitClockWithRtc(u8 taskId)
{
RtcCalcLocalTime();
gTasks[taskId].data[TD_HOURS] = gLocalTime.hours;
gTasks[taskId].data[TD_MINUTES] = gLocalTime.minutes;
gTasks[taskId].data[TD_MHAND_ANGLE] = gTasks[taskId].data[TD_MINUTES] * 6;
gTasks[taskId].data[TD_HHAND_ANGLE] = (gTasks[taskId].data[TD_HOURS] % 12) * 30 + (gTasks[taskId].data[TD_MINUTES] / 10) * 5;
if(gLocalTime.hours <= 11)
gTasks[taskId].data[TD_PERIOD] = AM;
else
gTasks[taskId].data[TD_PERIOD] = PM;
}
void sub_810B05C(struct Sprite *sprite)
{
u16 angle;
s16 sin;
s16 cos;
u16 x;
u16 y;
angle = gTasks[sprite->data0].data[TD_MHAND_ANGLE];
sin = Sin2(angle) / 16;
cos = Cos2(angle) / 16;
SetOamMatrix(0, cos, sin, -sin, cos);
x = gClockHandCoords[angle][0];
y = gClockHandCoords[angle][1];
//Manual sign extension
if(x > 0x80)
x |= 0xFF00;
if(y > 0x80)
y |= 0xFF00;
sprite->pos2.x = x;
sprite->pos2.y = y;
}
void sub_810B0F4(struct Sprite *sprite)
{
u16 angle;
s16 sin;
s16 cos;
u16 x;
u16 y;
angle = gTasks[sprite->data0].data[TD_HHAND_ANGLE];
sin = Sin2(angle) / 16;
cos = Cos2(angle) / 16;
SetOamMatrix(1, cos, sin, -sin, cos);
x = gClockHandCoords[angle][0];
y = gClockHandCoords[angle][1];
//Manual sign extension
if(x > 0x80)
x |= 0xFF00;
if(y > 0x80)
y |= 0xFF00;
sprite->pos2.x = x;
sprite->pos2.y = y;
}
void sub_810B18C(struct Sprite *sprite)
{
s16 sin;
s16 cos;
if(gTasks[sprite->data0].data[TD_PERIOD] != AM)
{
if((u16)(sprite->data1 - 60) <= 29)
sprite->data1 += 5;
if(sprite->data1 <= 59)
sprite->data1++;
}
else
{
if((u16)(sprite->data1 - 46) <= 29)
sprite->data1 -= 5;
if(sprite->data1 > 75)
sprite->data1--;
}
cos = Cos2((u16)sprite->data1);
sprite->pos2.x = cos * 30 / 4096;
sin = Sin2((u16)sprite->data1);
sprite->pos2.y = sin * 30 / 4096;
}
void sub_810B230(struct Sprite *sprite)
{
s16 sin;
s16 cos;
if(gTasks[sprite->data0].data[TD_PERIOD] != AM)
{
if((u16)(sprite->data1 - 105) <= 29)
sprite->data1 += 5;
if(sprite->data1 <= 104)
sprite->data1++;
}
else
{
if((u16)(sprite->data1 - 91) <= 29)
sprite->data1 -= 5;
if(sprite->data1 > 120)
sprite->data1--;
}
cos = Cos2((u16)sprite->data1);
sprite->pos2.x = cos * 30 / 4096;
sin = Sin2((u16)sprite->data1);
sprite->pos2.y = sin * 30 / 4096;
}