diff --git a/config/cflags.txt b/config/cflags.txt index e6acc3401..48ad88319 100644 --- a/config/cflags.txt +++ b/config/cflags.txt @@ -410,10 +410,12 @@ src/pal/levels/02_maktar_nebula/L02_004013F8-g8.c -O2 -G8 -ffunction-sections -f src/pal/levels/shared/L12_0042C130-rc2.c -O2 -G0 -mno-split-addresses -ffunction-sections -fno-builtin src/pal/levels/shared/L18_003F9170-flags.c -O2 -G0 -ffunction-sections -mno-split-addresses src/pal/levels/23_damosel_orbit/L23_003C3978-flags.c -O2 -G0 -ffunction-sections -g +src/us2/game/0026EDE8-loader.c -O2 -G0 -ffunction-sections -fcall-used-hi1 -fcall-used-lo1 -fcall-used-accum1 src/us2/game/0029C448-rc2.c -O2 -fno-schedule-insns -G0 -mno-split-addresses -ffunction-sections -fno-builtin src/us2/game/002CE618-flags.c -O2 -G0 -ffunction-sections -frac2-gcse-unsplit-edges src/us2/game/002CE6A8-flags.c -O2 -G0 -ffunction-sections -frac2-gcse-unsplit-edges src/us2/game/002CE6D8-flags.c -O2 -G0 -ffunction-sections -frac2-gcse-unsplit-edges +src/us2/game/002957C0-map-setup-g64.c -O2 -G64 -Wa,-G64 -ffunction-sections -g -Wa,--r5900-la-addend=sn src/us2/game/002D5F10-b.c -O2 -G8 -ffunction-sections src/us2/game/002DCF58-rc2.c -O2 -G0 -ffunction-sections -fno-builtin src/us2/game/0033C958-flags.c -O2 -G0 -ffunction-sections -mno-split-addresses diff --git a/config/us2/boot/functions.tsv b/config/us2/boot/functions.tsv index c31d4c955..bedd51630 100644 --- a/config/us2/boot/functions.tsv +++ b/config/us2/boot/functions.tsv @@ -668,7 +668,7 @@ func_0026EA00 0026EA00 196 func_0026EAC8 0026EAC8 204 func_0026EB98 0026EB98 188 func_0026EC58 0026EC58 400 -func_US2_0026EDE8 0026EDE8 2340 +func_US2_0026EDE8 0026EDE8 2348 func_US2_0026F718 0026F718 8 func_0026F720 0026F720 8 func_0026F728 0026F728 8 diff --git a/src/us2/game/0026EDE8-loader.c b/src/us2/game/0026EDE8-loader.c new file mode 100644 index 000000000..1309c09d9 --- /dev/null +++ b/src/us2/game/0026EDE8-loader.c @@ -0,0 +1,346 @@ +/* func_US2_0026EDE8: v2.00's copy of func_0026EDE8 (src/game/0026EA00-loader.c), the boot + * title loop, with the same flags and source (see that file for what it takes). v2.00 skips + * table 1 when it unpacks the archive's six resource tables, and sixteen of its callees are + * v2.00's own functions. As elsewhere in v2.00, the pad's pressed word is at 0x1A4, not 0x1A0. */ +#include "common.h" + +typedef struct { char *data; int words[3]; } LoaderResource; +typedef struct { int code, count, data, size; } LoaderBank; +typedef struct { int offsets[0x64 / 4]; } LoaderArchive; +typedef struct { char pad[0x18]; LoaderArchive *archive; } LoaderMemory; +typedef struct { char pad[0x32C]; int base; char pad330[0x20]; int offset, count; } LoaderDisc; + +/* The memory-card state at D_001393E0 (McState_298F00 in src/game/00298F00.c). */ +typedef struct { + int port, slot, type, free, result, format; + short status, tries; + char pad1C[0xA0 - 0x1C]; +} BootCard; +typedef struct { + BootCard card[2]; + char pad140[0x15C - 0x140]; + int state, sub, next_state, next_card; +} BootMemcard; + +typedef struct { char pad[0x1A4]; unsigned int pressed; } LoaderPad; +typedef struct { char pad[0x2C]; int count; } LoaderTables; +typedef struct { char pad[0x24CC]; int enabled; } LoaderGame; +typedef struct { char pad[7]; char flag; } LoaderSound; +typedef struct { int active; short *sequence; } LoaderMovie; +typedef struct { char pad[10]; unsigned char index; } LoaderSelection; +typedef struct { char pad[4]; unsigned char mode; char rest[219]; } LoaderOption; +typedef struct { char pad[0x18]; int format; char pad1c[0x14]; int audio; } LoaderSettings; + +extern LoaderMemory D_001BAEC0; +extern LoaderDisc D_0014B540; +extern BootMemcard D_001393E0[]; +extern LoaderPad D_00138180; +extern LoaderTables D_00254E78; +extern LoaderGame D_00189E20; +extern LoaderSound D_001A63A8; +extern LoaderMovie D_001BAD40; +extern LoaderSelection D_00139568; +extern LoaderOption D_00239BA0[]; +extern LoaderSettings D_00152C00; +extern char D_00238C80[], D_01806380[], D_0180DA80[]; +extern int D_00138320[]; +extern char *D_001B1604 __attribute__((sda)); +extern LoaderResource *D_001B1840 __attribute__((sda)); +extern LoaderArchive *D_001A7280[] __attribute__((sda)); +extern unsigned long long D_001A7200 __attribute__((sda)); +extern int D_001A8C88[] __attribute__((sda)); +extern int D_001B16A8[] __attribute__((sda)), D_001B16AC[] __attribute__((sda)); +extern int D_001A8BB0[] __attribute__((sda)), D_001A8BB4[] __attribute__((sda)); +extern int D_001A8BB8[] __attribute__((sda)), D_001A8BBC[] __attribute__((sda)); +extern int D_001A8B84[] __attribute__((sda)), D_001B1684[] __attribute__((sda)), D_001B1598[] __attribute__((sda)); +extern unsigned char D_001A7BB0[] __attribute__((sda)); +extern short D_001A7A10[] __attribute__((sda)); +extern int D_001A7290[] __attribute__((sda)), D_001A72C0[] __attribute__((sda)); +extern int D_001A7AF0[] __attribute__((sda)), D_001A7B90[] __attribute__((sda)), D_001A72D0[] __attribute__((sda)); +extern unsigned short D_001A7AF2[] __attribute__((sda)); +extern int D_001A7478 MACRO_ADDR; +extern float D_001B168C MACRO_ADDR; + +extern void func_0011AEA0(int); +extern int func_001261F0(int); +extern int func_00132028(void); +extern void func_00133220(void); +extern void func_0026EA00(int); +extern void func_0026EAC8(int); +extern void func_0026EC58(unsigned short *); +extern void func_0027B948(void), func_US2_0027CB08(void), func_US2_0027CB80(void); +extern void func_0027D330(int); +extern void func_00280710(void); +extern void func_00282A28(void); +extern float func_00283CE0(int); +extern int func_00284E80(void); +extern void func_00284EA8(void), func_00284FC0(void), func_00285338(void), func_US2_00287140(void); +extern int func_00288AA0(unsigned char *, int); +extern int func_00288BE8(void *); +extern void func_0028AB70(void); +extern void func_00290758(void), func_00290C60(void); +extern void func_US2_00292650(int *, int); +extern void func_US2_00292928(int), func_00292408(int), func_002925F0(int), func_002926B8(int); +extern void func_US2_00293138(void); +extern void func_US2_002957C0(void); +extern void func_00298178(void), func_US2_00299CF0(void); +extern void func_US2_0029DB80(void); +extern void func_US2_0029E308(int, int); +extern int func_002B49E0(int, int, int, int, unsigned char *); +extern int func_002B4B70(int, int); +extern void func_US2_002B5B38(void); +extern void func_002B67E0(int, int); +extern int func_002B7B18(int, int, int); +extern short func_002B7CE0(int); +extern void func_002B9000(void); +extern void func_002C9C20(void); +extern void func_US2_002CB860(void); +extern int func_US2_002EA0C0(void); +extern void func_US2_002EB740(void); +extern void func_US2_002ED260(void); +extern void func_002EED08(void); +extern void func_US2_002F6E10(void); +extern void func_002FC220(void), func_002FC280(void); +extern void func_002FC3C0(unsigned long long); +extern long long func_002FCB00(int, int, int, int); + +static inline BootMemcard *Memcard(void) { BootMemcard *mc = D_001393E0; return mc; } +static inline int CardType(BootMemcard *mc) { return mc->card[0].type; } +static inline int CardFormat(BootMemcard *mc) { return mc->card[0].format; } +static inline int CardStatus(BootMemcard *mc) { return mc->card[0].status; } +static inline int CardFree(BootMemcard *mc) { return mc->card[0].free; } + +void func_US2_0026EDE8(void) +{ + LoaderResource *tables[8]; + int counts[8]; + short sequence[32]; + int frames = 0, loaded = 0, state; + LoaderArchive *archive; + char *image, *extra; + float time; + + D_001A8C88[0] = 1; + func_00290C60(); + { + LoaderMemory *memory = &D_001BAEC0; + LoaderDisc *disc = &D_0014B540; + func_002B7B18((int)memory->archive + 0x400000, disc->offset + disc->base, disc->count); + } + while (D_001393E0->state == 2 && D_001393E0->next_state < 0) { + func_US2_00299CF0(); + func_00298178(); + func_001261F0(0); + } + while (D_001393E0->state != 2 || D_001393E0->next_state >= 0) { + func_US2_00299CF0(); + func_00298178(); + func_001261F0(0); + } + for (;;) { + if (!(CardType(Memcard()) != 2 + || (CardFormat(Memcard()) != 0 && CardStatus(Memcard()) < -1 && CardFree(Memcard()) < 475))) + break; + loaded = 1; + if (D_001393E0->state < 3 && D_001393E0->next_state < 0) { + if (D_001393E0->card[0].type != 2) + func_0026EAC8((int)D_01806380); + else if (D_001393E0->card[0].status != -4) + func_0026EAC8((int)D_0180DA80); + if (D_001393E0->next_state < 0) { + D_001393E0->next_state = 7; + D_001393E0->next_card = 0; + } + } + func_002B9000(); + func_US2_00299CF0(); + func_00298178(); + if (frames <= 119) + frames++; + func_001261F0(0); + if (frames >= 61) { + if (D_00138180.pressed & 0xFFFF0FFF) + break; + } + } + func_00290758(); + if (loaded) { + int i; + func_0027D330(5); + for (i = 29; i >= 0; i--) + func_001261F0(0); + } + { + LoaderMemory *memory = &D_001BAEC0; + func_002B7CE0(1); + func_0011AEA0(0); + func_US2_0029E308((int)memory->archive + 0x400000, (int)memory->archive); + func_0011AEA0(0); + func_002EED08(); + archive = memory->archive; + func_0026EA00(archive->offsets[0x50 / 4] + (int)archive); + D_001A7280[2] = memory->archive; + func_US2_00293138(); + func_002B67E0(archive->offsets[8 / 4] + (int)archive, 0); + { + LoaderBank *bank = (LoaderBank *)(archive->offsets[0] + (int)archive); + D_001B1604 = (char *)bank + bank->code + bank->size; + func_US2_00292650((int *)((char *)bank + bank->data), bank->count); + } + } + { + int i, j; + for (i = 0; i < 6; i++) { + int *table, *part; + int count; + if (i == 1) + continue; + table = (int *)(archive->offsets[0x48 / 4] + (int)archive); + part = (int *)((int)table + table[i]); + count = part[0]; + part += 2; + tables[i] = (LoaderResource *)part; + counts[i] = count; + for (j = 0; j < counts[i]; j++) + tables[i][j].data += (int)tables[i] - 8; + } + } + D_00254E78.count = counts[D_001A7BB0[4]]; + D_001B1840 = tables[D_001A7BB0[4]]; + image = (char *)(archive->offsets[0x10 / 4] + (int)archive); + extra = (char *)(archive->offsets[0x60 / 4] + (int)archive); + { + int i; + for (i = 44; i >= 0; i--) + func_001261F0(0); + } + func_0027D330(30); + { + int i; + for (i = 29; i >= 0; i--) + func_001261F0(0); + } + func_0026EA00(archive->offsets[0x58 / 4] + (int)archive); + { + LoaderSound *sound; + D_00189E20.enabled = 1; + sound = &D_001A63A8; + D_001A8BBC[0] = 20; + D_001B16A8[0] = 20; + D_001B16AC[0] = (int)D_00238C80; + sound->flag = 0; + D_001A8BB8[0] = -2; + D_001A8BB0[0] = 0; + D_001A8BB4[0] = 0; + D_001B1684[0] = 0; + } + func_US2_002957C0(); + func_0028AB70(); + func_US2_0029DB80(); + func_002C9C20(); + { + int i; + for (i = 24; i >= 0; i--) + func_001261F0(0); + } + func_0027D330(30); + frames = 1800; + D_001B1598[0] = 0; + func_001261F0(0); + func_00284E80(); + func_00133220(); + D_001A7478 = 3; + func_00288AA0((unsigned char *)&D_001BAD40, 0xB2); + func_00288BE8(&D_001BAD40); + func_US2_002B5B38(); + while (!D_001A8B84[0]) { + D_001B1840 = tables[D_001A7BB0[4]]; + D_00254E78.count = counts[D_001A7BB0[4]]; + /* T1_COUNT, the timer-1 counter register. */ + D_001A7200 += T1_COUNT; + T1_COUNT = 0; + func_00280710(); + func_002FC280(); + func_002FC220(); + func_00284FC0(); + func_00285338(); + func_00284EA8(); + func_00132028(); + state = D_001A8BB0[0]; + switch (state) { + case -1: + case 0: + if (D_001A8BB4[0] == 3 || frames >= 1800) { + frames = 0; + func_0026EC58((unsigned short *)sequence); + D_001BAD40.active = 1; + D_001A7478 = 2; + D_001BAD40.sequence = sequence; + func_00288AA0((unsigned char *)&D_001BAD40, sequence[1]); + func_00288BE8(&D_001BAD40); + } else { + func_002FCB00((int)(image + 0x10), D_001A72D0[3], 512, 416); + func_002B49E0(3, 1, 6, 0, 0); + } + break; + case 1: + func_US2_002F6E10(); + if (extra) { + int i; + func_0026EA00((int)extra); + for (i = 29; i >= 0; i--) + func_001261F0(0); + func_0027D330(30); + extra = 0; + } + break; + case 3: + frames++; + func_002B9000(); + if (D_00138320[0]) + frames = 0; + func_US2_002CB860(); + func_US2_0027CB80(); + if (frames >= 1800) { + frames = 0; + func_002B4B70(0, 0); + } + break; + case 4: + func_002B9000(); + func_US2_00287140(); + func_US2_0027CB08(); + break; + case 6: + func_002B9000(); + func_US2_002EA0C0(); + func_US2_002EB740(); + break; + default: + func_00282A28(); + break; + } + if (D_001A8BB0[0] != state) + D_001B1684[0] = 0; + else + D_001B1684[0]++; + func_US2_00299CF0(); + func_00298178(); + func_002FC3C0(1); + time = func_00283CE0(T1_COUNT); + D_001B168C = time * (D_001A7B90[0] ? 0.0000868055578f : 0.000104166669f); + func_0027B948(); + func_US2_002B5B38(); + D_001B1598[0]++; + func_001261F0(0); + } + if (D_001A7290[0] != D_001A7A10[4]) + func_US2_00292928(D_001A7A10[4]); + if (D_001A72C0[0] != (D_00239BA0 + D_00139568.index)->mode) + func_00292408((D_00239BA0 + D_00139568.index)->mode); + if (D_00152C00.audio != (D_001A7AF2[0] & 31)) + func_002926B8(D_001A7AF2[0] & 31); + if (D_00152C00.format != (D_001A7AF0[0] & 3)) + func_002925F0(D_001A7AF0[0] & 3); + func_US2_002ED260(); +} diff --git a/src/us2/game/0026EDE8.c b/src/us2/game/0026EDE8.c index d48f669cf..008f0788e 100644 --- a/src/us2/game/0026EDE8.c +++ b/src/us2/game/0026EDE8.c @@ -1,6 +1,6 @@ #include "include_asm.h" -INCLUDE_ASM("asm/us2/game", func_US2_0026EDE8); +/* func_US2_0026EDE8 lives in 0026EDE8-loader.c. */ unsigned int func_US2_0026F718(void) { diff --git a/src/us2/game/002957C0-map-setup-g64.c b/src/us2/game/002957C0-map-setup-g64.c new file mode 100644 index 000000000..ce19a1670 --- /dev/null +++ b/src/us2/game/002957C0-map-setup-g64.c @@ -0,0 +1,149 @@ +/* func_US2_002957C0: v2.00's copy of func_00294F10 (src/game/00294BC8-map-setup-g64.c), + * the map screen setup, with the same flags. The allocator's source-line arguments are + * 8 higher, and func_0029D4D0 is v2.00's own func_US2_0029E308. */ +#include "common.h" +extern unsigned int func_00294EC8(int); +extern int D_001C4FA0[]; +extern int D_001A79F0_3[] __attribute__((sda)); +typedef struct { int sector, size; } MapFile; +typedef struct { + char pad0[0x36C]; + int base; /* 0x36C */ + char pad370[0x14F0 - 0x370]; + MapFile files0[28]; /* 0x14F0 */ + MapFile files1[28]; /* 0x15D0 */ +} MapToc; +extern char D_0014B540_1[]; +typedef struct { float x0, y0, x1, y1, u0, v0, u1, v1; } UiMapEndpoints; +typedef struct { float ax, bx, ay, by; } UiMapCoefficients; +extern int D_00256028[][2]; +extern UiMapEndpoints D_00255C30[]; +extern UiMapCoefficients D_00255ED0[]; +extern UiMapEndpoints D_001A93D0_gp[2] SDATA(D_001A93D0); +extern UiMapCoefficients D_001A9428_gp[2] SDATA(D_001A9428); +extern unsigned char D_001A7AF8[] MACRO_ADDR; +extern char *D_001BAED0 __attribute__((nosda)); +extern char D_001A95A0[], D_001A95B8[]; +extern unsigned char D_0018D278[]; +extern void func_00295C50(int); +extern int func_002B7C80(void *, int, int); +extern int func_002EED58(void *, int, int, char *); +extern int func_US2_0029E308(void *, void *); +extern void *func_0028B2B8(int, int, char *, int); +extern void func_00282B50(void *, void *, int); +extern void func_00297730(char *, unsigned char *, int); +extern void func_00297400(u8 *, u8 *, short *); + +void func_US2_002957C0(void) +{ + int i; + float u0, y0, v0, x1, u1, x0, y1, v1; + char *scratch, *packed; + int bytes; + int none = -1; + + D_001C4FA0[4] = 1; + { int i; for (i = 0; i < 21; i++) { + D_001C4FA0[0x108 / 4 + i] = D_00256028[i][0]; + ((float *)D_001C4FA0)[0xB4 / 4 + i] = 0.65f; + D_001C4FA0[0x15C / 4 + i] = D_00256028[i][1]; + } } + D_001C4FA0[0x238 / 4] = none; + func_00295C50(D_001A79F0_3[0]); + { int i; for (i = 0; i < 21; i++) { + float sx, sy; + x0 = D_00255C30[i].x0; + y0 = D_00255C30[i].y0; + x1 = D_00255C30[i].x1; + y1 = D_00255C30[i].y1; + u0 = D_00255C30[i].u0; + v0 = D_00255C30[i].v0; + u1 = D_00255C30[i].u1; + v1 = D_00255C30[i].v1; + sx = (u0 - u1) / (x0 - x1); + sy = (v0 - v1) / (y0 - y1); + D_00255ED0[i].bx = sx; + D_00255ED0[i].ax = u0 - sx * x0; + D_00255ED0[i].by = sy; + D_00255ED0[i].ay = v0 - sy * y0; + } } + { int i; for (i = 0; i < 2; i++) { + float sx, sy; + x0 = D_001A93D0_gp[i].x0; + y0 = D_001A93D0_gp[i].y0; + x1 = D_001A93D0_gp[i].x1; + y1 = D_001A93D0_gp[i].y1; + u0 = D_001A93D0_gp[i].u0; + v0 = D_001A93D0_gp[i].v0; + u1 = D_001A93D0_gp[i].u1; + v1 = D_001A93D0_gp[i].v1; + sx = (u0 - u1) / (x0 - x1); + D_001A9428_gp[i].bx = sx; + D_001A9428_gp[i].ax = u0 - sx * x0; + sy = (v0 - v1) / (y0 - y1); + D_001A9428_gp[i].by = sy; + D_001A9428_gp[i].ay = v0 - sy * y0; + } } + if ((((MapToc *)D_0014B540_1)->files0[D_001C4FA0[0x230 / 4]].size != 0 && !D_001A7AF8[5]) + || (((MapToc *)D_0014B540_1)->files1[D_001C4FA0[0x230 / 4]].size != 0 && D_001A7AF8[5])) { + D_001C4FA0[0x28 / 4] = 1; + if (D_001A7AF8[5]) + bytes = ((MapToc *)D_0014B540_1)->files1[D_001C4FA0[0x230 / 4]].size << 7; + else + bytes = ((MapToc *)D_0014B540_1)->files0[D_001C4FA0[0x230 / 4]].size << 7; + scratch = D_001BAED0; + packed = scratch + 0x9A800; + if (D_001A7AF8[5]) { + func_002B7C80(packed, ((MapToc *)D_0014B540_1)->files1[D_001C4FA0[0x230 / 4]].sector + ((MapToc *)D_0014B540_1)->base, ((MapToc *)D_0014B540_1)->files1[D_001C4FA0[0x230 / 4]].size); + D_001C4FA0[0x23C / 4] = 1; + } else { + func_002B7C80(packed, ((MapToc *)D_0014B540_1)->files0[D_001C4FA0[0x230 / 4]].sector + ((MapToc *)D_0014B540_1)->base, ((MapToc *)D_0014B540_1)->files0[D_001C4FA0[0x230 / 4]].size); + D_001C4FA0[0x23C / 4] = 0; + } + D_001C4FA0[0x238 / 4] = func_002EED58(packed, bytes, 0x3C00, D_001A95A0); + D_001C4FA0[0x240 / 4] = bytes; + func_US2_0029E308(packed, scratch); + { + int size = ((int *)scratch)[1] - ((int *)scratch)[0]; + D_001C4FA0[0] = (int)func_0028B2B8(size, 0, D_001A95B8, 0x2F3); + func_00282B50((void *)D_001C4FA0[0], scratch + ((int *)scratch)[0], size); + } + D_001C4FA0[0] += 8; + D_001C4FA0[1] = D_001C4FA0[0]; + { + int size = ((int *)scratch)[2] - ((int *)scratch)[1]; + D_001C4FA0[5] = (int)func_0028B2B8(size, 0, D_001A95B8, 0x304); + func_00282B50((void *)D_001C4FA0[5], scratch + ((int *)scratch)[1], size); + } + D_001C4FA0[2] = (int)func_0028B2B8(0x1000, 0, D_001A95B8, 0x30B); + for (i = 0; i < 8; i++) { + D_001C4FA0[0x30 / 4 + i * 4] = -1; + D_001C4FA0[0x34 / 4 + i * 4] = -1; + D_001C4FA0[0x38 / 4 + i * 4] = D_001C4FA0[2] + (i << 9); + } + D_001C4FA0[3] = (int)func_0028B2B8(0x8000, 0, D_001A95B8, 0x314); + if (func_00294EC8(D_001C4FA0[0x230 / 4])) + func_00297730((char *)D_001C4FA0[3], D_0018D278 + (D_001C4FA0[0x230 / 4] << 11), D_001C4FA0[5]); + else + func_00297400((u8 *)D_001C4FA0[3], (u8 *)D_001C4FA0[0], (short *)D_001C4FA0[1]); + { + int i, j; + float limit = 256.0f, center = 15.5f; + for (i = 0; i < 32; i++) { + float dy = center - (float)i; + float dy2 = dy * dy; + for (j = 0; j < 32; j++) { + float dx = center - (float)j; + if (dx * dx + dy2 > limit) + ((u8 *)D_001C4FA0 + 0x1B0)[j / 8 + (i << 2)] |= 1 << (j % 8); + } + } + } + } else { + D_001C4FA0[0] = 0; + D_001C4FA0[2] = 0; + D_001C4FA0[3] = 0; + D_001C4FA0[1] = 0; + D_001C4FA0[0x28 / 4] = 0; + } +} diff --git a/src/us2/game/002957C0.c b/src/us2/game/002957C0.c index e4833f4e6..0d7fe85c3 100644 --- a/src/us2/game/002957C0.c +++ b/src/us2/game/002957C0.c @@ -1,6 +1,6 @@ #include "include_asm.h" -INCLUDE_ASM("asm/us2/game", func_US2_002957C0); +/* func_US2_002957C0 lives in 002957C0-map-setup-g64.c. */ /* func_US2_00295D70, the v2.00 copy of func_002954C0: the same C with one added store, D_001C4FA0[0x2B8 / 4] = e. */ diff --git a/src/us2/game/002CCAA0-g8.c b/src/us2/game/002CCAA0-g8.c new file mode 100644 index 000000000..6044bc79c --- /dev/null +++ b/src/us2/game/002CCAA0-g8.c @@ -0,0 +1,55 @@ +/* func_US2_002CCAA0: v2.00's copy of func_002CBAE0 (src/game/002C7748-g8.c), the + * menu-source dispatcher. The code is v1.01's with every address moved; it is the + * release's own function because three of its callees changed in v2.00. + * D_001AB910 is declared volatile as in func_002CBAE0 and func_002CBC58: retail + * rereads it for every test and keeps one load whose value it discards (the empty + * D_0025A058/D_00259B48 arm). Without the qualifier the body is 328 bytes, not 376. */ +typedef struct { + int mode, pad4, value; + int padC[2]; + char *source; + char *destination; + int state; +} MenuState_US2_2CCAA0; +typedef struct { char pad[0x1C4]; int flags; } InputState_US2_2CCAA0; +extern MenuState_US2_2CCAA0 D_001F2840; +extern InputState_US2_2CCAA0 D_00138180; +extern char D_00259018[]; +extern char D_0025A738[]; +extern char D_0025A498[]; +extern char D_0025A190[]; +extern char D_0025A058[]; +extern char D_00259B48[]; +extern volatile int D_001AB910 __attribute__((sda)); +extern int (*D_00210ACC[])(int); +extern void func_0029CE38(void); +extern int func_US2_0029D0C8(int); +extern int func_US2_002D7BA0(int); +extern int func_US2_0029D138(int); + +int func_US2_002CCAA0(void) +{ + int result = 0; + + if (D_001F2840.source == D_00259018) { + if (D_00138180.flags & 0x910) { + D_001F2840.state = D_001F2840.value == 4 ? 2 : 1; + result = 1; + } else if (D_00210ACC[0](D_00138180.flags) >= 0) { + result = 1; + } + } else if (D_001F2840.source == D_0025A738) { + func_0029CE38(); + } else if (D_001F2840.source == D_0025A498 && !D_001AB910) { + func_US2_0029D0C8(0); + } else if (D_001F2840.source == D_0025A190 && !D_001AB910) { + if (func_US2_002D7BA0(0)) + D_001F2840.state = D_001F2840.value == 4 ? 2 : 1; + func_US2_0029D138(D_00138180.flags); + result = D_001F2840.destination != D_0025A498; + } else if ((D_001F2840.source == D_0025A058 && !D_001AB910) + || (D_001F2840.source == D_00259B48 && !D_001AB910)) { + /* nothing: only the tests remain */ + } + return result; +} diff --git a/src/us2/game/002CCAA0.c b/src/us2/game/002CCAA0.c index e7fedc9b0..3ae2b22e3 100644 --- a/src/us2/game/002CCAA0.c +++ b/src/us2/game/002CCAA0.c @@ -1,6 +1,6 @@ #include "include_asm.h" -INCLUDE_ASM("asm/us2/game", func_US2_002CCAA0); +/* func_US2_002CCAA0 lives in 002CCAA0-g8.c. */ INCLUDE_ASM("asm/us2/game", func_US2_002CCC18); diff --git a/src/us2/levels/05_feltzin_system/L05_0041EFBC.c b/src/us2/levels/05_feltzin_system/L05_0041EFBC.c index 0582a9cb5..793e698ae 100644 --- a/src/us2/levels/05_feltzin_system/L05_0041EFBC.c +++ b/src/us2/levels/05_feltzin_system/L05_0041EFBC.c @@ -1,3 +1,3 @@ #include "include_asm.h" -INCLUDE_ASM("asm/us2/levels", func_US2_L05_0041F478); +/* func_US2_L05_0041F478 lives in L05_0041F478-g8.c. */ diff --git a/src/us2/levels/05_feltzin_system/L05_0041F478-g8.c b/src/us2/levels/05_feltzin_system/L05_0041F478-g8.c new file mode 100644 index 000000000..9efff0665 --- /dev/null +++ b/src/us2/levels/05_feltzin_system/L05_0041F478-g8.c @@ -0,0 +1,295 @@ +#include "common.h" + +/* func_US2_L05_0041F478: v2.00's copy of func_L05_0041DF58 (src/levels/05_feltzin_system/ + * L05_0041DF58-g8.c), the Feltzin System mission HUD, with the same flags. v2.00 moved the + * HUD text ids down by 0x16A; func_L05_003263F8 is v2.00's own func_US2_L05_00327640 and + * the level copy func_L00_0030CF60 is the boot's func_US2_0029CC48. */ + +/* func_L05_0041DF58 (DrawFeltzinMissionHud): the Feltzin System mission HUD. The mission text for + the current stage, the ship's health and ammo bars, the weapon icons and the three corner sprites. + Ported from the matched func_L10_00421790 (L10_00421790-g8.c), the same routine for Hrugis Cloud. + + Every text and sprite label y goes through label_y, the HUD label idiom (dead-test helper, allowed + by owner ruling). Case 1's second label passes the stage global, which is 1 in that case, as + `active` (a value holding 1, as allowed by owner ruling): with the literal 1, both of case 0's and + case 1's identical second-draw tails reach jump2 with equal RTL and are cross-jumped into one; + retail keeps them apart. */ + +typedef struct { u8 bytes[16]; } Block; + +typedef struct { + s32 active; + u8 pad04[8]; + s32 maxLevel; + s32 maxAmmo; + s32 value; + u8 pad18[4]; + s16 icon; + u8 pad1E[10]; +} HudWeapon; + +typedef struct { + u8 pad00[0x10]; + s32 objectives; + s32 wave; + u8 pad18[0x10]; + s32 health; +} HudMissionState; + +typedef struct { + u8 pad00[0x34]; + s32 blinkTimer; + s32 blinkOn; + u8 pad3C[8]; + s32 time; +} HudBlinkVars; + +extern u8 *D_L05_001B13B0 __attribute__((sda)); +extern s32 D_L05_001B1360 __attribute__((sda)); +extern s32 D_L05_001B1438 __attribute__((sda)); +extern s32 D_L05_001B1440 __attribute__((sda)); +extern s32 D_L05_001B1428 __attribute__((sda)); +extern s32 D_L05_001B13DC __attribute__((sda)); +extern s32 D_L05_001B13D0 __attribute__((sda)); +extern void *D_L05_001B1390 __attribute__((sda)); +extern void *D_L05_001B1394 __attribute__((sda)); +extern void *D_L05_001B1398 __attribute__((sda)); +extern void *D_L05_001B139C __attribute__((sda)); +extern void *D_L05_001B13A0 __attribute__((sda)); +extern void *D_L05_001B13A4 __attribute__((sda)); +extern u8 *D_L05_001A904C MACRO_ADDR; +extern s32 D_L05_001B143C MACRO_ADDR; +extern s32 D_L05_001B1444 MACRO_ADDR; +extern s32 D_L05_001B142C MACRO_ADDR; +extern f32 D_L05_001B2D84; +extern s32 D_L05_001B2D80 MACRO_ADDR; +extern s32 D_001A7340 MACRO_ADDR; +extern s32 D_L05_001B3550 MACRO_ADDR; +extern HudMissionState D_L05_00221D10; +extern f32 D_L05_001AC4E0, D_L05_001AC4E4; +extern char D_L05_001B1448[], D_L05_001B1450[], D_L05_001B1498[]; +extern Block D_L05_001B1468, D_L05_001B1478, D_L05_001B1488; +extern HudWeapon D_L05_002A1800[]; + +extern void func_L05_00421B98(s32, s32, s32, s32); +extern char *func_00288FB8(s32); +extern s32 func_00115DA8(char *, char *, ...); +extern void func_0027F5B8(s32, s32, u64, char *, s32); +extern s32 func_00282948(s32 *); +extern void func_002ED578(s32, s32 *, s32 *, s32 *); +extern void *func_00336D50(void *, s32); +extern f32 func_00283CE0(s32); +extern void func_00300968(void *, f32, f32, s32, f32, f32); +extern s32 func_002ED8A0(s32); +extern s32 func_00283D38(u32, u32, f32); +extern void func_0027EAE8(s32, s32, s32, s32, s32, u32 *); +extern void *func_0028E588(s32, s32); +extern void func_0028EA58(void *, s32, s32, s32, s32, Block *); +extern void func_0027F538(s32, s32, u64, char *, s32); +extern void func_US2_L05_00327640(s32); +extern s32 func_L05_00324DB8(void); +extern void func_US2_0029CC48(void), func_L05_0037A5F8(void); + +static __inline__ s32 screen_coord(s32 mode, f32 value, f32 offset) +{ + f32 scaled = value * D_L05_001B2D84 + 0.5f; + + if (mode == 1) + return (s32)(scaled + offset); + return (s32)scaled; +} + +static __inline__ int label_y(void *handle, float value, float scale, float half, int active) +{ + int mode = D_L05_001B2D80; + float scaled = value * scale + half; + int result = (int)scaled; + void *copy; + + if (mode == active) + scaled = scale; + if (handle != 0) + scaled = scale; + copy = handle; + if (copy != 0) + scaled = half; + return result; +} + +s32 func_US2_L05_0041F478(void) { + char text[128]; + char *label; + u32 colors[2], colors2[2]; + Block b0, b1, b2; + s32 a, b, c, idx, newidx, color, textX; + HudBlinkVars *data = *(HudBlinkVars **)(D_L05_001B13B0 + 0x68); + f32 x, y, ratio, tmp, base, end, fill, tweenColor; + void *sprite0, *sprite2; + + switch (D_L05_001B1360) { + case 0: + func_L05_00421B98(0, 1, 1, 1); + label = func_00288FB8(0x3067); + func_00115DA8(text, D_L05_001B1448, label, D_L05_00221D10.objectives); + textX = D_L05_001B1438 - 60; + func_0027F5B8(textX, label_y((void *)textX, D_L05_001B143C - 8, D_L05_001B2D84, 0.5f, 1), 0x80808080, text, 128); + label = func_00288FB8(0x3068); + func_00115DA8(text, D_L05_001B1448, label, D_L05_00221D10.wave + 1); + textX = D_L05_001B1440 - 60; + func_0027F5B8(textX, label_y((void *)textX, D_L05_001B1444 - 8, D_L05_001B2D84, 0.5f, 1), 0x80808080, text, 128); + break; + case 1: { + f32 half = 0.5f; + s32 textX2; + + func_L05_00421B98(1, 1, 0, 1); + label = func_00288FB8(0x306a); + func_00115DA8(text, D_L05_001B1448, label, D_L05_00221D10.objectives); + textX = D_L05_001B1440 - 60; + func_0027F5B8(textX, label_y((void *)textX, D_L05_001B1444 - 8, D_L05_001B2D84, half, 1), 0x80808080, text, 128); + func_002ED578(data->time, &a, &b, &c); + label = func_00288FB8(0x2e19); + func_00115DA8(text, D_L05_001B1450, label, a, b, c); + textX2 = D_L05_001B1428 - 80; + /* active is the switch value, 1 in this case (allowed by owner ruling, 2026-11-09). */ + func_0027F5B8(textX2, label_y((void *)textX2, D_L05_001B142C - 8, D_L05_001B2D84, half, D_L05_001B1360), 0x80808080, text, 128); + break; + } + case 2: { + s32 textX2; + + func_L05_00421B98(0, 1, 0, 1); + label = func_00288FB8(0x3067); + func_00115DA8(text, D_L05_001B1448, label, D_L05_00221D10.objectives); + textX2 = D_L05_001B1440 - 60; + func_0027F5B8(textX2, label_y((void *)textX2, D_L05_001B1444 - 8, D_L05_001B2D84, 0.5f, 1), 0x80808080, text, 128); + break; + } + case 3: { + f32 half = 0.5f; + s32 textX2; + + func_L05_00421B98(1, 1, 0, 1); + label = func_00288FB8(0x306d); + func_00115DA8(text, D_L05_001B1448, label, D_L05_001B13D0); + textX = D_L05_001B1440 - 60; + func_0027F5B8(textX, label_y((void *)textX, D_L05_001B1444 - 8, D_L05_001B2D84, half, 1), 0x80808080, text, 128); + func_002ED578(D_L05_001B3550, &a, &b, &c); + label = func_00288FB8(0x2e19); + func_00115DA8(text, D_L05_001B1450, label, a, b, c); + textX2 = D_L05_001B1428 - 80; + func_0027F5B8(textX2, label_y((void *)textX2, D_L05_001B142C - 8, D_L05_001B2D84, half, 1), 0x80808080, text, 128); + break; + } + } + + if (D_L05_001A904C) { + D_L05_001B1390 = func_00336D50(D_L05_001A904C + 0x8710, 128); + D_L05_001B1394 = func_00336D50(D_L05_001A904C + 0x8710, 129); + D_L05_001B1398 = func_00336D50(D_L05_001A904C + 0x8710, 130); + D_L05_001B139C = func_00336D50(D_L05_001A904C + 0x8710, 131); + D_L05_001B13A0 = func_00336D50(D_L05_001A904C + 0x8710, 132); + D_L05_001B13A4 = func_00336D50(D_L05_001A904C + 0x8710, 133); + x = func_00283CE0(D_001A7340) * 0.5f; + y = screen_coord(D_L05_001B2D80, 200.0f, 4.0f); + func_00300968(D_L05_001B1390, x, y, 0x60442d00, 1.0f, 0.0f); + func_00300968(D_L05_001B1394, x, y, 0x55f0c070, 1.0f, 0.0f); + + idx = func_002ED8A0(6); + ratio = func_00283CE0(D_L05_002A1800[idx].value) / func_00283CE0(D_L05_002A1800[idx].maxLevel); + switch (idx) { + case 6: + if (ratio > 0.0f) { + tweenColor = func_00283D38(0x800000ff, 0x8000ff00, ratio); + func_00300968(D_L05_001B139C, x, y, (s32)tweenColor, 1.0f, 0.0f); + } + break; + case 12: + if (ratio > 0.5f) { + ratio -= 0.5f; + tweenColor = func_00283D38(0x800000ff, 0x8000ff00, ratio + ratio); + func_00300968(D_L05_001B13A0, x, y, (s32)tweenColor, 1.0f, 0.0f); + func_00300968(D_L05_001B139C, x, y, 0x8000ff00, 1.0f, 0.0f); + } else if (ratio > 0.0f) { + tweenColor = func_00283D38(0x800000ff, 0x8000ff00, ratio + ratio); + func_00300968(D_L05_001B139C, x, y, (s32)tweenColor, 1.0f, 0.0f); + } + break; + case 14: + if (ratio > 0.6666667f) { + ratio -= 0.6666667f; + tweenColor = func_00283D38(0x800000ff, 0x8000ff00, ratio * 3.0f); + func_00300968(D_L05_001B13A4, x, y, (s32)tweenColor, 1.0f, 0.0f); + func_00300968(D_L05_001B13A0, x, y, 0x8000ff00, 1.0f, 0.0f); + func_00300968(D_L05_001B139C, x, y, 0x8000ff00, 1.0f, 0.0f); + } else if (ratio > 0.33333334f) { + ratio -= 0.33333334f; + tweenColor = func_00283D38(0x800000ff, 0x8000ff00, ratio * 3.0f); + func_00300968(D_L05_001B13A0, x, y, (s32)tweenColor, 1.0f, 0.0f); + func_00300968(D_L05_001B139C, x, y, 0x8000ff00, 1.0f, 0.0f); + } else if (ratio > 0.0f) { + tweenColor = func_00283D38(0x800000ff, 0x8000ff00, ratio * 3.0f); + func_00300968(D_L05_001B139C, x, y, (s32)tweenColor, 1.0f, 0.0f); + } + break; + } + + fill = D_L05_00221D10.health * 0.01f; + if (fill > 0.3f) { + data->blinkOn = 1; + } else if (func_00282948(&data->blinkTimer)) { + data->blinkTimer = 5; + data->blinkOn ^= 1; + } + colors[1] = func_00283D38(0x800000ff, 0x8000ff00, fill); + colors[0] = 0x800000ff; + tmp = fill * 200.0f + 156.0f; + if (data->blinkOn) + func_0027EAE8(156, 14, (s32)tmp, 27, 1, colors); + + idx = func_002ED8A0(7); + ratio = func_00283CE0(D_L05_002A1800[idx].value); + fill = ratio / func_00283CE0(D_L05_002A1800[idx].maxAmmo); + color = func_00283D38(0x800000ff, 0x8000ff00, fill); + base = func_00283CE0(450); + end = func_00283CE0(386); + end -= func_00283CE0(450); + colors2[0] = 0x800000ff; + colors2[1] = color; + end = end * fill; + tmp = base + end; + if (fill > 0.0f) + func_0027EAE8(450, 8, (s32)tmp, 19, 1, colors2); + + b0 = D_L05_001B1468; + b1 = D_L05_001B1478; + b2 = D_L05_001B1488; + func_0028EA58(func_0028E588(0xea97, 1), 21, 7, 30, 30, &b1); + func_0028EA58(func_0028E588(0xea97, 0), 21, 7, 30, 30, &b0); + func_0028EA58(func_0028E588(0xea97, D_L05_002A1800[func_002ED8A0(D_L05_001B13DC)].icon), 21, 7, 30, 30, &b2); + func_0028EA58(func_0028E588(0xea97, 1), 462, 9, 30, 30, &b1); + func_0028EA58(func_0028E588(0xea97, D_L05_002A1800[func_002ED8A0(7)].icon), 462, 9, 30, 30, &b2); + func_00115DA8(text, D_L05_001B1498, D_L05_002A1800[func_002ED8A0(D_L05_001B13DC)].value, + D_L05_002A1800[func_002ED8A0(D_L05_001B13DC)].maxAmmo); + func_0027F538(67, 5, 0x80808080, text, 128); + + func_US2_L05_00327640(2); + newidx = func_L05_00324DB8(); + if (newidx >= 0) { + D_L05_002A1800[func_002ED8A0(D_L05_001B13DC)].active = 0; + D_L05_001B13DC = newidx; + D_L05_002A1800[func_002ED8A0(newidx)].active = 1; + } + func_00300968(D_L05_001B1398, x, y, 0x80f0f0f0, 1.0f, 0.0f); + } + + func_US2_0029CC48(); + sprite0 = func_00336D50(D_L05_001A904C + 0x8710, 186); + data = func_00336D50(D_L05_001A904C + 0x8710, 187); + sprite2 = func_00336D50(D_L05_001A904C + 0x8710, 188); + func_00300968(sprite0, D_L05_001AC4E0 + 4.0f, label_y(sprite0, D_L05_001AC4E4 + 4.0f, D_L05_001B2D84, 0.5f, 1), 0x60442d00, 0.8f, 0.0f); + func_00300968(data, D_L05_001AC4E0 + 4.0f, label_y(data, D_L05_001AC4E4 + 4.0f, D_L05_001B2D84, 0.5f, 1), 0x60241700, 0.8f, 0.0f); + func_00300968(sprite2, D_L05_001AC4E0 + 4.0f, label_y(sprite2, D_L05_001AC4E4 + 4.0f, D_L05_001B2D84, 0.5f, 1), 0x55f0c070, 0.8f, 0.0f); + func_L05_0037A5F8(); + return 1; +} diff --git a/tools/levels.py b/tools/levels.py index 2a6a0fa63..aa3fc2ed2 100644 --- a/tools/levels.py +++ b/tools/levels.py @@ -1065,6 +1065,10 @@ def level_extent(number: int, address: int, size: int) -> tuple[int, int]: # was a row of its own, func_PAL_0026F578 (see FUNCTION_RESIDUES). The function # is 12 bytes longer than USA v1.01's func_0026EDE8 and has no padding nop after it. "func_PAL_0026EC50": (2340, 12), + # Boot only, the same function in USA v2.00: the row stopped before its + # `jr $ra; addiu $sp,$sp,0xD0`, which no row held; a padding nop follows. The + # function is 8 bytes longer than USA v1.01's func_0026EDE8 (a skipped table). + "func_US2_0026EDE8": (2340, 8), }